public async Task LoginAsync(OpenidConnectPkceSettings openidClientPkceSettings = null)
        {
            try
            {
                openidClientPkceSettings = openidClientPkceSettings ?? globalOpenidClientPkceSettings;

                var nonce        = RandomGenerator.GenerateNonce();
                var codeVerifier = RandomGenerator.Generate(64);

                ValidateResponseMode(openidClientPkceSettings.ResponseMode);
                var loginCallBackUri = new Uri(new Uri(navigationManager.BaseUri), openidClientPkceSettings.LoginCallBackPath).OriginalString;
                var state            = await SaveStateAsync(openidClientPkceSettings, loginCallBackUri, navigationManager.Uri, codeVerifier : codeVerifier, nonce : nonce);

                var authenticationRequest = new AuthenticationRequest
                {
                    ClientId     = openidClientPkceSettings.ClientId,
                    ResponseMode = openidClientPkceSettings.ResponseMode,
                    ResponseType = openidClientPkceSettings.ResponseType,
                    RedirectUri  = loginCallBackUri,
                    Scope        = openidClientPkceSettings.AllScope.ToSpaceList(),
                    Nonce        = nonce,
                    State        = state
                };
                var codeChallengeRequest = new CodeChallengeSecret
                {
                    CodeChallenge       = await codeVerifier.Sha256HashBase64urlEncodedAsync(),
                    CodeChallengeMethod = IdentityConstants.CodeChallengeMethods.S256,
                };

                var requestDictionary = authenticationRequest.ToDictionary().AddToDictionary(codeChallengeRequest);
                if (openidClientPkceSettings.Resources?.Count() > 0)
                {
                    var resourceRequest = new ResourceRequest
                    {
                        Resources = openidClientPkceSettings.Resources
                    };
                    requestDictionary = requestDictionary.AddToDictionary(resourceRequest);
                }

                var oidcDiscovery = await GetOidcDiscoveryAsync(openidClientPkceSettings.OidcDiscoveryUri);

                var authorizationUri = QueryHelpers.AddQueryString(oidcDiscovery.AuthorizationEndpoint, requestDictionary);
                navigationManager.NavigateTo(authorizationUri, true);
            }
            catch (Exception ex)
            {
                throw new SecurityException($"Failed to login, Authority '{openidClientPkceSettings.Authority}'.", ex);
            }
        }
        /// <summary>
        /// Is Valid OAuth 2.0 Code Challenge Secret.
        /// </summary>
        public static void Validate(this CodeChallengeSecret codeChallengeSecret)
        {
            if (codeChallengeSecret == null)
            {
                new ArgumentNullException(nameof(codeChallengeSecret));
            }

            if (codeChallengeSecret.CodeChallenge.IsNullOrEmpty())
            {
                throw new ArgumentNullException(nameof(codeChallengeSecret.CodeChallenge), codeChallengeSecret.GetTypeName());
            }

            codeChallengeSecret.CodeChallenge.ValidateMaxLength(IdentityConstants.MessageLength.CodeChallengeMax, nameof(codeChallengeSecret.CodeChallenge), codeChallengeSecret.GetTypeName());
            codeChallengeSecret.CodeChallengeMethod.ValidateMaxLength(IdentityConstants.MessageLength.CodeChallengeMethodMax, nameof(codeChallengeSecret.CodeChallengeMethod), codeChallengeSecret.GetTypeName());
        }
Esempio n. 3
0
        public async Task <IActionResult> AuthenticationRequestAsync(string partyId)
        {
            logger.ScopeTrace(() => "Up, OIDC Authentication request.");
            var oidcUpSequenceData = await sequenceLogic.GetSequenceDataAsync <OidcUpSequenceData>(remove : false);

            if (!oidcUpSequenceData.UpPartyId.Equals(partyId, StringComparison.Ordinal))
            {
                throw new Exception("Invalid up-party id.");
            }
            logger.SetScopeProperty(Constants.Logs.UpPartyId, oidcUpSequenceData.UpPartyId);

            var party = await tenantRepository.GetAsync <TParty>(oidcUpSequenceData.UpPartyId);

            logger.SetScopeProperty(Constants.Logs.UpPartyClientId, party.Client.ClientId);

            await oidcDiscoveryReadUpLogic.CheckOidcDiscoveryAndUpdatePartyAsync(party);

            var nonce            = RandomGenerator.GenerateNonce();
            var loginCallBackUrl = HttpContext.GetUpPartyUrl(party.Name, Constants.Routes.OAuthController, Constants.Endpoints.AuthorizationResponse, partyBindingPattern: party.PartyBindingPattern);

            oidcUpSequenceData.ClientId    = !party.Client.SpClientId.IsNullOrWhiteSpace() ? party.Client.SpClientId : party.Client.ClientId;
            oidcUpSequenceData.RedirectUri = loginCallBackUrl;
            oidcUpSequenceData.Nonce       = nonce;
            if (party.Client.EnablePkce)
            {
                var codeVerifier = RandomGenerator.Generate(64);
                oidcUpSequenceData.CodeVerifier = codeVerifier;
            }
            await sequenceLogic.SaveSequenceDataAsync(oidcUpSequenceData);

            var authenticationRequest = new AuthenticationRequest
            {
                ClientId     = oidcUpSequenceData.ClientId,
                ResponseMode = party.Client.ResponseMode,
                ResponseType = party.Client.ResponseType,
                RedirectUri  = loginCallBackUrl,
                Nonce        = nonce,
                State        = await sequenceLogic.CreateExternalSequenceIdAsync()
            };

            switch (oidcUpSequenceData.LoginAction)
            {
            case LoginAction.ReadSession:
                authenticationRequest.Prompt = IdentityConstants.AuthorizationServerPrompt.None;
                break;

            case LoginAction.RequireLogin:
                authenticationRequest.Prompt = IdentityConstants.AuthorizationServerPrompt.Login;
                break;

            default:
                break;
            }

            if (oidcUpSequenceData.MaxAge.HasValue)
            {
                authenticationRequest.MaxAge = oidcUpSequenceData.MaxAge;
            }

            if (!oidcUpSequenceData.UserId.IsNullOrEmpty())
            {
                authenticationRequest.LoginHint = oidcUpSequenceData.UserId;
            }

            authenticationRequest.Scope = new[] { IdentityConstants.DefaultOidcScopes.OpenId }.ConcatOnce(party.Client.Scopes).ToSpaceList();

            //TODO add AcrValues
            //authenticationRequest.AcrValues = "urn:federation:authentication:windows";

            logger.ScopeTrace(() => $"Up, Authentication request '{authenticationRequest.ToJsonIndented()}'.", traceType: TraceTypes.Message);
            var nameValueCollection = authenticationRequest.ToDictionary();

            if (party.Client.EnablePkce)
            {
                var codeChallengeRequest = new CodeChallengeSecret
                {
                    CodeChallenge       = await oidcUpSequenceData.CodeVerifier.Sha256HashBase64urlEncodedAsync(),
                    CodeChallengeMethod = IdentityConstants.CodeChallengeMethods.S256,
                };

                logger.ScopeTrace(() => $"Up, CodeChallengeSecret request '{codeChallengeRequest.ToJsonIndented()}'.", traceType: TraceTypes.Message);
                nameValueCollection = nameValueCollection.AddToDictionary(codeChallengeRequest);
            }

            securityHeaderLogic.AddFormActionAllowAll();

            logger.ScopeTrace(() => $"Up, Authentication request URL '{party.Client.AuthorizeUrl}'.");
            logger.ScopeTrace(() => "Up, Sending OIDC Authentication request.", triggerEvent: true);
            return(await nameValueCollection.ToRedirectResultAsync(party.Client.AuthorizeUrl));
        }
Esempio n. 4
0
        private void ValidateAuthenticationRequest(OidcDownClient client, AuthenticationRequest authenticationRequest, CodeChallengeSecret codeChallengeSecret)
        {
            try
            {
                var  responseTypes  = authenticationRequest.ResponseType.ToSpaceList();
                bool isImplicitFlow = !responseTypes.Where(rt => rt.Contains(IdentityConstants.ResponseTypes.Code)).Any();
                authenticationRequest.Validate(isImplicitFlow);

                if (client.RequirePkce)
                {
                    if (responseTypes.Where(rt => !rt.Equals(IdentityConstants.ResponseTypes.Code)).Any())
                    {
                        throw new OAuthRequestException($"Require '{IdentityConstants.ResponseTypes.Code}' flow with PKCE.")
                              {
                                  RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                              };
                    }
                }

                if (!client.RedirectUris.Any(u => u.Equals(authenticationRequest.RedirectUri, StringComparison.InvariantCultureIgnoreCase)))
                {
                    throw new OAuthRequestException($"Invalid redirect Uri '{authenticationRequest.RedirectUri}'.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                          };
                }

                if (!client.ClientId.Equals(authenticationRequest.ClientId, StringComparison.InvariantCultureIgnoreCase))
                {
                    throw new OAuthRequestException($"Invalid client id '{authenticationRequest.ClientId}'.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidClient
                          };
                }

                if (!authenticationRequest.Scope.Contains(IdentityConstants.DefaultOidcScopes.OpenId))
                {
                    throw new OAuthRequestException($"Require '{IdentityConstants.DefaultOidcScopes.OpenId}' scope.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidScope
                          };
                }
                var resourceScopes = oauthResourceScopeDownLogic.GetResourceScopes(client as TClient);
                var invalidScope   = authenticationRequest.Scope.ToSpaceList().Where(s => !(resourceScopes.Select(rs => rs).Contains(s) || (client.Scopes != null && client.Scopes.Select(ps => ps.Scope).Contains(s))) && IdentityConstants.DefaultOidcScopes.OpenId != s);
                if (invalidScope.Count() > 0)
                {
                    throw new OAuthRequestException($"Invalid scope '{authenticationRequest.Scope}'.")
                          {
                              RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidScope
                          };
                }

                ValidateResponseType(client, authenticationRequest, responseTypes);

                if (!authenticationRequest.ResponseMode.IsNullOrEmpty())
                {
                    var invalidResponseMode = !(new[] { IdentityConstants.ResponseModes.Fragment, IdentityConstants.ResponseModes.Query, IdentityConstants.ResponseModes.FormPost }.Contains(authenticationRequest.ResponseMode));
                    if (invalidResponseMode)
                    {
                        throw new OAuthRequestException($"Invalid response mode '{authenticationRequest.ResponseMode}'.")
                              {
                                  RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                              };
                    }
                }

                if (client.RequirePkce)
                {
                    codeChallengeSecret.Validate();
                }
            }
            catch (ArgumentException ex)
            {
                throw new OAuthRequestException(ex.Message, ex)
                      {
                          RouteBinding = RouteBinding, Error = IdentityConstants.ResponseErrors.InvalidRequest
                      };
            }
        }