Example #1
0
        public async Task <DeviceAuthorizationResponse> RequestDeviceAuthorizationAsync()
        {
            DiscoveryDocumentResponse disco = await DiscoveryCache.GetAsync();

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

            DeviceAuthorizationResponse response = await AuthHttpClient.RequestDeviceAuthorizationAsync(new DeviceAuthorizationRequest
            {
                Address      = disco.DeviceAuthorizationEndpoint,
                Scope        = Configuration["Scope"],
                ClientId     = Configuration["ClientId"],
                ClientSecret = Configuration["ClientSecret"],
            });

            string           url  = $"{ response.VerificationUri}?userCode={ response.UserCode}";
            ProcessStartInfo proc = new ProcessStartInfo(url)
            {
                UseShellExecute = true
            };

            Process.Start(proc);
            return(response);
        }
        private static async Task <TokenResponse> RequestTokenAsync(DeviceAuthorizationResponse authorizeResponse)
        {
            var client = new HttpClient();

            while (true)
            {
                var response = await client.RequestDeviceTokenAsync(new DeviceTokenRequest
                {
                    Address      = disco.TokenEndpoint,
                    ClientId     = Constants.SampleClientId,
                    ClientSecret = Constants.SampleClientSecret,
                    DeviceCode   = authorizeResponse.DeviceCode
                });

                if (response.IsError)
                {
                    if (response.Error == OidcConstants.TokenErrors.AuthorizationPending || response.Error == OidcConstants.TokenErrors.SlowDown)
                    {
                        Console.WriteLine($"{response.Error}...waiting.");
                        Thread.Sleep(authorizeResponse.Interval * 1000);
                    }
                    else
                    {
                        throw new Exception(response.Error);
                    }
                }
                else
                {
                    return(response);
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="DeviceAuthorizationSuccessEvent"/> class.
 /// </summary>
 /// <param name="response">The response.</param>
 /// <param name="request">The request.</param>
 public DeviceAuthorizationSuccessEvent(DeviceAuthorizationResponse response, DeviceAuthorizationRequestValidationResult request)
     : this()
 {
     ClientId   = request.ValidatedRequest.Client?.ClientId;
     ClientName = request.ValidatedRequest.Client?.ClientName;
     Endpoint   = Constants.EndpointNames.DeviceAuthorization;
     Scopes     = request.ValidatedRequest.ValidatedResources?.RawScopeValues.ToSpaceSeparatedString();
 }
        public void ExecuteDeviceAuthorizationAfterExpiry()
        {
            const string clientId                = "device";
            ITokenClient tokenClient             = null !;
            DeviceAuthorizationResponse response = null !;

            "Given a token client".x(
                () =>
            {
                tokenClient = new TokenClient(
                    TokenCredentials.AsDevice(),
                    _fixture.Client,
                    new Uri(WellKnownOpenidConfiguration));

                Assert.NotNull(tokenClient);
            });

            "When a device requests authorization".x(
                async() =>
            {
                var genericResponse = await tokenClient.GetAuthorization(new DeviceAuthorizationRequest(clientId))
                                      .ConfigureAwait(false) as Option <DeviceAuthorizationResponse> .Result;

                Assert.NotNull(genericResponse);

                response = genericResponse.Item;
            });

            Option <GrantedTokenResponse> expiredPoll = null !;

            "and the device polls the token server after expiry".x(
                async() =>
            {
                expiredPoll = await tokenClient.GetToken(
                    TokenRequest.FromDeviceCode(clientId, response.DeviceCode, 7))
                              .ConfigureAwait(false);
            });

            "then error shows request expiry".x(
                async() =>
            {
                Assert.IsType <Option <GrantedTokenResponse> .Error>(expiredPoll);
                Assert.Equal(
                    ErrorCodes.ExpiredToken,
                    (expiredPoll as Option <GrantedTokenResponse> .Error).Details.Title);
            });
        }
Example #5
0
        private async void OnLoaded(object sender, RoutedEventArgs e)
        {
            var disco = await Cache.GetAsync();

            if (disco.IsError)
            {
                CloseWithError(disco.Error);
                return;
            }

            var client = new HttpClient();

            _authorizationResponse = await client.RequestDeviceAuthorizationAsync(
                new DeviceAuthorizationRequest
            {
                Address  = disco.DeviceAuthorizationEndpoint,
                ClientId = Constants.ClientId
            });

            if (_authorizationResponse.IsError)
            {
                CloseWithError(_authorizationResponse.Error);
                return;
            }

            var hyperlink = new Hyperlink(new Run(_authorizationResponse.VerificationUri));

            hyperlink.Click += (_, __) =>
            {
                Process.Start(
                    new ProcessStartInfo
                {
                    FileName        = _authorizationResponse.VerificationUri,
                    UseShellExecute = true
                });
            };

            UrlTextBlock.Content  = hyperlink;
            UserCodeLabel.Content = _authorizationResponse.UserCode;

            var qrCodeUrl = string.Format(
                Constants.QrCodeUrlFormat, Uri.EscapeUriString(_authorizationResponse.VerificationUri));

            QrCodeImage.Source = new BitmapImage(new Uri(qrCodeUrl));
        }
Example #6
0
        private static async Task <TokenResponse> RequestTokenAsync(DeviceAuthorizationResponse authorizeResponse)
        {
            var disco = await _cache.GetAsync();

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

            using (var httpClient = new HttpClient())
            {
                while (true)
                {
                    using (var deviceTokenRequest = new DeviceTokenRequest())
                    {
                        deviceTokenRequest.Address    = disco.TokenEndpoint;
                        deviceTokenRequest.ClientId   = "device";
                        deviceTokenRequest.DeviceCode = authorizeResponse.DeviceCode;

                        var response = await httpClient.RequestDeviceTokenAsync(deviceTokenRequest);

                        if (response.IsError)
                        {
                            if (response.Error == OidcConstants.TokenErrors.AuthorizationPending || response.Error == OidcConstants.TokenErrors.SlowDown)
                            {
                                WriteLine($"{response.Error}...waiting.");
                                Thread.Sleep(authorizeResponse.Interval * 1000);
                            }
                            else
                            {
                                throw new InvalidOperationException(response.Error);
                            }
                        }
                        else
                        {
                            return(response);
                        }
                    }
                }
            }
        }
        private void LogResponse(DeviceAuthorizationResponse response, DeviceAuthorizationRequestValidationResult requestResult)
        {
            var clientId = $"{requestResult.ValidatedRequest.Client.ClientId} ({requestResult.ValidatedRequest.Client?.ClientName ?? "no name set"})";

            if (response.DeviceCode != null)
            {
                _logger.LogTrace("Device code issued for {clientId}: {deviceCode}", clientId, response.DeviceCode);
            }
            if (response.UserCode != null)
            {
                _logger.LogTrace("User code issued for {clientId}: {userCode}", clientId, response.UserCode);
            }
            if (response.VerificationUri != null)
            {
                _logger.LogTrace("Verification URI issued for {clientId}: {verificationUri}", clientId, response.VerificationUri);
            }
            if (response.VerificationUriComplete != null)
            {
                _logger.LogTrace("Verification URI (Complete) issued for {clientId}: {verificationUriComplete}", clientId, response.VerificationUriComplete);
            }
        }
Example #8
0
        private async Task <TokenResponse> RequestTokenAsync(DeviceAuthorizationResponse authorizeResponse)
        {
            var disco = await _disco.GetAsync();

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

            var client = new HttpClient();

            while (true)
            {
                var response = await client.RequestDeviceTokenAsync(new DeviceTokenRequest
                {
                    Address      = disco.TokenEndpoint,
                    ClientId     = _configuration.GetValue <string>("ClientId"),
                    ClientSecret = _configuration.GetValue <string>("ClientSecret"),
                    DeviceCode   = authorizeResponse.DeviceCode
                });

                if (response.IsError)
                {
                    if (response.Error == OidcConstants.TokenErrors.AuthorizationPending || response.Error == OidcConstants.TokenErrors.SlowDown)
                    {
                        System.Console.WriteLine($"{response.Error}...waiting.");
                        await Task.Delay(authorizeResponse.Interval * 1000);
                    }
                    else
                    {
                        throw new Exception(response.Error);
                    }
                }
                else
                {
                    return(response);
                }
            }
        }
Example #9
0
        private async Task <TokenResponse> RequestTokenAsync(DeviceAuthorizationResponse authorizeResponse)
        {
            var result = await disco.GetAsync();

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

            var client = new HttpClient();

            while (true)
            {
                var response = await client.RequestDeviceTokenAsync(new DeviceTokenRequest
                {
                    Address    = result.TokenEndpoint,
                    ClientId   = "device",
                    DeviceCode = authorizeResponse.DeviceCode
                });

                if (response.IsError)
                {
                    if (response.Error == OidcConstants.TokenErrors.AuthorizationPending ||
                        response.Error == OidcConstants.TokenErrors.SlowDown)
                    {
                        await Task.Delay(authorizeResponse.Interval * 1000);
                    }
                    else
                    {
                        throw new Exception(response.Error);
                    }
                }
                else
                {
                    return(response);
                }
            }
        }
Example #10
0
        public 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"
            });

            if (response.IsError)
            {
                throw new Exception(response.Error);
            }
            DeviceAuthorizationResponse = response;
            return(response);
        }
Example #11
0
 public DeviceAuthorizationResult(DeviceAuthorizationResponse response)
 {
     Response = response ?? throw new ArgumentNullException(nameof(response));
 }
    /// <summary>
    /// Processes the response.
    /// </summary>
    /// <param name="validationResult">The validation result.</param>
    /// <param name="baseUrl">The base URL.</param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException">validationResult or Client</exception>
    /// <exception cref="ArgumentException">Value cannot be null or whitespace. - baseUrl</exception>
    public virtual async Task <DeviceAuthorizationResponse> ProcessAsync(DeviceAuthorizationRequestValidationResult validationResult, string baseUrl)
    {
        using var activity = Tracing.BasicActivitySource.StartActivity("DeviceAuthorizationResponseGenerator.Process");

        if (validationResult == null)
        {
            throw new ArgumentNullException(nameof(validationResult));
        }
        if (validationResult.ValidatedRequest.Client == null)
        {
            throw new ArgumentNullException(nameof(validationResult.ValidatedRequest.Client));
        }
        if (string.IsNullOrWhiteSpace(baseUrl))
        {
            throw new ArgumentException("Value cannot be null or whitespace.", nameof(baseUrl));
        }

        Logger.LogTrace("Creating response for device authorization request");

        var response = new DeviceAuthorizationResponse();

        // generate user_code
        var userCodeGenerator = await UserCodeService.GetGenerator(
            validationResult.ValidatedRequest.Client.UserCodeType ??
            Options.DeviceFlow.DefaultUserCodeType);

        var retryCount = 0;

        while (retryCount < userCodeGenerator.RetryLimit)
        {
            var userCode = await userCodeGenerator.GenerateAsync();

            var deviceCode = await DeviceFlowCodeService.FindByUserCodeAsync(userCode);

            if (deviceCode == null)
            {
                response.UserCode = userCode;
                break;
            }

            retryCount++;
        }

        if (response.UserCode == null)
        {
            throw new InvalidOperationException("Unable to create unique device flow user code");
        }

        // generate verification URIs
        response.VerificationUri = Options.UserInteraction.DeviceVerificationUrl;
        if (response.VerificationUri.IsLocalUrl())
        {
            // if url is relative, parse absolute URL
            response.VerificationUri = baseUrl.RemoveTrailingSlash() + Options.UserInteraction.DeviceVerificationUrl;
        }

        if (!string.IsNullOrWhiteSpace(Options.UserInteraction.DeviceVerificationUserCodeParameter))
        {
            response.VerificationUriComplete =
                $"{response.VerificationUri}?{Options.UserInteraction.DeviceVerificationUserCodeParameter}={response.UserCode}";
        }

        // expiration
        response.DeviceCodeLifetime = validationResult.ValidatedRequest.Client.DeviceCodeLifetime;

        // interval
        response.Interval = Options.DeviceFlow.Interval;

        // store device request (device code & user code)
        response.DeviceCode = await DeviceFlowCodeService.StoreDeviceAuthorizationAsync(response.UserCode, new DeviceCode
        {
            Description     = validationResult.ValidatedRequest.Description,
            ClientId        = validationResult.ValidatedRequest.Client.ClientId,
            IsOpenId        = validationResult.ValidatedRequest.IsOpenIdRequest,
            Lifetime        = response.DeviceCodeLifetime,
            CreationTime    = Clock.UtcNow.UtcDateTime,
            RequestedScopes = validationResult.ValidatedRequest.ValidatedResources.RawScopeValues
        });

        return(response);
    }
        public void ExecuteDeviceAuthorizationFlowWithUserApproval()
        {
            const string clientId    = "device";
            ITokenClient tokenClient = null !;
            DeviceAuthorizationResponse           response    = null !;
            GrantedTokenResponse                  token       = null !;
            Task <Option <GrantedTokenResponse> > pollingTask = null !;

            "Given a token client".x(
                () =>
            {
                tokenClient = new TokenClient(
                    TokenCredentials.AsDevice(),
                    _fixture.Client,
                    new Uri(WellKnownOpenidConfiguration));

                Assert.NotNull(tokenClient);
            });

            "and an access token".x(
                async() =>
            {
                var authClient = new TokenClient(
                    TokenCredentials.FromClientCredentials(clientId, "client"),
                    _fixture.Client,
                    new Uri(WellKnownOpenidConfiguration));
                var tokenResponse = await authClient.GetToken(
                    TokenRequest.FromPassword("user", "password", new[] { "openid" }))
                                    .ConfigureAwait(false);

                Assert.IsType <Option <GrantedTokenResponse> .Result>(tokenResponse);

                token = (tokenResponse as Option <GrantedTokenResponse> .Result).Item;
            });

            "When a device requests authorization".x(
                async() =>
            {
                var genericResponse = await tokenClient.GetAuthorization(new DeviceAuthorizationRequest(clientId))
                                      .ConfigureAwait(false);

                Assert.IsType <Option <DeviceAuthorizationResponse> .Result>(genericResponse);

                response = (genericResponse as Option <DeviceAuthorizationResponse> .Result).Item;
            });

            "and the device polls the token server".x(
                async() =>
            {
                pollingTask = tokenClient.GetToken(
                    TokenRequest.FromDeviceCode(clientId, response.DeviceCode, response.Interval));

                Assert.False(pollingTask.IsCompleted);
            });

            "and user successfully posts user code".x(
                async() =>
            {
                var client = _fixture.Client();
                var msg    = new HttpRequestMessage
                {
                    Method     = HttpMethod.Post,
                    RequestUri = new Uri(response.VerificationUri),
                    Content    = new FormUrlEncodedContent(
                        new[] { new KeyValuePair <string, string>("code", response.UserCode) })
                };
                msg.Headers.Authorization = new AuthenticationHeaderValue(token.TokenType, token.AccessToken);

                var approval = await client.SendAsync(msg).ConfigureAwait(false);

                Assert.Equal(HttpStatusCode.OK, approval.StatusCode);
            });

            "then token is returned from polling".x(
                async() =>
            {
                var tokenResponse = await pollingTask.ConfigureAwait(false);

                Assert.IsType <Option <GrantedTokenResponse> .Result>(tokenResponse);
            });
        }