async Task AuthenticateAsync(HttpContext context) { var config = OidcClientConfigurationSection.Instance; var appRelativeCallbackUrl = config.AppRelativeCallbackUrl; if (context.Request.AppRelativeCurrentExecutionFilePath.Equals(appRelativeCallbackUrl, StringComparison.OrdinalIgnoreCase)) { var authorizeErrorUrl = config.AuthorizeErrorRedirectUrl; var tokenUrl = config.Endpoints.Token; var userInfoUrl = config.Endpoints.UserInfo; var clientId = config.ClientId; var clientSecret = config.ClientSecret; var issuerName = config.IssuerName; var signingcert = X509.LocalMachine.TrustedPeople.SubjectDistinguishedName.Find( config.SigningCertificate, false).First(); var callUserInfoEndpoint = config.CallUserInfoEndpoint; // parse OIDC authorize response var response = OidcClient.HandleAuthorizeResponse(context.Request.QueryString); // event? callback recieved, pass response (allow cancel and need new url?) var authorizeResponseEventArgs = new AuthorizeResponseEventArgs { Response = response }; OnAuthorizeResponse(authorizeResponseEventArgs); if (authorizeResponseEventArgs.Cancel) { if (String.IsNullOrWhiteSpace(authorizeResponseEventArgs.RedirectUrl)) { throw new ArgumentNullException("RedirectUrl"); } context.Response.Redirect(authorizeResponseEventArgs.RedirectUrl); return; } if (response.IsError) { if (!String.IsNullOrWhiteSpace(authorizeErrorUrl)) { if (!authorizeErrorUrl.Contains("?")) { authorizeErrorUrl += "?"; } if (!authorizeErrorUrl.EndsWith("?")) { authorizeErrorUrl += "&"; } authorizeErrorUrl += "error=" + response.Error; context.Response.Redirect(authorizeErrorUrl); return; } throw new InvalidOperationException("OpenID Connect Callback Error: " + response.Error + ". Handle the AuthorizeResponse event to handle authorization errors."); } try { // read and parse state cookie var cookie = new ProtectedCookie(ProtectionMode.MachineKey); var storedState = cookie.Read("oidcstate"); ProtectedCookie.Delete("oidcstate"); var separator = storedState.IndexOf('_'); if (separator == -1) { throw new InvalidOperationException("state invalid."); } var state = storedState.Substring(0, separator); var returnUrl = storedState.Substring(separator + 1); if (appRelativeCallbackUrl.StartsWith("~/")) { appRelativeCallbackUrl = appRelativeCallbackUrl.Substring(2); } var redirectUri = context.Request.GetApplicationUrl() + appRelativeCallbackUrl; // validate state if (response.State != state) { throw new InvalidOperationException("state invalid."); } // call token endpoint and retrieve id and access token (and maybe a refresh token) var tokenResponse = await OidcClient.CallTokenEndpointAsync( new Uri(tokenUrl), new Uri(redirectUri), response.Code, clientId, clientSecret); // event -- token obtained event var tokenResponseEventArgs = new TokenResponseEventArgs { Response = tokenResponse }; OnTokenResponse(tokenResponseEventArgs); if (tokenResponseEventArgs.Cancel) { if (String.IsNullOrWhiteSpace(tokenResponseEventArgs.RedirectUrl)) { throw new ArgumentNullException("RedirectUrl"); } context.Response.Redirect(tokenResponseEventArgs.RedirectUrl); return; } // validate identity token var identityClaims = OidcClient.ValidateIdentityToken( tokenResponse.IdentityToken, issuerName, clientId, signingcert); // event -- identity token validated w/ claims var identityTokenValidatedEventArgs = new IdentityTokenValidatedEventArgs { Claims = identityClaims }; OnIdentityTokenValidated(identityTokenValidatedEventArgs); if (identityTokenValidatedEventArgs.Cancel) { if (String.IsNullOrWhiteSpace(identityTokenValidatedEventArgs.RedirectUrl)) { throw new ArgumentNullException("RedirectUrl"); } context.Response.Redirect(identityTokenValidatedEventArgs.RedirectUrl); return; } var claims = identityTokenValidatedEventArgs.Claims.ToList(); if (callUserInfoEndpoint) { // retrieve user info data var userInfoClaims = await OidcClient.GetUserInfoClaimsAsync( new Uri(userInfoUrl), tokenResponse.AccessToken); // event -- profile loaded w/ claims var userInfoClaimsReceivedEventArgs = new UserInfoClaimsReceivedEventArgs { Claims = userInfoClaims }; OnUserInfoClaimsReceived(userInfoClaimsReceivedEventArgs); if (userInfoClaimsReceivedEventArgs.Cancel) { if (String.IsNullOrWhiteSpace(userInfoClaimsReceivedEventArgs.RedirectUrl)) { throw new ArgumentNullException("RedirectUrl"); } context.Response.Redirect(userInfoClaimsReceivedEventArgs.RedirectUrl); return; } claims = userInfoClaimsReceivedEventArgs.Claims.ToList(); } // create identity claims.Add(new Claim("at", tokenResponse.AccessToken)); var id = new ClaimsIdentity(claims, "oidc"); if (!string.IsNullOrWhiteSpace(tokenResponse.RefreshToken)) { id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken)); } // create principal var principal = new ClaimsPrincipal(id); var transformedPrincipal = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(string.Empty, principal); // establish session var sessionToken = new SessionSecurityToken(transformedPrincipal); // event? raise session security token created var sessionTokenCreatedEventArgs = new SessionTokenCreatedEventArgs { Token = sessionToken }; OnSessionSecurityTokenCreated(sessionTokenCreatedEventArgs); FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken); // event? signed in -- pass in return URL and allow them to change OnSignedIn(); // redirect local to return url if (!string.IsNullOrWhiteSpace(returnUrl)) { context.Response.Redirect(returnUrl); } else { context.Response.Redirect("~/"); } } catch (Exception ex) { // event? general error/fail var errorEventArgs = new ErrorEventArgs() { Exception = ex }; OnError(errorEventArgs); if (!errorEventArgs.ExceptionHandled) { throw; } } } }
void OnAuthenticateRequestRequest(object sender, EventArgs e) { var context = HttpContext.Current; if (context.Request.AppRelativeCurrentExecutionFilePath.Equals("~/oidccallback", StringComparison.OrdinalIgnoreCase)) { var config = OidcClientConfigurationSection.Instance; var tokenUrl = config.Endpoints.Token; var userInfoUrl = config.Endpoints.UserInfo; var clientId = config.ClientId; var clientSecret = config.ClientSecret; var issuerName = config.IssuerName; var signingcert = X509.LocalMachine.TrustedPeople.SubjectDistinguishedName.Find( config.SigningCertificate).First(); // parse OIDC authorize response var response = OidcClient.HandleAuthorizeResponse(context.Request.QueryString); if (response.IsError) { throw new InvalidOperationException(response.Error); } // read and parse state cookie var cookie = new ProtectedCookie(ProtectionMode.MachineKey); var storedState = cookie.Read("oidcstate"); var separator = storedState.IndexOf('_'); if (separator == -1) { throw new InvalidOperationException("state invalid."); } var state = storedState.Substring(0, separator); var returnUrl = storedState.Substring(separator + 1); var redirectUri = context.Request.GetApplicationUrl() + "oidccallback"; // validate state if (response.State != state) { throw new InvalidOperationException("state invalid."); } // call token endpoint and retrieve id and access token (and maybe a refresh token) var tokenResponse = OidcClient.CallTokenEndpoint( new Uri(tokenUrl), new Uri(redirectUri), response.Code, clientId, clientSecret); // validate identity token var identityClaims = OidcClient.ValidateIdentityToken( tokenResponse.IdentityToken, issuerName, clientId, signingcert); // retrieve user info data var userInfoClaims = OidcClient.GetUserInfoClaims( new Uri(userInfoUrl), tokenResponse.AccessToken); // create identity var id = new ClaimsIdentity(userInfoClaims, "oidc"); if (!string.IsNullOrWhiteSpace(tokenResponse.RefreshToken)) { id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken)); } // create principal var principal = new ClaimsPrincipal(id); var transformedPrincipal = FederatedAuthentication.FederationConfiguration.IdentityConfiguration.ClaimsAuthenticationManager.Authenticate(string.Empty, principal); // establish session var sessionToken = new SessionSecurityToken(transformedPrincipal); FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken); // redirect local to return url if (!string.IsNullOrWhiteSpace(returnUrl)) { context.Response.Redirect(returnUrl); } else { context.Response.Redirect("~/"); } } }