コード例 #1
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);
        }
コード例 #2
0
        private async Task <IActionResult> ExchangeAuthorizationCodeOrRefreshTokenGrantType(OpenIddictRequest request)
        {
            var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ??
                              throw new InvalidOperationException("The application details cannot be found.");

            // Retrieve the claims principal stored in the authorization code/refresh token.
            var info = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme) ??
                       throw new InvalidOperationException("The user principal cannot be resolved.");

            if (request.IsRefreshTokenGrantType())
            {
                var type = info.Principal.FindFirst(OpenIdConstants.Claims.EntityType)?.Value;
                if (!string.Equals(type, OpenIdConstants.EntityTypes.User))
                {
                    return(Forbid(new AuthenticationProperties(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.UnauthorizedClient,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] =
                            "The refresh token grant type is not allowed for refresh tokens retrieved using the client credentials flow."
                    }), OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }
            }

            // By default, re-use the principal stored in the authorization code/refresh token.
            var principal = info.Principal;

            // If the user service is available, try to refresh the principal by retrieving
            // the user object from the database and creating a new claims-based principal.
            var service = HttpContext.RequestServices.GetService <IUserService>();

            if (service != null)
            {
                var user = await service.GetUserByUniqueIdAsync(principal.GetUserIdentifier());

                if (user != null)
                {
                    principal = await service.CreatePrincipalAsync(user);
                }
            }

            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()));
            }

            foreach (var claim in principal.Claims)
            {
                claim.SetDestinations(GetDestinations(claim, principal));
            }

            return(SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
        }
コード例 #3
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));
        }
コード例 #4
0
        public async Task <ActionResult> ExchangeAsync()
        {
            OpenIddictRequest request = HttpContext.GetOpenIddictServerRequest();

            if (request.IsPasswordGrantType())
            {
                // Allow the user to log in with their email address too.
                // We already check that usernames are only "word" chars (\w+), so this check is sufficient.
                ApplicationUser user = request.Username.Contains("@", StringComparison.Ordinal)
                    ? await _userManager.FindByEmailAsync(request.Username)
                    : await _userManager.FindByNameAsync(request.Username);

                if (user == null)
                {
                    AuthenticationProperties properties = new(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.
                SignInResult result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, lockoutOnFailure : false);

                if (!result.Succeeded)
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The username/password couple is invalid.",
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                return(await SignInAsync(request, user));
            }

            if (request.IsRefreshTokenGrantType())
            {
                // Retrieve the claims principal stored in the refresh token.
                AuthenticateResult result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme);

                // Retrieve the user profile corresponding to the refresh token.
                ApplicationUser user = await _signInManager.ValidateSecurityStampAsync(result.Principal);

                if (user == null)
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The refresh token is no longer valid.",
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                // Ensure the user is still allowed to sign in.
                if (!await _signInManager.CanSignInAsync(user))
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in.",
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                // Reuse the properties stored in the refresh token, including the scopes originally granted.
                return(await SignInAsync(request, user));
            }

            IAssertionGrantHandler assertionGrantHandler = _assertionGrantHandlerProvider.GetHandler(request.GrantType);

            if (assertionGrantHandler != null)
            {
                // Reject the request if the "assertion" parameter is missing.
                if (string.IsNullOrEmpty(request.Assertion))
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidRequest,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The mandatory 'assertion' parameter was missing.",
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                AssertionGrantResult validationResult = await assertionGrantHandler.ValidateAsync(request.Assertion);

                if (!validationResult.IsSuccessful)
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = validationResult.Error,
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                // Find the user associated with this external log in
                ApplicationUser user = await _userManager.FindByLoginAsync(assertionGrantHandler.Name, validationResult.ExternalUserId);

                if (user == null)
                {
                    if (!string.IsNullOrEmpty(request.Username))
                    {
                        // They provided a user name, so try to implicitly create an account for them
                        user = new ApplicationUser {
                            UserName = request.Username, Email = validationResult.ExternalUserEmail
                        };
                        IdentityResult creationResult = await _userManager.CreateAsync(user);

                        if (!creationResult.Succeeded)
                        {
                            AuthenticationProperties properties = new(new Dictionary <string, string>
                            {
                                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = string.Join(" ", creationResult.Errors.Select(error => error.Description)),
                            });

                            return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                        }
                    }

                    if (user == null)
                    {
                        // If the user is already logged in, use the current user
                        user = await _userManager.GetUserAsync(User);
                    }

                    // Add the login if we found a user
                    if (user != null)
                    {
                        UserLoginInfo  login          = new(assertionGrantHandler.Name, validationResult.ExternalUserId, assertionGrantHandler.Name);
                        IdentityResult addLoginResult = await _userManager.AddLoginAsync(user, login);

                        if (!addLoginResult.Succeeded)
                        {
                            AuthenticationProperties properties = new(new Dictionary <string, string>
                            {
                                [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                                [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = string.Join(" ", addLoginResult.Errors.Select(error => error.Description)),
                            });

                            return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                        }
                    }
                    else
                    {
                        // Ask the user to create an account.
                        AuthenticationProperties properties = new(new Dictionary <string, string>
                        {
                            [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.AccountSelectionRequired,
                        });

                        return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                    }
                }

                // Ensure the user is allowed to sign in.
                if (!await _signInManager.CanSignInAsync(user))
                {
                    AuthenticationProperties properties = new(new Dictionary <string, string>
                    {
                        [OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant,
                        [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in.",
                    });

                    return(Forbid(properties, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme));
                }

                return(await SignInAsync(request, user));
            }

            throw new NotImplementedException("The specified grant type is not implemented.");
        }