Пример #1
0
    public async Task UpdateByDeviceCodeAsync()
    {
        var deviceCode = await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1");

        deviceCode.ShouldNotBeNull();
        deviceCode.Lifetime.ShouldBe(42);

        await _deviceFlowStore.UpdateByUserCodeAsync(
            "DeviceFlowCodesUserCode1",
            new DeviceCode
        {
            Lifetime = 43
        }
            );

        deviceCode = await _deviceFlowStore.FindByDeviceCodeAsync("DeviceCode1");

        deviceCode.Lifetime.ShouldBe(43);
    }
 /// <summary>
 /// Updates device authorization, searching by user code.
 /// </summary>
 /// <param name="userCode">The user code.</param>
 /// <param name="data">The data.</param>
 /// <returns></returns>
 public Task UpdateByUserCodeAsync(string userCode, DeviceCode data)
 {
     return(_store.UpdateByUserCodeAsync(userCode.Sha256(), data));
 }
    /// <summary>
    /// Updates device authorization, searching by user code.
    /// </summary>
    /// <param name="userCode">The user code.</param>
    /// <param name="data">The data.</param>
    /// <returns></returns>
    public Task UpdateByUserCodeAsync(string userCode, DeviceCode data)
    {
        using var activity = Tracing.StoreActivitySource.StartActivity("DefaultDeviceFlowCodeService.UpdateByUserCode");

        return(_store.UpdateByUserCodeAsync(userCode.Sha256(), data));
    }
Пример #4
0
 public async Task UpdateByUserCode(string userCode, [FromBody] DeviceCode data)
 {
     await _store.UpdateByUserCodeAsync(userCode, data);
 }
        public async Task <IActionResult> AuthorizeDeviceAsync([FromBody] AuthorizeDeviceRequest data)
        {
            // validate client
            var clientResult = await _clientValidator.ValidateAsync(this.HttpContext);

            if (clientResult.Client == null)
            {
                return(Unauthorized(OidcConstants.TokenErrors.InvalidClient));
            }
            var client = clientResult.Client as ClientExtra;

            var grantType =
                clientResult.Client.AllowedGrantTypes.FirstOrDefault(agt => agt == OidcConstants.GrantTypes.DeviceCode);

            if (grantType == null)
            {
                return(Unauthorized(OidcConstants.TokenErrors.InvalidGrant));
            }

            var deviceAuth = await _deviceFlowStore.FindByUserCodeAsync(data.UserCode.Sha256());

            if (deviceAuth == null)
            {
                return(NotFound($"Invalid user code, Device authorization failure - user code is invalid"));
            }


            // VALIDATE if issuer must exist and must be allowed
            // -------------------------------------------------------------------
            var issuer = data.Issuer;

            if (!string.IsNullOrEmpty(data.Issuer))
            {
                issuer = issuer.ToLower();
                var foundIssuer = client.AllowedArbitraryIssuers.FirstOrDefault(x => x == issuer);
                if (string.IsNullOrWhiteSpace(foundIssuer))
                {
                    return(NotFound($"issuer:{issuer} is NOT in the AllowedArbitraryIssuers collection."));
                }
            }

            // VALIDATE if AccessTokenLifetime must exist and must be allowed
            // -------------------------------------------------------------------
            int lifetime = client.AccessTokenLifetime;

            if (data.AccessTokenLifetime != null)
            {
                var requestedAccessTokenLifetime = (int)data.AccessTokenLifetime;
                if (requestedAccessTokenLifetime > 0 && requestedAccessTokenLifetime <= client.AccessTokenLifetime)
                {
                    lifetime = requestedAccessTokenLifetime;
                }
                else
                {
                    return(NotFound($"AccessTokenLifetime:{requestedAccessTokenLifetime} is NOT in range 0-{client.AccessTokenLifetime}."));
                }
            }

            if (data.AccessTokenLifetime != null)
            {
                deviceAuth.Lifetime = (int)data.AccessTokenLifetime;
            }

            string subject = "";

            try
            {
                var validatedResult =
                    await _identityTokenValidator.ValidateIdTokenAsync(data.IdToken,
                                                                       _tokenExchangeOptions.AuthorityKey);

                if (validatedResult.IsError)
                {
                    throw new Exception(
                              $"failed to validate: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken}={data.IdToken}",
                              new Exception(validatedResult.Error));
                }

                subject = SubjectFromClaimsPrincipal(validatedResult.User);
                if (string.IsNullOrWhiteSpace(subject))
                {
                    throw new Exception(
                              $"subject does not exist: {FluffyBunny4.Constants.TokenExchangeTypes.SubjectToken}={data.IdToken}");
                }

                var claims = validatedResult.User.Claims.ToList();
                claims.Add(new Claim(JwtClaimTypes.AuthenticationTime,
                                     claims.FirstOrDefault(c => c.Type == JwtClaimTypes.IssuedAt).Value));
                claims.Add(new Claim(JwtClaimTypes.IdentityProvider, _tokenExchangeOptions.AuthorityKey));

                var newClaimsIdentity = new ClaimsIdentity(claims);
                var subjectPrincipal  = new ClaimsPrincipal(newClaimsIdentity);

                deviceAuth.Subject = subjectPrincipal;

                var requestedScopes = deviceAuth.RequestedScopes.ToList();
                var offlineAccess   =
                    requestedScopes.FirstOrDefault(x => x == IdentityServerConstants.StandardScopes.OfflineAccess);

                var allowedScopes      = new List <string>();
                var allowedClaims      = new List <Claim>();
                var finalCustomPayload = new Dictionary <string, object>();

                var consentAuthorizeResponseTasks = new List <Task <ConsentAuthorizeResponseContainer <PostContext> > >();
                var requestedServiceScopes        = GetServiceToScopesFromRequest(deviceAuth.RequestedScopes.ToList());
                foreach (var serviceScopeSet in requestedServiceScopes)
                {
                    var externalService =
                        await _externalServicesStore.GetExternalServiceByNameAsync(serviceScopeSet.Key);

                    if (externalService == null)
                    {
                        continue;
                    }

                    var discoCache =
                        await _consentDiscoveryCacheAccessor.GetConsentDiscoveryCacheAsync(serviceScopeSet.Key);

                    var doco = await discoCache.GetAsync();

                    if (doco.IsError)
                    {
                        _logger.LogError(doco.Error);
                        continue;
                    }
                    List <string> scopes = null;
                    switch (doco.AuthorizationType)
                    {
                    case Constants.AuthorizationTypes.Implicit:
                        scopes = null;
                        break;

                    case Constants.AuthorizationTypes.SubjectAndScopes:
                        scopes = serviceScopeSet.Value;
                        break;
                    }

                    if (doco.AuthorizationType == Constants.AuthorizationTypes.Implicit)
                    {
                        allowedScopes.AddRange(serviceScopeSet.Value);
                    }
                    else
                    {
                        var request = new ConsentAuthorizeRequest
                        {
                            AuthorizeType = doco.AuthorizationType,
                            Scopes        = scopes,
                            Subject       = subject,
                            Requester     = new ConsentAuthorizeRequest.ClientRequester()
                            {
                                ClientDescription = client.Description,
                                ClientId          = client.ClientId,
                                ClientName        = client.ClientName,
                                Namespace         = client.Namespace,
                                Tenant            = client.TenantName
                            }
                        };
                        // How to send many requests in parallel in ASP.Net Core
                        // https://www.michalbialecki.com/2018/04/19/how-to-send-many-requests-in-parallel-in-asp-net-core/
                        var task = _consentExternalService.PostAuthorizationRequestAsync(doco, request, new PostContext()
                        {
                            ServiceScopeSet   = serviceScopeSet,
                            DiscoveryDocument = doco
                        });
                        consentAuthorizeResponseTasks.Add(task);
                    }
                }
                var consentAuthorizeResponses = await Task.WhenAll(consentAuthorizeResponseTasks);

                foreach (var consentAuthorizeResponse in consentAuthorizeResponses)
                {
                    var response        = consentAuthorizeResponse.Response;
                    var serviceScopeSet = consentAuthorizeResponse.Context.ServiceScopeSet;
                    var doco            = consentAuthorizeResponse.Context.DiscoveryDocument;

                    if (response.Error != null)
                    {
                        _logger.LogError(response.Error.Message);
                        continue;
                    }
                    if (response.Authorized)
                    {
                        switch (doco.AuthorizationType)
                        {
                        case Constants.AuthorizationTypes.SubjectAndScopes:
                            // make sure no funny business is coming in from the auth call.
                            var serviceRoot = $"{_tokenExchangeOptions.BaseScope}{serviceScopeSet.Key}";
                            var query       = (from item in response.Scopes
                                               where item.StartsWith(serviceRoot)
                                               select item);
                            allowedScopes.AddRange(query);
                            if (response.Claims != null && response.Claims.Any())
                            {
                                foreach (var cac in response.Claims)
                                {
                                    // namespace the claims.
                                    allowedClaims.Add(new Claim($"{serviceScopeSet.Key}.{cac.Type}",
                                                                cac.Value));
                                }
                            }

                            if (response.CustomPayload != null)
                            {
                                finalCustomPayload.Add(serviceScopeSet.Key, response.CustomPayload);
                            }

                            break;
                        }
                    }
                }

                if (finalCustomPayload.Any())
                {
                    allowedClaims.Add(new Claim(
                                          Constants.CustomPayload,
                                          _serializer.Serialize(finalCustomPayload),
                                          IdentityServerConstants.ClaimValueTypes.Json));
                }

                deviceAuth.IsAuthorized = true;
                //  deviceAuth.SessionId = sid;
                if (!string.IsNullOrWhiteSpace(offlineAccess))
                {
                    allowedScopes.Add(offlineAccess);
                }

                deviceAuth.AuthorizedScopes = allowedScopes;

                var deviceExtra = _coreMapperAccessor.Mapper.Map <DeviceCodeExtra>(deviceAuth);
                deviceExtra.AuthorizedClaims    = allowedClaims;
                deviceExtra.Issuer              = issuer;
                deviceExtra.AccessTokenLifetime = lifetime;

                await _deviceFlowStore.UpdateByUserCodeAsync(data.UserCode.Sha256(), deviceExtra);

                return(Ok());
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, ex.Message);
                return(StatusCode(500));
            }
        }