/// <summary> /// Represents an event called for each validated userinfo request /// to allow the user code to decide how the request should be handled. /// </summary> /// <param name="context">The context instance associated with this event.</param> /// <returns>A <see cref="T:System.Threading.Tasks.Task" /> that can be used to monitor the asynchronous operation.</returns> public override Task HandleUserinfoRequest(HandleUserinfoRequestContext context) { var result = base.HandleUserinfoRequest(context); var clientId = context.Ticket?.Identity?.GetClaim("client_id"); var userName = context.Ticket?.Identity?.GetClaim("username"); if (clientId.IsNullOrWhiteSpace() || userName.IsNullOrWhiteSpace()) { return(result); } // Populate requested/allowed claims // See https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/issues/543 using (var rockContext = new RockContext()) { var user = new UserLoginService(rockContext).GetByUserName(userName); if (user == null) { return(result); } var requestedScopes = context.Ticket?.GetScopes(); var clientAllowedScopes = RockIdentityHelper.NarrowRequestedScopesToApprovedScopes(rockContext, clientId, requestedScopes); var clientAllowedClaims = RockIdentityHelper.GetAllowedClientClaims(rockContext, clientId, clientAllowedScopes); var claimsIdentity = RockIdentityHelper.GetRockClaimsIdentity(user, clientAllowedClaims, clientId); foreach (var claim in claimsIdentity?.Claims) { context.Claims.Add(claim.Type, claim.Value); } } return(result); }
/// <summary> /// Represents an event called for each validated token request /// to allow the user code to decide how the request should be handled. /// </summary> /// <param name="context">The context instance associated with this event.</param> public override Task HandleTokenRequest(HandleTokenRequestContext context) { // Only handle grant_type=password requests and let ASOS // process grant_type=refresh_token requests automatically. if (context.Request.IsPasswordGrantType()) { UserLogin user = null; ClaimsIdentity identity = null; IEnumerable <string> allowedClientScopes = null; var loginValid = false; // Do all the data access here so we can dispose of the rock context asap. using (var rockContext = new RockContext()) { var userLoginService = new UserLoginService(rockContext); user = userLoginService.GetByUserName(context.Request.Username); // Populate the entity type for use later. _ = user.EntityType; allowedClientScopes = RockIdentityHelper.NarrowRequestedScopesToApprovedScopes(rockContext, context.Request.ClientId, context.Request.GetScopes()).ToList(); var allowedClientClaims = RockIdentityHelper.GetAllowedClientClaims(rockContext, context.Request.ClientId, allowedClientScopes); identity = RockIdentityHelper.GetRockClaimsIdentity(user, allowedClientClaims, context.Request.ClientId); var component = AuthenticationContainer.GetComponent(user.EntityType.Name); if (component != null && component.IsActive && !component.RequiresRemoteAuthentication) { loginValid = component.AuthenticateAndTrack(user, context.Request.Password); rockContext.SaveChanges(); } } if (identity == null || allowedClientScopes == null) { context.Reject( error: OpenIdConnectConstants.Errors.InvalidClient, description: "Invalid client configuration."); return(Task.FromResult(0)); } if (user == null || !loginValid) { context.Reject( error: OpenIdConnectConstants.Errors.InvalidGrant, description: "Invalid credentials."); return(Task.FromResult(0)); } // Ensure the user is allowed to sign in. if (!user.IsConfirmed.HasValue || !user.IsConfirmed.Value || (user.IsPasswordChangeRequired != null && user.IsPasswordChangeRequired.Value)) { context.Reject( error: OpenIdConnectConstants.Errors.InvalidGrant, description: "The specified user is not allowed to sign in."); return(Task.FromResult(0)); } // Create a new authentication ticket holding the user identity. var ticket = new AuthenticationTicket(identity, new AuthenticationProperties()); // Set the list of scopes granted to the client application. ticket.SetScopes(allowedClientScopes); // Set the resource servers the access token should be issued for. ticket.SetResources("resource_server"); context.Validate(ticket); } if (context.Request.IsClientCredentialsGrantType()) { // We don't need to validate the client id here because it was already validated in the ValidateTokenRequest method. var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationType); identity.AddClaim(OpenIdConnectConstants.Claims.Subject, context.Request.ClientId, OpenIdConnectConstants.Destinations.AccessToken); // Create a new authentication ticket holding the user identity. var ticket = new AuthenticationTicket(identity, new AuthenticationProperties()); context.Validate(ticket); } return(Task.FromResult(0)); }