예제 #1
0
        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()
            });
        }
예제 #2
0
 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));
        }
예제 #4
0
        private async Task <bool> ValidateReturnUrlAsync(string returnUrl)
        {
            IdentityServer4.Models.AuthorizationRequest context = await interaction.GetAuthorizationContextAsync(returnUrl);

            return(context != null && interaction.IsValidReturnUrl(returnUrl));
        }