private async Task <IActionResult> PasswordFlow(OpenIddictRequest request) { if (!request.IsPasswordGrantType()) { return(BadRequest("The specified grant type is not implemented.")); } var user = await _user.FindByNameAsync(request.Username); if (user == null || !await _sign.CanSignInAsync(user)) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid" }); return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } // Validate the username/password parameters and ensure the account is not locked out. var result = await _sign.CheckPasswordSignInAsync(user, request.Password, true); if (!result.Succeeded) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid" }); return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } var principal = await _sign.CreateUserPrincipalAsync(user); principal.SetScopes(request.GetScopes()); principal.SetResources(await _scope.ListResourcesAsync(request.GetScopes()).ToListAsync()); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
private async Task <IActionResult> CodeFlow(OpenIddictRequest request) { if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType()) { throw new InvalidOperationException("The specified grant type is not supported."); } var principal = (await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)).Principal; if (principal == null) { return(NotFound()); } var user = await _sign.ValidateSecurityStampAsync(principal); if (user == null) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." }))); } if (!await _sign.CanSignInAsync(user)) { return(Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." }))); } principal.SetScopes(request.GetScopes()); principal.SetResources(await _scope.ListResourcesAsync(request.GetScopes()).ToListAsync()); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
public static async Task <string> IsUserAuthorized( OpenIddictAuthorizationManager <BTCPayOpenIdAuthorization> authorizationManager, OpenIddictRequest request, string userId, string applicationId) { var authorizations = await authorizationManager.ListAsync(queryable => queryable.Where(authorization => authorization.Subject.Equals(userId, StringComparison.OrdinalIgnoreCase) && applicationId.Equals(authorization.Application.Id, StringComparison.OrdinalIgnoreCase) && authorization.Status.Equals(OpenIddictConstants.Statuses.Valid, StringComparison.OrdinalIgnoreCase))).ToArrayAsync(); if (authorizations.Length > 0) { var scopeTasks = authorizations.Select(authorization => (authorizationManager.GetScopesAsync(authorization).AsTask(), authorization.Id)); await Task.WhenAll(scopeTasks.Select((tuple) => tuple.Item1)); var authorizationsWithSufficientScopes = scopeTasks .Select((tuple) => (Id: tuple.Id, Scopes: tuple.Item1.Result)) .Where((tuple) => !request.GetScopes().Except(tuple.Scopes).Any()); if (authorizationsWithSufficientScopes.Any()) { return(authorizationsWithSufficientScopes.First().Id); } } return(null); }
public static async Task <ClaimsPrincipal> CreateClaimsPrincipalAsync(OpenIddictApplicationManager <BTCPayOpenIdClient> applicationManager, OpenIddictAuthorizationManager <BTCPayOpenIdAuthorization> authorizationManager, IdentityOptions identityOptions, SignInManager <ApplicationUser> signInManager, OpenIddictRequest request, ApplicationUser user) { var principal = await signInManager.CreateUserPrincipalAsync(user); if (!request.IsAuthorizationCodeGrantType() && !request.IsRefreshTokenGrantType()) { principal.SetScopes(request.GetScopes().Restrict(principal)); } else if (request.IsAuthorizationCodeGrantType() && string.IsNullOrEmpty(principal.GetInternalAuthorizationId())) { var app = await applicationManager.FindByClientIdAsync(request.ClientId); var authorizationId = await IsUserAuthorized(authorizationManager, request, user.Id, app.Id); if (!string.IsNullOrEmpty(authorizationId)) { principal.SetInternalAuthorizationId(authorizationId); } } principal.SetDestinations(identityOptions); return(principal); }
protected virtual async Task <IActionResult> HandleClientCredentialsAsync(OpenIddictRequest request) { // Note: the client credentials are automatically validated by OpenIddict: // if client_id or client_secret are invalid, this action won't be invoked. var application = await ApplicationManager.FindByClientIdAsync(request.ClientId); if (application == null) { throw new InvalidOperationException(L["TheApplicationDetailsCannotBeFound"]); } // Create a new ClaimsIdentity containing the claims that // will be used to create an id_token, a token or a code. var identity = new ClaimsIdentity( TokenValidationParameters.DefaultAuthenticationType, OpenIddictConstants.Claims.PreferredUsername, OpenIddictConstants.Claims.Role); // The Subject and PreferredUsername will be removed by <see cref="RemoveClaimsFromClientCredentialsGrantType"/>. // Use the client_id as the subject identifier. identity.AddClaim(OpenIddictConstants.Claims.Subject, await ApplicationManager.GetClientIdAsync(application), OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); identity.AddClaim(OpenIddictConstants.Claims.PreferredUsername, await ApplicationManager.GetDisplayNameAsync(application), OpenIddictConstants.Destinations.AccessToken, OpenIddictConstants.Destinations.IdentityToken); // Note: In the original OAuth 2.0 specification, the client credentials grant // doesn't return an identity token, which is an OpenID Connect concept. // // As a non-standardized extension, OpenIddict allows returning an id_token // to convey information about the client application when the "openid" scope // is granted (i.e specified when calling principal.SetScopes()). When the "openid" // scope is not explicitly set, no identity token is returned to the client application. // Set the list of scopes granted to the client application in access_token. var principal = new ClaimsPrincipal(identity); principal.SetScopes(request.GetScopes()); principal.SetResources(await GetResourcesAsync(request.GetScopes())); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim)); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
private async Task EnrichPrincipalAsync(OpenIddictRequest request, ClaimsPrincipal principal, bool alwaysDeliverPermissions) { var scopes = request.GetScopes(); principal.SetScopes(scopes); principal.SetResources(await scopeManager.ListResourcesAsync(scopes, HttpContext.RequestAborted).ToListAsync(HttpContext.RequestAborted)); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal, alwaysDeliverPermissions)); } }
protected virtual async Task <IActionResult> SetSuccessResultAsync(OpenIddictRequest request, IdentityUser user) { // Create a new ClaimsPrincipal containing the claims that // will be used to create an id_token, a token or a code. var principal = await SignInManager.CreateUserPrincipalAsync(user); principal.SetScopes(request.GetScopes()); principal.SetResources(await GetResourcesAsync(request.GetScopes())); await SetClaimsDestinationsAsync(principal); await IdentitySecurityLogManager.SaveAsync( new IdentitySecurityLogContext { Identity = OpenIddictSecurityLogIdentityConsts.OpenIddict, Action = OpenIddictSecurityLogActionConsts.LoginSucceeded, UserName = request.Username, ClientId = request.ClientId } ); return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
private async Task <ClaimsPrincipal> EnrichPrincipalAsync(ClaimsPrincipal principal, OpenIddictRequest request) { var scopes = request.GetScopes(); var resources = await scopeManager.ListResourcesAsync(scopes, HttpContext.RequestAborted).ToListAsync(HttpContext.RequestAborted); principal.SetScopes(scopes); principal.SetResources(resources); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return(principal); }
private async Task <IActionResult> AuthorizeImplicitFlow( OpenIddictRequest oidcRequest, HttpContext httpContext, CancellationToken cancellationToken) { if (httpContext.User.Identity?.IsAuthenticated == false) { // If the client application request promptless authentication, // return an error indicating that the user is not logged in. if (oidcRequest.HasPrompt(Prompts.None)) { var properties = new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in." }); // Ask OpenIddict to return a login_required error to the client application. return(new ForbidResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties)); } return(new ChallengeResult()); } // Retrieve the profile of the logged in user. var dbUser = await _userManager.GetUserAsync(httpContext.User) ?? throw new InvalidOperationException("The user details cannot be retrieved."); // Create a new ClaimsPrincipal containing the claims that // will be used to create an id_token, a token or a code. var principal = await _signInManager.CreateUserPrincipalAsync(dbUser); // Set the list of scopes granted to the client application. var scopes = oidcRequest.GetScopes(); var resources = await _scopeManager.ListResourcesAsync(scopes, cancellationToken).ToListAsync(); principal.SetScopes(scopes); principal.SetResources(resources); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } // Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens. return(new SignInResult(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, principal)); }
private async Task <IActionResult> ExchangeClientCredentialsGrantType(OpenIddictRequest request) { // Note: client authentication is always enforced by OpenIddict before this action is invoked. var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ?? throw new InvalidOperationException("The application details cannot be found."); var identity = new ClaimsIdentity( OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, Claims.Name, Claims.Role); identity.AddClaim(OpenIdConstants.Claims.EntityType, OpenIdConstants.EntityTypes.Application, Destinations.AccessToken, Destinations.IdentityToken); identity.AddClaim(Claims.Subject, request.ClientId, Destinations.AccessToken, Destinations.IdentityToken); identity.AddClaim(Claims.Name, await _applicationManager.GetDisplayNameAsync(application), Destinations.AccessToken, Destinations.IdentityToken); // If the role service is available, add all the role claims // associated with the application roles in the database. var roleService = HttpContext.RequestServices.GetService <IRoleService>(); foreach (var role in await _applicationManager.GetRolesAsync(application)) { identity.AddClaim(identity.RoleClaimType, role, Destinations.AccessToken, Destinations.IdentityToken); if (roleService != null) { foreach (var claim in await roleService.GetRoleClaimsAsync(role)) { identity.AddClaim(claim.SetDestinations(Destinations.AccessToken, Destinations.IdentityToken)); } } } var principal = new ClaimsPrincipal(identity); principal.SetResources(await GetResourcesAsync(request.GetScopes())); return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
private async Task <ActionResult> SignInAsync(OpenIddictRequest request, ApplicationUser user) { // Create a new ClaimsPrincipal containing the claims that // will be used to create an id_token, a token or a code. ClaimsPrincipal principal = await _signInManager.CreateUserPrincipalAsync(user); // Set the list of scopes granted to the client application. // Note: the offline_access scope must be granted // to allow OpenIddict to return a refresh token. principal.SetScopes(AllowedRefreshTokenScopes.Intersect(request.GetScopes())); // Note: by default, claims are NOT automatically included in the access and identity tokens. // To allow OpenIddict to serialize them, you must attach them a destination, that specifies // whether they should be included in access tokens, in identity tokens or in both. foreach (Claim claim in principal.Claims) { // Never include the security stamp in the access and identity tokens, as it's a secret value. if (claim.Type == _identityOptions.Value.ClaimsIdentity.SecurityStampClaimType) { continue; } List <string> destinations = new() { OpenIddictConstants.Destinations.AccessToken, }; // Only add the iterated claim to the id_token if the corresponding scope was granted to the client application. // The other claims will only be added to the access_token, which is encrypted when using the default format. if ((claim.Type == OpenIddictConstants.Claims.Name && principal.HasScope(OpenIddictConstants.Scopes.Profile)) || (claim.Type == OpenIddictConstants.Claims.Email && principal.HasScope(OpenIddictConstants.Scopes.Email)) || (claim.Type == OpenIddictConstants.Claims.Role && principal.HasScope(OpenIddictConstants.Scopes.Roles))) { destinations.Add(OpenIddictConstants.Destinations.IdentityToken); } claim.SetDestinations(destinations); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
public async Task <ClaimsPrincipal> Handle(OpenIddictRequest request) { if (!request.IsClientCredentialsGrantType()) { throw new NotImplementedException("The specified grant type is not implemented"); } var application = await _applicationManager.FindByClientIdAsync(request.ClientId !) ?? throw new NotFoundException <string?>("Admin API Client", request.ClientId); if (!await _applicationManager.ValidateClientSecretAsync(application, request.ClientSecret !)) { throw new AuthenticationException("Invalid Admin API Client key and secret"); } var requestedScopes = request.GetScopes(); var appScopes = (await _applicationManager.GetPermissionsAsync(application)) .Where(p => p.StartsWith(OpenIddictConstants.Permissions.Prefixes.Scope)) .Select(p => p.Substring(OpenIddictConstants.Permissions.Prefixes.Scope.Length)) .ToList(); var missingScopes = requestedScopes.Where(s => !appScopes.Contains(s)).ToList(); if (missingScopes.Any()) { throw new AuthenticationException($"Client is not allowed access to requested scope(s): {string.Join(", " , missingScopes)}"); } var displayName = await _applicationManager.GetDisplayNameAsync(application); var identity = new ClaimsIdentity(JwtBearerDefaults.AuthenticationScheme); identity.AddClaim(OpenIddictConstants.Claims.Subject, request.ClientId !, OpenIddictConstants.Destinations.AccessToken); identity.AddClaim(OpenIddictConstants.Claims.Name, displayName !, OpenIddictConstants.Destinations.AccessToken); var principal = new ClaimsPrincipal(identity); principal.SetScopes(requestedScopes); return(principal); }
private async Task <IActionResult> ExchangePasswordGrantType(OpenIddictRequest request) { var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ?? throw new InvalidOperationException("The application details cannot be found."); // By design, the password flow requires direct username/password validation, which is performed by // the user service. If this service is not registered, prevent the password flow from being used. var service = HttpContext.RequestServices.GetService <IUserService>(); if (service == null) { return(Forbid(new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.UnsupportedGrantType, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = S["The resource owner password credentials grant is not supported."] }), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } string error = null; var user = await service.AuthenticateAsync(request.Username, request.Password, (key, message) => error = message); if (user == null) { return(Forbid(new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.InvalidGrant, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = error }), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } var principal = await service.CreatePrincipalAsync(user); var authorizations = await _authorizationManager.FindAsync( subject : principal.GetUserIdentifier(), client : await _applicationManager.GetIdAsync(application), status : Statuses.Valid, type : AuthorizationTypes.Permanent, scopes : request.GetScopes()).ToListAsync(); // If the application is configured to use external consent, // reject the request if no existing authorization can be found. switch (await _applicationManager.GetConsentTypeAsync(application)) { case ConsentTypes.External when !authorizations.Any(): return(Forbid(new AuthenticationProperties(new Dictionary <string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = S["The logged in user is not allowed to access this client application."] }), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); } var identity = (ClaimsIdentity)principal.Identity; identity.AddClaim(OpenIdConstants.Claims.EntityType, OpenIdConstants.EntityTypes.User, Destinations.AccessToken, Destinations.IdentityToken); // Note: while ASP.NET Core Identity uses the legacy WS-Federation claims (exposed by the ClaimTypes class), // OpenIddict uses the newer JWT claims defined by the OpenID Connect specification. To ensure the mandatory // subject claim is correctly populated (and avoid an InvalidOperationException), it's manually added here. if (string.IsNullOrEmpty(principal.FindFirst(Claims.Subject)?.Value)) { identity.AddClaim(new Claim(Claims.Subject, principal.GetUserIdentifier())); } principal.SetScopes(request.GetScopes()); principal.SetResources(await GetResourcesAsync(request.GetScopes())); // Automatically create a permanent authorization to avoid requiring explicit consent // for future authorization or token requests containing the same scopes. var authorization = authorizations.FirstOrDefault(); if (authorization == null) { authorization = await _authorizationManager.CreateAsync( principal : principal, subject : principal.GetUserIdentifier(), client : await _applicationManager.GetIdAsync(application), type : AuthorizationTypes.Permanent, scopes : principal.GetScopes()); } principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme)); }
public async Task <IActionResult> Exchange() { //Change based on: https://github.com/openiddict/openiddict-core/blob/dev/samples/Mvc.Server/Controllers/AuthorizationController.cs#L59 //If you try to do it as a parameter then you'll get a grant_type failure for some reason. OpenIddictRequest authRequest = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); if (authRequest.IsPasswordGrantType()) { return(await Authenticate(authRequest.Username, authRequest.Password, authRequest.GetScopes())); } return(BadRequest(new OpenIddictResponse() { Error = OpenIddictConstants.Errors.UnsupportedGrantType, ErrorDescription = "The specified grant type is not supported." })); }