/*****************************************/
        /* helper APIs for the AccountController */
        /*****************************************/
        private async Task <LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
        {
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context?.IdP != null && await _schemeProvider.GetSchemeAsync(context.IdP) != null)
            {
                var local = context.IdP == IdentityServer4.IdentityServerConstants.LocalIdentityProvider;

                // this is meant to short circuit the UI and only trigger the one external IdP
                var vm = new LoginViewModel
                {
                    EnableLocalLogin = local,
                    ReturnUrl        = returnUrl,
                    Username         = context?.LoginHint,
                };

                if (!local)
                {
                    vm.ExternalProviders = new[] { new ExternalProvider {
                                                       AuthenticationScheme = context.IdP
                                                   } };
                }

                return(vm);
            }

            var schemes = await _schemeProvider.GetAllSchemesAsync();

            var providers = schemes
                            .Where(x => x.DisplayName != null)
                            .Select(x => new ExternalProvider
            {
                DisplayName          = x.DisplayName ?? x.Name,
                AuthenticationScheme = x.Name
            }).ToList();

            var allowLocal = true;

            if (context?.Client.ClientId != null)
            {
                var client = await _clientStore.FindEnabledClientByIdAsync(context.Client.ClientId);

                if (client != null)
                {
                    allowLocal = client.EnableLocalLogin;

                    if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
                    {
                        providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
                    }
                }
            }

            return(new LoginViewModel
            {
                AllowRememberLogin = AccountOptions.AllowRememberLogin,
                EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin,
                ReturnUrl = returnUrl,
                Username = context?.LoginHint,
                ExternalProviders = providers.ToArray()
            });
        }
示例#2
0
        /// <summary>
        /// Validates the asynchronous.
        /// </summary>
        /// <param name="message">The message.</param>
        /// <param name="user">The user.</param>
        /// <returns></returns>
        public async Task <SignInValidationResult> ValidateAsync(WsFederationMessage message, ClaimsPrincipal user)
        {
            var result = new SignInValidationResult
            {
                WsFederationMessage = message
            };

            // check client
            var client = await _clients.FindEnabledClientByIdAsync(message.Wtrealm);

            if (client == null)
            {
                return(new SignInValidationResult
                {
                    Error = "invalid_relying_party",
                    ErrorMessage = $"{message.Wtrealm} client not found."
                });
            }
            if (client.ProtocolType != IdentityServerConstants.ProtocolTypes.WsFederation)
            {
                return(new SignInValidationResult
                {
                    Error = "invalid_relying_party",
                    ErrorMessage = $"{message.Wtrealm} client is not a wsfed client."
                });
            }

            var rp = await _relyingParties.FindRelyingPartyByRealm(message.Wtrealm).ConfigureAwait(false);

            if (rp == null)
            {
                return(new SignInValidationResult
                {
                    Error = "invalid_relying_party",
                    ErrorMessage = $"{message.Wtrealm} relying party not found."
                });
            }

            var replyUrl = message.Wreply ?? client.RedirectUris.FirstOrDefault();

            if (!Uri.TryCreate(replyUrl, UriKind.Absolute, out Uri _))
            {
                return(new SignInValidationResult
                {
                    Error = "invalid_relying_party",
                    ErrorMessage = $"'{replyUrl}' is not a valid absolute uri. Message wreply received: {message.Wreply}. Client 1st redirect uri: {client.RedirectUris.FirstOrDefault()}."
                });
            }

            result.Client       = client;
            result.ReplyUrl     = replyUrl;
            result.RelyingParty = rp;

            if (user == null || !user.Identity.IsAuthenticated)
            {
                result.SignInRequired = true;
            }

            result.User = user;

            return(result);
        }
        private async Task <AuthorizeRequestValidationResult> ValidateClientAsync(ValidatedAuthorizeRequest request)
        {
            //////////////////////////////////////////////////////////
            // client_id must be present
            /////////////////////////////////////////////////////////
            var clientId = request.Raw.Get(OidcConstants.AuthorizeRequest.ClientId);

            if (clientId.IsMissingOrTooLong(_options.InputLengthRestrictions.ClientId))
            {
                LogError("client_id is missing or too long", request);
                return(Invalid(request, description: "Invalid client_id"));
            }

            request.ClientId = clientId;


            //////////////////////////////////////////////////////////
            // redirect_uri must be present, and a valid uri
            //////////////////////////////////////////////////////////
            var redirectUri = request.Raw.Get(OidcConstants.AuthorizeRequest.RedirectUri);

            if (redirectUri.IsMissingOrTooLong(_options.InputLengthRestrictions.RedirectUri))
            {
                LogError("redirect_uri is missing or too long", request);
                return(Invalid(request, description: "Invalid redirect_uri"));
            }

            if (!Uri.TryCreate(redirectUri, UriKind.Absolute, out var _))
            {
                LogError("malformed redirect_uri: " + redirectUri, request);
                return(Invalid(request, description: "Invalid redirect_uri"));
            }

            request.RedirectUri = redirectUri;


            //////////////////////////////////////////////////////////
            // check for valid client
            //////////////////////////////////////////////////////////
            var client = await _clients.FindEnabledClientByIdAsync(request.ClientId);

            if (client == null)
            {
                LogError("Unknown client or not enabled: " + request.ClientId, request);
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient));
            }

            request.SetClient(client);

            //////////////////////////////////////////////////////////
            // check if client protocol type is oidc
            //////////////////////////////////////////////////////////
            if (request.Client.ProtocolType != IdentityServerConstants.ProtocolTypes.OpenIdConnect)
            {
                LogError($"Invalid protocol type for OIDC authorize endpoint: {request.Client.ProtocolType}", request);
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, description: "Invalid protocol"));
            }

            //////////////////////////////////////////////////////////
            // check if redirect_uri is valid
            //////////////////////////////////////////////////////////
            if (await _uriValidator.IsRedirectUriValidAsync(request.RedirectUri, request.Client) == false)
            {
                LogError("Invalid redirect_uri: " + request.RedirectUri, request);
                return(Invalid(request, OidcConstants.AuthorizeErrors.UnauthorizedClient, "Invalid redirect_uri"));
            }

            return(Valid(request));
        }
        /// <summary>
        /// Validates an identity token.
        /// </summary>
        /// <param name="token">The token.</param>
        /// <param name="clientId">The client identifier.</param>
        /// <param name="validateLifetime">if set to <c>true</c> the lifetime gets validated. Otherwise not.</param>
        /// <returns></returns>
        public virtual async Task <TokenValidationResult> ValidateIdentityTokenAsync(string token, string clientId = null, bool validateLifetime = true)
        {
            _logger.LogDebug("Start identity token validation");

            if (token.Length > _options.InputLengthRestrictions.Jwt)
            {
                _logger.LogError("JWT too long");
                return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            if (clientId.IsMissing())
            {
                clientId = GetClientIdFromJwt(token);

                if (clientId.IsMissing())
                {
                    _logger.LogError("No clientId supplied, can't find id in identity token.");
                    return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
                }
            }

            _log.ClientId         = clientId;
            _log.ValidateLifetime = validateLifetime;

            var client = await _clients.FindEnabledClientByIdAsync(clientId);

            if (client == null)
            {
                _logger.LogError("Unknown or diabled client: {clientId}.", clientId);
                return(Invalid(OidcConstants.ProtectedResourceErrors.InvalidToken));
            }

            _log.ClientName = client.ClientName;
            _logger.LogDebug("Client found: {clientId} / {clientName}", client.ClientId, client.ClientName);

            var keys = await _keys.GetValidationKeysAsync();

            var result = await ValidateJwtAsync(token, clientId, keys, validateLifetime);

            result.Client = client;

            if (result.IsError)
            {
                LogError("Error validating JWT");
                return(result);
            }

            _log.Claims = result.Claims.ToClaimsDictionary();

            _logger.LogDebug("Calling into custom token validator: {type}", _customValidator.GetType().FullName);
            var customResult = await _customValidator.ValidateIdentityTokenAsync(result);

            if (customResult.IsError)
            {
                LogError("Custom validator failed: " + (customResult.Error ?? "unknown"));
                return(customResult);
            }

            _log.Claims = customResult.Claims.ToClaimsDictionary();

            LogSuccess();
            return(customResult);
        }
示例#5
0
        public async Task <LoginViewModel> BuildLoginViewModelAsync(string returnUrl)
        {
            var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

            if (context?.IdP != null)
            {
                // this is meant to short circuit the UI and only trigger the one external IdP
                return(new LoginViewModel
                {
                    EnableLocalLogin = false,
                    ReturnUrl = returnUrl,
                    Email = context?.LoginHint,
                    ExternalProviders = new ExternalProvider[] { new ExternalProvider {
                                                                     AuthenticationScheme = context.IdP
                                                                 } }
                });
            }

            var schemes = _httpContextAccessor.HttpContext.Authentication.GetAuthenticationSchemes();

            var providers = schemes
                            .Where(x => x.DisplayName != null && !AccountOptions.WindowsAuthenticationSchemes.Contains(x.AuthenticationScheme))
                            .Select(x => new ExternalProvider
            {
                DisplayName          = x.DisplayName,
                AuthenticationScheme = x.AuthenticationScheme
            }).ToList();

            if (AccountOptions.WindowsAuthenticationEnabled)
            {
                // this is needed to handle windows auth schemes
                var windowsSchemes = schemes.Where(s => AccountOptions.WindowsAuthenticationSchemes.Contains(s.AuthenticationScheme));
                if (windowsSchemes.Any())
                {
                    providers.Add(new ExternalProvider
                    {
                        AuthenticationScheme = AccountOptions.WindowsAuthenticationSchemes.First(),
                        DisplayName          = AccountOptions.WindowsAuthenticationDisplayName
                    });
                }
            }

            var allowLocal = true;

            if (context?.ClientId != null)
            {
                var client = await _clientStore.FindEnabledClientByIdAsync(context.ClientId);

                if (client != null)
                {
                    allowLocal = client.EnableLocalLogin;

                    if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
                    {
                        providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
                    }
                }
            }

            return(new LoginViewModel
            {
                AllowRememberLogin = AccountOptions.AllowRememberLogin,
                EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin,
                ReturnUrl = returnUrl,
                Email = context?.LoginHint,
                ExternalProviders = providers.ToArray()
            });
        }
示例#6
0
        public async Task Invalid_GrantType_For_Client()
        {
            var client = await _clients.FindEnabledClientByIdAsync("client");

            var validator = Factory.CreateTokenRequestValidator();

            var parameters = new NameValueCollection();

            parameters.Add(OidcConstants.TokenRequest.GrantType, OidcConstants.GrantTypes.Password);
            parameters.Add(OidcConstants.TokenRequest.Scope, "resource");

            var result = await validator.ValidateRequestAsync(parameters, client.ToValidationResult());

            result.IsError.Should().BeTrue();
            result.Error.Should().Be(OidcConstants.TokenErrors.UnauthorizedClient);
        }
        public async Task Valid_Code_Request()
        {
            var client = await _clients.FindEnabledClientByIdAsync("codeclient");

            var grants = Factory.CreateGrantService();

            var code = new AuthorizationCode
            {
                Subject         = IdentityServerPrincipal.Create("123", "bob"),
                ClientId        = client.ClientId,
                Lifetime        = client.AuthorizationCodeLifetime,
                RedirectUri     = "https://server/cb",
                RequestedScopes = new List <string>
                {
                    "openid"
                }
            };

            await grants.StoreAuthorizationCodeAsync("valid", code);

            var validator = Factory.CreateTokenRequestValidator(
                grants: grants);

            var parameters = new NameValueCollection();

            parameters.Add(OidcConstants.TokenRequest.GrantType, OidcConstants.GrantTypes.AuthorizationCode);
            parameters.Add(OidcConstants.TokenRequest.Code, "valid");
            parameters.Add(OidcConstants.TokenRequest.RedirectUri, "https://server/cb");

            var result = await validator.ValidateRequestAsync(parameters, client);

            result.IsError.Should().BeFalse();
        }
    private async Task BuildModelAsync(string returnUrl)
    {
        Input = new InputModel
        {
            ReturnUrl = returnUrl
        };

        var context = await _interaction.GetAuthorizationContextAsync(returnUrl);

        if (context?.IdP != null && await _schemeProvider.GetSchemeAsync(context.IdP) != null)
        {
            var local = context.IdP == Duende.IdentityServer.IdentityServerConstants.LocalIdentityProvider;

            // this is meant to short circuit the UI and only trigger the one external IdP
            View = new ViewModel
            {
                EnableLocalLogin = local,
            };

            Input.Username = context?.LoginHint;

            if (!local)
            {
                View.ExternalProviders = new[] { new ViewModel.ExternalProvider {
                                                     AuthenticationScheme = context.IdP
                                                 } };
            }

            return;
        }

        var schemes = await _schemeProvider.GetAllSchemesAsync();

        var providers = schemes
                        .Where(x => x.DisplayName != null)
                        .Select(x => new ViewModel.ExternalProvider
        {
            DisplayName          = x.DisplayName ?? x.Name,
            AuthenticationScheme = x.Name
        }).ToList();

        var dyanmicSchemes = (await _identityProviderStore.GetAllSchemeNamesAsync())
                             .Where(x => x.Enabled)
                             .Select(x => new ViewModel.ExternalProvider
        {
            AuthenticationScheme = x.Scheme,
            DisplayName          = x.DisplayName
        });

        providers.AddRange(dyanmicSchemes);


        var allowLocal = true;

        if (context?.Client.ClientId != null)
        {
            var client = await _clientStore.FindEnabledClientByIdAsync(context.Client.ClientId);

            if (client != null)
            {
                allowLocal = client.EnableLocalLogin;

                if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
                {
                    providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
                }
            }
        }

        View = new ViewModel
        {
            AllowRememberLogin = LoginOptions.AllowRememberLogin,
            EnableLocalLogin   = allowLocal && LoginOptions.AllowLocalLogin,
            ExternalProviders  = providers.ToArray()
        };
    }