コード例 #1
0
        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));
        }
コード例 #2
0
        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));
        }
コード例 #3
0
        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);
        }
コード例 #4
0
        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);
        }
コード例 #5
0
    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));
    }
コード例 #6
0
        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));
            }
        }
コード例 #7
0
    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));
    }
コード例 #8
0
        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);
        }
コード例 #9
0
ファイル: OpenIddictServer.cs プロジェクト: montr/montr
        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));
        }
コード例 #10
0
        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));
        }
コード例 #11
0
        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));
        }
コード例 #12
0
    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);
    }
コード例 #13
0
        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));
        }
コード例 #14
0
        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."
            }));
        }