예제 #1
0
        static async Task <DeviceAuthorizationResponse> RequestAuthorizationAsync()
        {
            var disco = await _cache.GetAsync();

            if (disco.IsError)
            {
                throw new Exception(disco.Error);
            }

            var client   = new HttpClient();
            var response = await client.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest
            {
                Address  = disco.DeviceAuthorizationEndpoint,
                ClientId = "device",
                ClientCredentialStyle = ClientCredentialStyle.PostBody
            });

            if (response.IsError)
            {
                throw new Exception(response.Error);
            }

            Console.WriteLine($"user code   : {response.UserCode}");
            Console.WriteLine($"device code : {response.DeviceCode}");
            Console.WriteLine($"URL         : {response.VerificationUri}");
            Console.WriteLine($"Complete URL: {response.VerificationUriComplete}");

            Console.WriteLine($"\nPress enter to launch browser ({response.VerificationUri})");
            Console.ReadLine();

            Process.Start(new ProcessStartInfo(response.VerificationUriComplete)
            {
                UseShellExecute = true
            });
            return(response);
        }
예제 #2
0
        public async Task InvokeAsync(HttpContext context)
        {
            string oldAccessToken = await context.GetTokenAsync(OpenIdConnectParameterNames.AccessToken);

            if (!string.IsNullOrEmpty(oldAccessToken))
            {
                JwtSecurityToken tokenInfo = new JwtSecurityToken(oldAccessToken);

                // Renew access token if pass halfway of its lifetime
                if (tokenInfo.ValidFrom + (tokenInfo.ValidTo - tokenInfo.ValidFrom) / 2 < DateTime.UtcNow)
                {
                    var disco = await _discoveryCache.GetAsync();

                    TokenClient tokenClient     = new TokenClient(disco.TokenEndpoint, _clientId, _clientSecret);
                    string      oldRefreshToken = await context.GetTokenAsync(OpenIdConnectParameterNames.RefreshToken);

                    TokenResponse tokenResult = await tokenClient.RequestRefreshTokenAsync(oldRefreshToken);

                    if (!tokenResult.IsError)
                    {
                        string idToken = await context.GetTokenAsync(OpenIdConnectParameterNames.IdToken);

                        string newAccessToken  = tokenResult.AccessToken;
                        string newRefreshToken = tokenResult.RefreshToken;

                        var tokens = new List <AuthenticationToken>
                        {
                            new AuthenticationToken {
                                Name = OpenIdConnectParameterNames.IdToken, Value = idToken
                            },
                            new AuthenticationToken {
                                Name = OpenIdConnectParameterNames.AccessToken, Value = newAccessToken
                            },
                            new AuthenticationToken {
                                Name = OpenIdConnectParameterNames.RefreshToken, Value = newRefreshToken
                            }
                        };

                        AuthenticateResult info = await context.AuthenticateAsync(_cookieSchemeName);

                        info.Properties.StoreTokens(tokens);
                        await context.SignInAsync(_cookieSchemeName, info.Principal, info.Properties);
                    }
                }
            }

            await _next.Invoke(context);
        }
예제 #3
0
        /// <inheritdoc />
        public async Task <TokenRefreshResult> TryRefreshTokenIfRequiredAsync(
            string refreshToken,
            string expiresAt,
            CancellationToken ct)
        {
            //检查我们是否有刷新令牌,如果没有,则失败。
            if (string.IsNullOrWhiteSpace(refreshToken))
            {
                return(TokenRefreshResult.Failed());
            }

            //检查令牌的到期日期是否低于阈值,如果不是,我们可以NoRefreshNeeded立即返回。
            if (!DateTime.TryParse(expiresAt, out var expiresAtDate) || expiresAtDate >= GetRefreshThreshold())
            {
                return(TokenRefreshResult.NoRefreshNeeded());
            }

            //使用提取提供商信息_discoveryCache。
            var discovered = await _discoveryCache.GetAsync();

            /*
             * RequestRefreshTokenAsync是IdentityModelNuGet包的扩展方法,可简化刷新令牌请求的创建
             */
            var tokenResult = await _httpClient.RequestRefreshTokenAsync(
                new RefreshTokenRequest
            {
                Address      = discovered.TokenEndpoint,
                ClientId     = "5440496238",
                ClientSecret = "saQR67zTYy",
                RefreshToken = refreshToken
            }, ct);

            ////如果令牌刷新成功,则返回成功并提供所需的信息,否则返回失败。
            if (tokenResult.IsError)
            {
                _logger.LogDebug(
                    "Unable to refresh token, reason: {refreshTokenErrorDescription}",
                    tokenResult.ErrorDescription);
                return(TokenRefreshResult.Failed());
            }

            //如果令牌刷新成功,则返回成功并提供所需的信息
            var newAccessToken  = tokenResult.AccessToken;
            var newRefreshToken = tokenResult.RefreshToken;
            var newExpiresAt    = CalculateNewExpiresAt(tokenResult.ExpiresIn);

            return(TokenRefreshResult.Success(newAccessToken, newRefreshToken, newExpiresAt));
        }
예제 #4
0
        private static async Task DeviceAuthorizationRequest()
        {
            var discoDoc = await discoCache.GetAsync();

            if (discoDoc.IsError)
            {
                throw new Exception("Unable to load discovery document");
            }

            var httpClient = new HttpClient();
            var response   = await httpClient.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest
            {
                Address  = discoDoc.DeviceAuthorizationEndpoint,
                ClientId = "device_console"
            });
        }
        private async Task <ActionResult> RedirectToExternalProvider(string query)
        {
            var discoveryResponse = await _discoveryCache.GetAsync();

            if (discoveryResponse.IsError)
            {
                _discoveryCache.Refresh();
                throw new Exception(discoveryResponse.Error);
            }

            var externalAuthorizeUrl = $"{discoveryResponse.AuthorizeEndpoint}{query}";

            _log.Info(
                $"Redirect URI substitued, trying to proxy to external provider on {externalAuthorizeUrl}");

            return(Redirect(externalAuthorizeUrl));
        }
예제 #6
0
        public async Task <IActionResult> Login([FromRoute] string platform, [FromQuery] string returnUrl)
        {
            string clientId;
            string signinCallback;

            switch (platform)
            {
            case "android":
                clientId       = _ironcladSettings.AndroidClient.ClientId;
                signinCallback = Url.AbsoluteAction("SigninCallbackAndroid", "Callback");
                break;

            case "ios":
                clientId       = _ironcladSettings.IosClient.ClientId;
                signinCallback = Url.AbsoluteAction("SigninCallbackIos", "Callback");
                break;

            default:
                return(BadRequest());
            }

            var discoveryResponse = await _discoveryCache.GetAsync();

            if (discoveryResponse.IsError)
            {
                _discoveryCache.Refresh();
                throw new Exception(discoveryResponse.Error);
            }


            var authorizeRequest = new Dictionary <string, string>
            {
                { OidcConstants.AuthorizeRequest.ClientId, clientId },
                { OidcConstants.AuthorizeRequest.RedirectUri, signinCallback },
                { OidcConstants.AuthorizeRequest.Scope, "profile openid email lykke offline_access" },
                { OidcConstants.AuthorizeRequest.ResponseType, OidcConstants.ResponseTypes.Code },
                { OidcConstants.AuthorizeRequest.Nonce, "mn4vcynp2tOEj7W9m88l" },
                { OidcConstants.AuthorizeRequest.State, "ttoY604BgSsliwgcnIt8" }
            };

            var query = QueryString.Create(authorizeRequest);

            var externalAuthorizeUrl = $"{discoveryResponse.AuthorizeEndpoint}{query.ToUriComponent()}";

            return(Redirect(externalAuthorizeUrl));
        }
        public async Task <IActionResult> RenewTokens()
        {
            var disco = await _discoveryCache.GetAsync();

            if (disco.IsError)
            {
                throw new Exception(disco.Error);
            }

            var rt = await HttpContext.GetTokenAsync("refresh_token");

            var tokenClient = _httpClientFactory.CreateClient();

            var tokenResult = await tokenClient.RequestRefreshTokenAsync(new RefreshTokenRequest
            {
                Address = disco.TokenEndpoint,

                ClientId     = "mvc.code",
                ClientSecret = "secret",
                RefreshToken = rt
            });

            if (!tokenResult.IsError)
            {
                var oldIdToken = await HttpContext.GetTokenAsync("id_token");

                var newAccessToken  = tokenResult.AccessToken;
                var newRefreshToken = tokenResult.RefreshToken;
                var expiresAt       = DateTime.UtcNow + TimeSpan.FromSeconds(tokenResult.ExpiresIn);

                var info = await HttpContext.AuthenticateAsync("Cookies");

                info.Properties.UpdateTokenValue("refresh_token", newRefreshToken);
                info.Properties.UpdateTokenValue("access_token", newAccessToken);
                info.Properties.UpdateTokenValue("expires_at", expiresAt.ToString("o", CultureInfo.InvariantCulture));

                await HttpContext.SignInAsync("Cookies", info.Principal, info.Properties);

                return(Redirect("~/Home/Secure"));
            }

            ViewData["Error"] = tokenResult.Error;
            return(View("Error"));
        }
예제 #8
0
        /// <inheritdoc />
        public async Task <TokenRefreshResult> TryRefreshTokenIfRequiredAsync(
            string refreshToken,
            string expiresAt,
            CancellationToken ct)
        {
            if (string.IsNullOrWhiteSpace(refreshToken))
            {
                return(TokenRefreshResult.Failed());
            }

            if (!DateTime.TryParse(expiresAt, out var expiresAtDate) || expiresAtDate >= GetRefreshThreshold())
            {
                return(TokenRefreshResult.NoRefreshNeeded());
            }

            var discovered = await _discoveryCache.GetAsync();

            var tokenResult = await _httpClient.RequestRefreshTokenAsync(
                new RefreshTokenRequest
            {
                Address      = discovered.TokenEndpoint,
                ClientId     = "WebFrontend",
                ClientSecret = "secret",
                RefreshToken = refreshToken
            }, ct);

            if (tokenResult.IsError)
            {
                _logger.LogDebug(
                    "Unable to refresh token, reason: {refreshTokenErrorDescription}",
                    tokenResult.ErrorDescription);
                return(TokenRefreshResult.Failed());
            }

            var newAccessToken  = tokenResult.AccessToken;
            var newRefreshToken = tokenResult.RefreshToken;
            var newExpiresAt    = CalculateNewExpiresAt(tokenResult.ExpiresIn);

            return(TokenRefreshResult.Success(newAccessToken, newRefreshToken, newExpiresAt));
        }
        private async Task VerifyAndCacheToken(JwtSecurityToken jwt)
        {
            var discovery = await discoveryCache.GetAsync();

            if (discovery.IsError)
            {
                throw new Exception("Unauthorized (authority discovery failed)");
            }

            var client = httpClientFactory.CreateClient();

            // this user/pass combo is specific to the IdentityServer demo authority,
            // and the use of scope as the username is generally specific to IdentityServer
            client.SetBasicAuthenticationOAuth("api", "secret");

            var tokenResponse = await client.IntrospectTokenAsync(
                new TokenIntrospectionRequest
            {
                Address      = discovery.IntrospectionEndpoint,
                ClientId     = "interactive.confidential",
                ClientSecret = "secret",
                Token        = jwt.RawData
            });

            if (tokenResponse.IsError)
            {
                throw new Exception($"Unauthorized (introspection error: {tokenResponse.Error})");
            }

            if (!tokenResponse.IsActive)
            {
                throw new Exception("Unauthorized (token deactivated by authority)");
            }

            var key = GetCacheKey(jwt);

            memoryCache.Set(key, jwt.RawData);
        }
예제 #10
0
        public async Task <TokenResponse> RefreshAccessTokenAsync()
        {
            var document = await _discoveryCache.GetAsync();

            var tokenClient = _httpClientFactory.CreateClient("tokenClient");

            var tokenResonse = await tokenClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
            {
                Address      = document.TokenEndpoint,
                ClientId     = _tenant.Credentials.ClientId,
                ClientSecret = _tenant.Credentials.ClientSecret,
            });

            lock (_accessLock)
            {
                CurrentTokenRecord = new TokenRecord
                {
                    TokenResponse    = tokenResonse,
                    ClientCredential = _tenant.Credentials,
                    Expiration       = DateTime.UtcNow.AddSeconds(tokenResonse.ExpiresIn - 300) // give a 5 minute skew.
                };
                return(tokenResonse);
            }
        }
예제 #11
0
        static async Task <BackchannelAuthenticationResponse> RequestBackchannelLoginAsync()
        {
            var disco = await _cache.GetAsync();

            if (disco.IsError)
            {
                throw new Exception(disco.Error);
            }

            var cibaEp = disco.BackchannelAuthenticationEndpoint;

            var username       = "******";
            var bindingMessage = Guid.NewGuid().ToString("N").Substring(0, 10);

            var req = new BackchannelAuthenticationRequest()
            {
                Address      = cibaEp,
                ClientId     = "ciba",
                ClientSecret = "secret",
                Scope        = "openid profile email resource1.scope1 offline_access",
                LoginHint    = username,
                //IdTokenHint = "eyJhbGciOiJSUzI1NiIsImtpZCI6IkYyNjZCQzA3NTFBNjIyNDkzMzFDMzI4QUQ1RkIwMkJGIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo1MDAxIiwibmJmIjoxNjM4NDc3MDE2LCJpYXQiOjE2Mzg0NzcwMTYsImV4cCI6MTYzODQ3NzMxNiwiYXVkIjoiY2liYSIsImFtciI6WyJwd2QiXSwiYXRfaGFzaCI6ImE1angwelVQZ2twczBVS1J5VjBUWmciLCJzaWQiOiIzQTJDQTJDNjdBNTAwQ0I2REY1QzEyRUZDMzlCQTI2MiIsInN1YiI6IjgxODcyNyIsImF1dGhfdGltZSI6MTYzODQ3NzAwOCwiaWRwIjoibG9jYWwifQ.GAIHXYgEtXw5NasR0zPMW3jSKBuWujzwwnXJnfHdulKX-I3r47N0iqHm5v5V0xfLYdrmntjLgmdm0DSvdXswtZ1dh96DqS1zVm6yQ2V0zsA2u8uOt1RG8qtjd5z4Gb_wTvks4rbUiwi008FOZfRuqbMJJDSscy_YdEJqyQahdzkcUnWZwdbY8L2RUTxlAAWQxktpIbaFnxfr8PFQpyTcyQyw0b7xmYd9ogR7JyOff7IJIHPDur0wbRdpI1FDE_VVCgoze8GVAbVxXPtj4CtWHAv07MJxa9SdA_N-lBcrZ3PHTKQ5t1gFXwdQvp3togUJl33mJSru3lqfK36pn8y8ow",
                BindingMessage  = bindingMessage,
                RequestedExpiry = 200
            };

            bool useRequestObject = false;

            if (useRequestObject)
            {
                req = new BackchannelAuthenticationRequest
                {
                    Address       = req.Address,
                    ClientId      = req.ClientId,
                    ClientSecret  = req.ClientSecret,
                    RequestObject = CreateRequestObject(new Dictionary <string, string>
                    {
                        { OidcConstants.BackchannelAuthenticationRequest.Scope, req.Scope },
                        { OidcConstants.BackchannelAuthenticationRequest.LoginHint, req.LoginHint },
                        { OidcConstants.BackchannelAuthenticationRequest.IdTokenHint, req.IdTokenHint },
                        { OidcConstants.BackchannelAuthenticationRequest.BindingMessage, req.BindingMessage },
                    }),
                };
            }

            var client   = new HttpClient();
            var response = await client.RequestBackchannelAuthenticationAsync(req);

            if (response.IsError)
            {
                throw new Exception(response.Error);
            }

            Console.WriteLine($"Login Hint                  : {username}");
            Console.WriteLine($"Binding Message             : {bindingMessage}");
            Console.WriteLine($"Authentication Request Id   : {response.AuthenticationRequestId}");
            Console.WriteLine($"Expires In                  : {response.ExpiresIn}");
            Console.WriteLine($"Interval                    : {response.Interval}");
            Console.WriteLine();

            Console.WriteLine($"\nPress enter to start polling the token endpoint.");
            Console.ReadLine();

            return(response);
        }
예제 #12
0
 public async Task <DiscoveryResponse> GetDiscoveryDocumentAsync(DiscoveryDocumentRequest?request = null, CancellationToken cancellationToken = default)
 {
     return(await _discoveryCache.GetAsync().ConfigureAwait(false));
 }