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