示例#1
0
        private async Task <string> SaveStateAsync(string oidcDiscoveryUri, string clientId, string callBackUri, string redirectUri, string codeVerifier = null, string nonce = null)
        {
            var state = RandomGenerator.GenerateNonce(32);
            var openidClientPkceState = new OpenidConnectPkceState
            {
                OidcDiscoveryUri = oidcDiscoveryUri,
                ClientId         = clientId,
                CallBackUri      = callBackUri,
                RedirectUri      = redirectUri,
                CodeVerifier     = codeVerifier,
                Nonce            = nonce
            };
            await sessionStorage.SetItemAsync(state, openidClientPkceState);

            return(state);
        }
        private async Task <(ClaimsPrincipal idTokenPrincipal, TokenResponse tokenResponse)> AcquireTokensAsync(OpenidConnectPkceState openidClientPkceState, string code)
        {
            var tokenRequest = new TokenRequest
            {
                GrantType   = IdentityConstants.GrantTypes.AuthorizationCode,
                Code        = code,
                ClientId    = openidClientPkceState.ClientId,
                RedirectUri = openidClientPkceState.CallBackUri,
            };

            var codeVerifierSecret = new CodeVerifierSecret
            {
                CodeVerifier = openidClientPkceState.CodeVerifier,
            };

            var oidcDiscovery = await GetOidcDiscoveryAsync(openidClientPkceState.OidcDiscoveryUri);

            var requestDictionary = tokenRequest.ToDictionary().AddToDictionary(codeVerifierSecret);

            if (openidClientPkceState.Resources?.Count() > 0)
            {
                var resourceRequest = new ResourceRequest
                {
                    Resources = openidClientPkceState.Resources
                };
                requestDictionary = requestDictionary.AddToDictionary(resourceRequest);
            }

            var request = new HttpRequestMessage(HttpMethod.Post, oidcDiscovery.TokenEndpoint);

            request.Content = new FormUrlEncodedContent(requestDictionary);

            var response = await GetHttpClient().SendAsync(request);

            switch (response.StatusCode)
            {
            case HttpStatusCode.OK:
                var result = await response.Content.ReadAsStringAsync();

                var tokenResponse = result.ToObject <TokenResponse>();
                tokenResponse.Validate(true);
                if (tokenResponse.AccessToken.IsNullOrEmpty())
                {
                    throw new ArgumentNullException(nameof(tokenResponse.AccessToken), tokenResponse.GetTypeName());
                }
                if (tokenResponse.ExpiresIn <= 0)
                {
                    throw new ArgumentNullException(nameof(tokenResponse.ExpiresIn), tokenResponse.GetTypeName());
                }

                // .NET 5.0 error, System.Security.Cryptography.RSA.Create() - System.PlatformNotSupportedException: System.Security.Cryptography.Algorithms is not supported on this platform.
                // https://github.com/dotnet/aspnetcore/issues/26123
                // https://github.com/dotnet/runtime/issues/40074
                // .NET 7
                // https://github.com/dotnet/designs/blob/main/accepted/2021/blazor-wasm-crypto.md#net-7-plan
#if !NET50 && !NET60
                var oidcDiscoveryKeySet = await GetOidcDiscoveryKeysAsync(openidClientPkceState.OidcDiscoveryUri);

                (var idTokenPrincipal, _) = JwtHandler.ValidateToken(tokenResponse.IdToken, oidcDiscovery.Issuer, oidcDiscoveryKeySet.Keys.ToMSJsonWebKeys(), openidClientPkceState.ClientId,
                                                                     nameClaimType: globalOpenidClientPkceSettings.NameClaimType, roleClaimType: globalOpenidClientPkceSettings.RoleClaimType);
#else
                var idTokenPrincipal = JwtHandler.ReadTokenClaims(tokenResponse.IdToken);
#endif

                var nonce = idTokenPrincipal.Claims.Where(c => c.Type == JwtClaimTypes.Nonce).Select(c => c.Value).FirstOrDefault();
                if (!openidClientPkceState.Nonce.Equals(nonce, StringComparison.Ordinal))
                {
                    throw new SecurityException("Nonce do not match.");
                }

                return(idTokenPrincipal, tokenResponse);

            case HttpStatusCode.BadRequest:
                var resultBadRequest = await response.Content.ReadAsStringAsync();

                var tokenResponseBadRequest = resultBadRequest.ToObject <TokenResponse>();
                tokenResponseBadRequest.Validate(true);
                throw new Exception($"Error login call back, Bad request. StatusCode={response.StatusCode}");

            default:
                throw new Exception($"Error login call back, Status Code not expected. StatusCode={response.StatusCode}");
            }
        }
示例#3
0
        private async Task <(int, ClaimsPrincipal, string, string)> AcquireTokensAsync(OpenidConnectPkceState openidClientPkceState, string code)
        {
            var tokenRequest = new TokenRequest
            {
                GrantType   = IdentityConstants.GrantTypes.AuthorizationCode,
                Code        = code,
                ClientId    = openidClientPkceState.ClientId,
                RedirectUri = openidClientPkceState.CallBackUri,
            };

            var codeVerifierSecret = new CodeVerifierSecret
            {
                CodeVerifier = openidClientPkceState.CodeVerifier,
            };

            var oidcDiscovery = await GetOidcDiscoveryAsync(openidClientPkceState.OidcDiscoveryUri);

            var request = new HttpRequestMessage(HttpMethod.Post, oidcDiscovery.TokenEndpoint);

            request.Content = new FormUrlEncodedContent(tokenRequest.ToDictionary().AddToDictionary(codeVerifierSecret));

            var httpClient = serviceProvider.GetService <HttpClient>();
            var response   = await httpClient.SendAsync(request);

            switch (response.StatusCode)
            {
            case HttpStatusCode.OK:
                var result = await response.Content.ReadAsStringAsync();

                var tokenResponse = result.ToObject <TokenResponse>();
                tokenResponse.Validate(true);
                if (tokenResponse.AccessToken.IsNullOrEmpty())
                {
                    throw new ArgumentNullException(nameof(tokenResponse.AccessToken), tokenResponse.GetTypeName());
                }
                if (tokenResponse.ExpiresIn <= 0)
                {
                    throw new ArgumentNullException(nameof(tokenResponse.ExpiresIn), tokenResponse.GetTypeName());
                }

                var oidcDiscoveryKeySet = await GetOidcDiscoveryKeysAsync(openidClientPkceState.OidcDiscoveryUri);

                (var idTokenPrincipal, _) = JwtHandler.ValidateToken(tokenResponse.IdToken, oidcDiscovery.Issuer, oidcDiscoveryKeySet.Keys, openidClientPkceState.ClientId, nameClaimType: globalOpenidClientPkceSettings.NameClaimType, roleClaimType: globalOpenidClientPkceSettings.RoleClaimType);

                var nonce = idTokenPrincipal.Claims.Where(c => c.Type == JwtClaimTypes.Nonce).Select(c => c.Value).SingleOrDefault();
                if (!openidClientPkceState.Nonce.Equals(nonce, StringComparison.Ordinal))
                {
                    throw new SecurityException("Nonce do not match.");
                }

                return(tokenResponse.ExpiresIn, idTokenPrincipal, tokenResponse.IdToken, tokenResponse.AccessToken);

            case HttpStatusCode.BadRequest:
                var resultBadRequest = await response.Content.ReadAsStringAsync();

                var tokenResponseBadRequest = resultBadRequest.ToObject <TokenResponse>();
                tokenResponseBadRequest.Validate(true);
                throw new Exception($"Error login call back, Bad request. StatusCode={response.StatusCode}");

            default:
                throw new Exception($"Error login call back, Status Code not expected. StatusCode={response.StatusCode}");
            }
        }
示例#4
0
 public Task <OidcUserSession> CreateSessionAsync(DateTimeOffset validUntil, ClaimsPrincipal claimsPrincipal, TokenResponse tokenResponse, string sessionState, OpenidConnectPkceState openidClientPkceState)
 {
     return(CreateUpdateSessionAsync(validUntil, claimsPrincipal, tokenResponse, sessionState, openidClientPkceState.OidcDiscoveryUri, openidClientPkceState.ClientId));
 }