public async Task ProcessAsync_when_generated_expect_device_code_stored() { var creationTime = DateTime.UtcNow; clock.UtcNowFunc = () => creationTime; var response = await generator.ProcessAsync(testResult, TestBaseUrl); response.DeviceCode.Should().NotBeNullOrWhiteSpace(); response.Interval.Should().Be(options.DeviceFlow.Interval); var deviceCode = await deviceFlowCodeService.FindByDeviceCodeAsync(response.DeviceCode); deviceCode.Should().NotBeNull(); deviceCode.ClientId.Should().Be(testResult.ValidatedRequest.Client.ClientId); deviceCode.IsOpenId.Should().Be(testResult.ValidatedRequest.IsOpenIdRequest); deviceCode.Lifetime.Should().Be(testResult.ValidatedRequest.Client.DeviceCodeLifetime); deviceCode.CreationTime.Should().Be(creationTime); deviceCode.Subject.Should().BeNull(); deviceCode.AuthorizedScopes.Should().BeNull(); response.DeviceCodeLifetime.Should().Be(deviceCode.Lifetime); }
/// <summary> /// Validates the device code. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> public async Task ValidateAsync(DeviceCodeValidationContext context) { var deviceCode = await _devices.FindByDeviceCodeAsync(context.DeviceCode); if (deviceCode == null) { _logger.LogError("Invalid device code"); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.InvalidGrant); return; } // validate client binding if (deviceCode.ClientId != context.Request.Client.ClientId) { _logger.LogError("Client {0} is trying to use a device code from client {1}", context.Request.Client.ClientId, deviceCode.ClientId); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.InvalidGrant); return; } if (await _throttlingService.ShouldSlowDown(context.DeviceCode, deviceCode)) { _logger.LogError("Client {0} is polling too fast", deviceCode.ClientId); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.SlowDown); return; } // validate lifetime if (deviceCode.CreationTime.AddSeconds(deviceCode.Lifetime) < _systemClock.UtcNow) { _logger.LogError("Expired device code"); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.ExpiredToken); return; } // denied if (deviceCode.IsAuthorized && (deviceCode.AuthorizedScopes == null || deviceCode.AuthorizedScopes.Any() == false)) { _logger.LogError("No scopes authorized for device authorization. Access denied"); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.AccessDenied); return; } // make sure code is authorized if (!deviceCode.IsAuthorized || deviceCode.Subject == null) { context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.AuthorizationPending); return; } // make sure user is enabled var isActiveCtx = new IsActiveContext(deviceCode.Subject, context.Request.Client, IdentityServerConstants.ProfileIsActiveCallers.DeviceCodeValidation); await _profile.IsActiveAsync(isActiveCtx); if (isActiveCtx.IsActive == false) { _logger.LogError("User has been disabled: {subjectId}", deviceCode.Subject.GetSubjectId()); context.Result = new TokenRequestValidationResult(context.Request, OidcConstants.TokenErrors.InvalidGrant); return; } context.Request.DeviceCode = deviceCode; context.Request.SessionId = deviceCode.SessionId; context.Result = new TokenRequestValidationResult(context.Request); await _devices.RemoveByDeviceCodeAsync(context.DeviceCode); }