public async Task <LoginModel> BuildLoginViewModelAsync(string returnUrl) { IdentityServer4.Models.AuthorizationRequest context = await this._interaction.GetAuthorizationContextAsync(returnUrl); if (context?.IdP != null) { // this is meant to short circuit the UI and only trigger the one external IdP return(new LoginModel { EnableLocalLogin = false, ReturnUrl = returnUrl, Email = context?.LoginHint, ExternalProviders = new ExternalProvider[] { new ExternalProvider { AuthenticationScheme = context.IdP } } }); } System.Collections.Generic.IEnumerable <AuthenticationScheme> schemes = await this._schemeProvider.GetAllSchemesAsync(); System.Collections.Generic.List <ExternalProvider> providers = schemes .Where(x => x.DisplayName != null || (AccountOptions.WindowsAuthenticationEnabled && x.Name.Equals(AccountOptions.WindowsAuthenticationSchemeName, StringComparison.OrdinalIgnoreCase)) ) .Select(x => new ExternalProvider { DisplayName = x.DisplayName, AuthenticationScheme = x.Name }).ToList(); bool allowLocal = true; if (context?.ClientId != null) { IdentityServer4.Models.Client client = await this._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 LoginModel { AllowRememberLogin = AccountOptions.AllowRememberLogin, EnableLocalLogin = allowLocal && AccountOptions.AllowLocalLogin, ReturnUrl = returnUrl, Email = context?.LoginHint, ExternalProviders = providers.ToArray() }); }
public bool IsNativeClient(IdentityServer4.Models.AuthorizationRequest context) { return(!context.RedirectUri.StartsWith("https", StringComparison.Ordinal) && !context.RedirectUri.StartsWith("http", StringComparison.Ordinal)); }
public async Task <IActionResult> Callback() { // read external identity from the temporary cookie AuthenticateResult result = await this.HttpContext.AuthenticateAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme); if (result?.Succeeded != true) { throw new Exception("External authentication error"); } if (_logger.IsEnabled(LogLevel.Debug)) { IEnumerable <string> externalClaims = result.Principal.Claims.Select(c => $"{c.Type}: {c.Value}"); _logger.LogDebug("External claims: {@claims}", externalClaims); } // lookup our user and external provider info //var (user, provider, providerUserId, claims) = FindUserFromExternalProvider(result); ClaimsPrincipal externalUser = result.Principal; // try to determine the unique id of the external user (issued by the provider) // the most common claim type for that are the sub claim and the NameIdentifier // depending on the external provider, some other claim type might be used Claim userEmailClaim = externalUser.FindFirst(JwtClaimTypes.Email) ?? externalUser.FindFirst(ClaimTypes.Email) ?? throw new Exception("Unknown userid"); string name = externalUser.FindFirst(JwtClaimTypes.Name)?.Value ?? externalUser.FindFirst(ClaimTypes.Name)?.Value ?? "unknown"; // lookup our user and external provider info (User user, string provider, string providerUserId, IEnumerable <Claim> claims) = this.FindUserFromExternalProvider(result); if (user == null) { // this might be where you might initiate a custom workflow for user registration // in this sample we don't show how that would be done, as our sample implementation // simply auto-provisions new external user user = AutoProvisionUser(provider, providerUserId, userEmailClaim.Value, name, claims); } // this allows us to collect any additonal claims or properties // for the specific prtotocols used and store them in the local auth cookie. // this is typically used to store data needed for signout from those protocols. List <Claim> additionalLocalClaims = new List <Claim>(); AuthenticationProperties localSignInProps = new AuthenticationProperties(); ProcessLoginCallbackForOidc(result, additionalLocalClaims, localSignInProps); ProcessLoginCallbackForWsFed(result, additionalLocalClaims, localSignInProps); ProcessLoginCallbackForSaml2p(result, additionalLocalClaims, localSignInProps); // issue authentication cookie for user await HttpContext.SignInAsync(user.UserId.ToString(), user.Email, provider, localSignInProps, additionalLocalClaims.ToArray()); // delete temporary cookie used during external authentication await HttpContext.SignOutAsync(IdentityServer4.IdentityServerConstants.ExternalCookieAuthenticationScheme); // retrieve return URL string returnUrl = result.Properties.Items["returnUrl"] ?? "~/"; // check if external login is in the context of an OIDC request IdentityServer4.Models.AuthorizationRequest context = await this._interaction.GetAuthorizationContextAsync(returnUrl); await _events.RaiseAsync(new UserLoginSuccessEvent(provider, providerUserId, user.UserId.ToString(), user.Email, true, context?.ClientId)); if (context != null) { if (await _clientStore.IsPkceClientAsync(context.ClientId)) { // if the client is PKCE then we assume it's native, so this change in how to // return the response is for better UX for the end user. return(View("Redirect", new RedirectViewModel { RedirectUrl = returnUrl })); } } return(Redirect(returnUrl)); }
private async Task <bool> ValidateReturnUrlAsync(string returnUrl) { IdentityServer4.Models.AuthorizationRequest context = await interaction.GetAuthorizationContextAsync(returnUrl); return(context != null && interaction.IsValidReturnUrl(returnUrl)); }