/// <summary> /// Modifies the HTTP request message pipeline to include a session identifier. /// </summary> /// <param name="request">The HTTP request message to send to the server.</param> /// <param name="cancellationToken">A cancellation token to cancel operation.</param> /// <returns>HTTP response message.</returns> protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // Get existing session data from the request, if any CookieHeaderValue cookie = request.Headers.GetCookies(SessionToken).FirstOrDefault(); string sessionCookieValue = cookie?[SessionToken].Value; Guid sessionID; // If session ID format is invalid, create a new one if (!Guid.TryParse(sessionCookieValue, out sessionID)) { sessionID = Guid.NewGuid(); } sessionCookieValue = sessionID.ToString(); // Save session ID (as Guid) in the request properties request.Properties[SessionToken] = sessionID; // Continue processing the HTTP request HttpResponseMessage response = await base.SendAsync(request, cancellationToken); // Store session ID in response message cookie response.Headers.AddCookies(new[] { new CookieHeaderValue(SessionToken, sessionCookieValue) { Path = "/" } }); // Get authentication options associated with this request ReadonlyAuthenticationOptions options = request.GetAuthenticationOptions(); // If requesting the AuthTest page using BASIC authentication, reissue the client's authentication token string authTestPage = options.AuthTestPage; if (request.RequestUri.LocalPath == authTestPage) { SecurityPrincipal securityPrincipal = request.GetRequestContext().Principal as SecurityPrincipal; SecurityIdentity securityIdentity = securityPrincipal?.Identity; ISecurityProvider securityProvider = securityIdentity?.Provider; string username = securityIdentity?.Name; string password = securityProvider?.Password; if (!string.IsNullOrEmpty(username) && !string.IsNullOrEmpty(password)) { string authenticationToken = IssueAuthenticationToken(username, password); InvalidateAuthenticationToken(request); response.Headers.AddCookies(new[] { new CookieHeaderValue(AuthenticationToken, authenticationToken) { Path = request.RequestUri.LocalPath, MaxAge = TimeSpan.FromDays(30.0D) } }); } // AuthTest page should always have a valid request verification token request.ValidateRequestVerificationToken(options); } return(response); }
/// <summary> /// Validates that the anti-forgery request verification token value comes from the user who submitted the data. /// </summary> /// <param name="request">HTTP request message.</param> /// <param name="options">Read-only authentication options for this <paramref name="request"/>.</param> /// <param name="formValidation">Flag that determines if form validation should be used.</param> public static void ValidateRequestVerificationToken(this HttpRequestMessage request, ReadonlyAuthenticationOptions options, bool formValidation = false) { if (formValidation) { // Form validation AntiForgery.Validate(request); } else { // Header validation string cookieToken = ""; string formToken = ""; IEnumerable <string> tokenHeaders; if (request.Headers.TryGetValues(options.RequestVerificationToken, out tokenHeaders)) { string[] tokens = tokenHeaders.First().Split(':'); if (tokens.Length == 2) { cookieToken = tokens[0].Trim(); formToken = tokens[1].Trim(); } } AntiForgery.Validate(request, cookieToken, formToken); } }
/// <summary> /// Validates that the anti-forgery request verification token value comes from the user who submitted the data. /// </summary> /// <param name="request">HTTP request message.</param> /// <param name="options">Read-only authentication options for this <paramref name="request"/>.</param> /// <param name="formValidation">Flag that determines if form validation should be used.</param> public static void ValidateRequestVerificationToken(this HttpRequestMessage request, ReadonlyAuthenticationOptions options, bool formValidation = false) { bool tryGetTokens(string name, out Tuple <string, string> values) { if (request.Headers.TryGetValues(name, out IEnumerable <string> tokenHeaders)) { string[] tokens = tokenHeaders.First().Split(':'); switch (tokens.Length) { case 1: values = new Tuple <string, string>(name, tokens[0].Trim()); return(true); case 2: values = new Tuple <string, string>(tokens[0].Trim(), tokens[1].Trim()); return(true); } } values = default; return(false); } // Check for anti-forgery operation with AJAX requests, in these cases, do not perform form validation if (tryGetTokens(options.AjaxRequestVerificationToken, out Tuple <string, string> tokenValues) && tokenValues.Item2.ParseBoolean()) { formValidation = false; } if (formValidation) { // Form validation AntiForgery.Validate(request); } else { // Header validation string cookieToken = ""; string formToken = ""; if (tryGetTokens(options.RequestVerificationToken, out tokenValues)) { cookieToken = tokenValues.Item1; formToken = tokenValues.Item2; } AntiForgery.Validate(request, cookieToken, formToken); } }