internal static StoredAuthorizationCode ToDbFormat(string key, AuthorizationCode code) { var result = new StoredAuthorizationCode { Id = "authorizationcodes/" + key, ClientId = code.ClientId, Client = code.Client.ClientId, CodeChallenge = code.CodeChallenge, WasConsentShown = code.WasConsentShown, CreationTime = code.CreationTime, Expires = code.CreationTime.AddSeconds(code.Client.AuthorizationCodeLifetime), RedirectUri = code.RedirectUri, IsOpenId = code.IsOpenId, Nonce = code.Nonce, SessionId = code.SessionId, CodeChallengeMethod = code.CodeChallengeMethod, SubjectId = code.SubjectId, RequestedScopes = (from s in code.RequestedScopes select s.Name).ToList(), }; result.Subject = new List<StoredIdentity>(); foreach (var id in code.Subject.Identities) { result.Subject.Add(Data.StoredIdentity.ToDbFormat(id)); } return result; }
public async Task Valid_Code_Request() { var client = await _clients.FindClientByIdAsync("codeclient"); var store = new InMemoryAuthorizationCodeStore(); var code = new AuthorizationCode { Subject = IdentityServerPrincipal.Create("123", "bob"), Client = client, RedirectUri = "https://server/cb", RequestedScopes = new List<Scope> { new Scope { Name = "openid" } } }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeFalse(); }
public async Task Unknown_Grant_Type() { var client = await _clients.FindClientByIdAsync("codeclient"); var store = new InMemoryAuthorizationCodeStore(); var code = new AuthorizationCode { Client = client, IsOpenId = true, RedirectUri = "https://server/cb", }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, "unknown"); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeTrue(); result.Error.Should().Be(Constants.TokenErrors.UnsupportedGrantType); }
public async Task StoreAsync(string key, AuthorizationCode value) { using (var s = _store.OpenAsyncSession()) using (s.Advanced.DocumentStore.AggressivelyCache()) { var toSave = Data.StoredAuthorizationCode.ToDbFormat(key, value); await s.StoreAsync(toSave); await s.SaveChangesAsync(); } }
public async Task StoreAsync(string key, AuthorizationCode value) { Log.Debug("Storing authorization code with key" + key); BsonDocument doc = _serializer.Serialize(key, value); var result = await Collection.ReplaceOneAsync( Filter.ById(key), doc, PerformUpsert).ConfigureAwait(false); Log.Debug(result.ToString); }
public void AuthorizationCodePersists() { var subClaim = new Claim("sub", "*****@*****.**"); var emailClaim = new Claim("email", "*****@*****.**"); var code = new AuthorizationCode { Client = new Client { ClientId = "cid" }, RequestedScopes = new List<Scope> { new Scope { Description = "this is description", Enabled = true, Name = "sname", DisplayName = "This is Name!" } }, Subject = new ClaimsPrincipal(new ClaimsIdentity(new List<Claim> { subClaim,emailClaim})) }; var clients = new List<Client> { new Client { ClientId = "cid", ClientName = "cname", Enabled = true, SlidingRefreshTokenLifetime = 100, AccessTokenType = AccessTokenType.Jwt, Flow = Flows.Implicit } }; var clientStore = new InMemoryClientStore(clients); var scopes = new List<Scope> { new Scope { Description = "sdescription", Name = "sname", Enabled = true, Emphasize = false, IncludeAllClaimsForUser = true, Required = false, Type = ScopeType.Identity } }; var scopeStore = new InMemoryScopeStore(scopes); var store = new RedisAuthorizationCodeStore(clientStore,scopeStore, RedisServer); store.StoreAsync("key1", code).Wait(); var result = store.GetAsync("key1").Result; Assert.Equal(code.SubjectId, result.SubjectId); Assert.Equal(code.ClientId, result.ClientId); }
private BsonArray SerializeIdentities(AuthorizationCode code) { var subject = new BsonArray(); foreach (ClaimsIdentity claimsIdentity in code.Subject.Identities) { var identity = new BsonDocument(); identity["authenticationType"] = claimsIdentity.AuthenticationType; var enumerable = claimsIdentity.Claims; var claims = ClaimSetSerializer.Serialize(enumerable); identity["claimSet"] = claims; subject.Add(identity); } return subject; }
public BsonDocument Serialize(string key, AuthorizationCode code) { var doc = new BsonDocument(); doc["_id"] = key; doc["_version"] = 1; doc["_clientId"] = code.ClientId; doc["_subjectId"] = code.SubjectId; doc["_expires"] = code.CreationTime.AddSeconds(code.Client.AuthorizationCodeLifetime).ToBsonDateTime(); doc["creationTime"] = code.CreationTime.ToBsonDateTime(); doc["isOpenId"] = code.IsOpenId; doc["redirectUri"] = code.RedirectUri; doc["wasConsentShown"] = code.WasConsentShown; doc.SetIfNotNull("nonce", code.Nonce); doc["subject"] = SerializeIdentities(code); var requestedScopes = new BsonArray(); foreach (var scope in code.RequestedScopes.Select(x=>x.Name)) { requestedScopes.Add(scope); } doc["requestedScopes"] = requestedScopes; return doc; }
private async Task RaiseCodeIssuedEventAsync(string id, AuthorizationCode code) { await _events.RaiseAuthorizationCodeIssuedEventAsync(id, code); }
public async Task Code_Request_with_disabled_User() { var client = await _clients.FindClientByIdAsync("codeclient"); var store = new InMemoryAuthorizationCodeStore(); var mock = new Mock<IUserService>(); mock.Setup(u => u.IsActiveAsync(It.IsAny<IsActiveContext>())).Callback<IsActiveContext>(ctx => { ctx.IsActive = false; }).Returns(Task.FromResult(0)); var code = new AuthorizationCode { Client = client, Subject = IdentityServerPrincipal.Create("123", "bob"), RedirectUri = "https://server/cb", RequestedScopes = new List<Scope> { new Scope { Name = "openid" } } }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store, userService: mock.Object); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeTrue(); }
private TokenRequestValidationResult ValidateAuthorizationCodeWithProofKeyParameters(string codeVerifier, AuthorizationCode authZcode) { if (authZcode.CodeChallenge.IsMissing() || authZcode.CodeChallengeMethod.IsMissing()) { LogError("Client uses AuthorizationCodeWithProofKey flow but missing code challenge or code challenge method in authZ code"); return Invalid(Constants.TokenErrors.InvalidGrant); } if (codeVerifier.IsMissing()) { LogError("Missing code_verifier"); return Invalid(Constants.TokenErrors.InvalidGrant); } if (codeVerifier.Length < _options.InputLengthRestrictions.CodeVerifierMinLength || codeVerifier.Length > _options.InputLengthRestrictions.CodeVerifierMaxLength) { LogError("code_verifier is too short or too long."); return Invalid(Constants.TokenErrors.InvalidGrant); } if (Constants.SupportedCodeChallengeMethods.Contains(authZcode.CodeChallengeMethod) == false) { LogError("Unsupported code challenge method: " + authZcode.CodeChallengeMethod); return Invalid(Constants.TokenErrors.InvalidGrant); } if (ValidateCodeVerifierAgainstCodeChallenge(codeVerifier, authZcode.CodeChallenge, authZcode.CodeChallengeMethod) == false) { LogError("Transformed code verifier does not match code challenge"); return Invalid(Constants.TokenErrors.InvalidGrant); } return Valid(); }
public async Task Client_Trying_To_Request_Token_Using_Another_Clients_Code() { var client1 = await _clients.FindClientByIdAsync("codeclient"); var client2 = await _clients.FindClientByIdAsync("codeclient_restricted"); var store = new InMemoryAuthorizationCodeStore(); var code = new AuthorizationCode { Client = client1, IsOpenId = true, RedirectUri = "https://server/cb", }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client2); result.IsError.Should().BeTrue(); result.Error.Should().Be(Constants.TokenErrors.InvalidGrant); }
public async Task Expired_AuthorizationCode() { var client = await _clients.FindClientByIdAsync("codeclient"); var store = new InMemoryAuthorizationCodeStore(); var code = new AuthorizationCode { Client = client, IsOpenId = true, RedirectUri = "https://server/cb", CreationTime = DateTimeOffset.UtcNow.AddSeconds(-100) }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeTrue(); result.Error.Should().Be(Constants.TokenErrors.InvalidGrant); }
public void TestFixtureSetup() { var database = RedisHelpers.ConnectionMultiplexer.GetDatabase(); var subject = new ClaimsPrincipal( new List<ClaimsIdentity> { new ClaimsIdentity( new List<Claim> { new Claim(Constants.ClaimTypes.Subject, "sid") }) }); var code = new AuthorizationCode { Client = new Client { ClientId = "cid" }, RequestedScopes = new List<Scope> { new Scope { Description = "this is description", Enabled = true, Name = "Scope", DisplayName = "Display Name" } }, Subject = subject, CodeChallenge = "CodeChallenge", CodeChallengeMethod = "CodeChallengeMethod", CreationTime = new DateTimeOffset(new DateTime(2016, 1, 1)), IsOpenId = true, Nonce = "Nonce", RedirectUri = "RedirectUri", SessionId = "SessionId", WasConsentShown = true }; var settings = new JsonSettingsFactory(new CustomMappersConfiguration()).Create(); var serialized = JsonConvert.SerializeObject(code, settings); database.StringSet("DEFAULT_ACS_Existing", serialized); database.StringSet("DEFAULT_ACS_Delete", serialized); }
public async Task AuthorizationCodeTooLong() { var client = await _clients.FindClientByIdAsync("codeclient"); var store = new InMemoryAuthorizationCodeStore(); var options = new IdentityServerOptions(); var code = new AuthorizationCode { Client = client, IsOpenId = true, RedirectUri = "https://server/cb", }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var longCode = "x".Repeat(options.InputLengthRestrictions.AuthorizationCode + 1); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, longCode); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeTrue(); result.Error.Should().Be(Constants.TokenErrors.InvalidGrant); }
public async Task Valid_Code_Request_With_CodeVerifier_Sha256() { var client = await _clients.FindClientByIdAsync("codewithproofkeyclient"); var store = new InMemoryAuthorizationCodeStore(); var options = new IdentityServerOptions(); var codeVerifier = "x".Repeat(options.InputLengthRestrictions.CodeChallengeMinLength); var codeVerifierBytes = Encoding.ASCII.GetBytes(codeVerifier); var hashedBytes = codeVerifierBytes.Sha256(); var codeChallenge = Base64Url.Encode(hashedBytes); var code = new AuthorizationCode { Client = client, Subject = IdentityServerPrincipal.Create("123", "bob"), RedirectUri = "https://server/cb", CodeChallenge = codeChallenge.Sha256(), CodeChallengeMethod = Constants.CodeChallengeMethods.SHA_256, RequestedScopes = new List<Scope> { new Scope { Name = "openid" } } }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); parameters.Add(Constants.TokenRequest.CodeVerifier, codeVerifier); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeFalse(); }
private static async Task<AuthorizationCode> Version1( BsonDocument doc, IClientStore clientStore, IScopeStore scopeStore) { var code = new AuthorizationCode(); code.CreationTime = doc.GetValueOrDefault("creationTime", code.CreationTime); code.IsOpenId = doc.GetValueOrDefault("isOpenId", code.IsOpenId); code.RedirectUri = doc.GetValueOrDefault("redirectUri", code.RedirectUri); code.WasConsentShown = doc.GetValueOrDefault("wasConsentShown", code.WasConsentShown); code.Nonce = doc.GetValueOrDefault("nonce", code.Nonce); var claimsPrincipal = new ClaimsPrincipal(); IEnumerable<ClaimsIdentity> identities = doc.GetValueOrDefault("subject", sub => { string authenticationType = sub.GetValueOrDefault("authenticationType", (string)null); var claims = sub.GetNestedValueOrDefault("claimSet", ClaimSetSerializer.Deserialize, new Claim[] { }); ClaimsIdentity identity = authenticationType == null ? new ClaimsIdentity(claims) : new ClaimsIdentity(claims, authenticationType); return identity; }, new ClaimsIdentity[] { }); claimsPrincipal.AddIdentities(identities); code.Subject = claimsPrincipal; var clientId = doc["_clientId"].AsString; code.Client = await clientStore.FindClientByIdAsync(clientId); if (code.Client == null) { throw new InvalidOperationException("Client not found when deserializing authorization code. Client id: " + clientId); } var scopes = doc.GetValueOrDefault( "requestedScopes", (IEnumerable<string>)new string[] { }).ToArray(); code.RequestedScopes = await scopeStore.FindScopesAsync(scopes); if (scopes.Count() > code.RequestedScopes.Count()) { throw new InvalidOperationException("Scopes not found when deserializing authorization code. Scopes: " + string.Join(", ",scopes.Except(code.RequestedScopes.Select(x=>x.Name)))); } return code; }
private async Task<string> CreateCodeAsync(ValidatedAuthorizeRequest request) { var code = new AuthorizationCode { Client = request.Client, Subject = request.Subject, SessionId = request.SessionId, IsOpenId = request.IsOpenIdRequest, RequestedScopes = request.ValidatedScopes.GrantedScopes, RedirectUri = request.RedirectUri, Nonce = request.Nonce, WasConsentShown = request.WasConsentShown, }; // store id token and access token and return authorization code var id = CryptoRandom.CreateUniqueId(); await _authorizationCodes.StoreAsync(id, code); await RaiseCodeIssuedEventAsync(id, code); return id; }
/// <summary> /// Stores the data. /// </summary> /// <param name="key">The key.</param> /// <param name="value">The value.</param> /// <returns></returns> public Task StoreAsync(string key, AuthorizationCode value) { _repository[key] = value; return Task.FromResult<object>(null); }
internal static async Task<AuthorizationCode> FromDbFormat(StoredAuthorizationCode code, IAsyncDocumentSession s, IScopeStore scopeStore) { var result = new AuthorizationCode { CreationTime = code.CreationTime, IsOpenId = code.IsOpenId, RedirectUri = code.RedirectUri, WasConsentShown = code.WasConsentShown, Nonce = code.Nonce, Client = Data.StoredClient.FromDbFormat(await s.LoadAsync<Data.StoredClient>("clients/" + code.Client)), CodeChallenge = code.CodeChallenge, CodeChallengeMethod = code.CodeChallengeMethod, SessionId = code.SessionId, RequestedScopes = await scopeStore.FindScopesAsync(code.RequestedScopes) }; var claimsPrinciple = new ClaimsPrincipal(); foreach (var id in code.Subject) { claimsPrinciple.AddIdentity(Data.StoredIdentity.FromDbFormat(id)); } result.Subject = claimsPrinciple; return result; }
public void StoreAsync_WhenCalled_ExpectAction() { // Arrange var mockCacheConfiguration = new Mock<IConfiguration<RedisCacheConfigurationEntity>>(); mockCacheConfiguration.Setup(r => r.Get).Returns( new RedisCacheConfigurationEntity { CacheDuration = 10, RedisCacheDefaultPrefix = "DEFAULT", UseObjectCompression = false }); var jsonSettingsFactory = new JsonSettingsFactory(new CustomMappersConfiguration()); var cacheManager = new RedisCacheManager<AuthorizationCode>( RedisHelpers.ConnectionMultiplexer, mockCacheConfiguration.Object, jsonSettingsFactory.Create()); var authorizationCodeStore = new AuthorizationCodeStore( cacheManager, mockCacheConfiguration.Object); var subject = new ClaimsPrincipal( new List<ClaimsIdentity> { new ClaimsIdentity( new List<Claim> { new Claim(Constants.ClaimTypes.Subject, "sid") }) }); var code = new AuthorizationCode { Client = new Client { ClientId = "cid" }, RequestedScopes = new List<Scope> { new Scope { Description = "this is description", Enabled = true, Name = "Scope", DisplayName = "Display Name" } }, Subject = subject }; // Act var stopwatch = Stopwatch.StartNew(); authorizationCodeStore.StoreAsync("KeyToStore", code).Wait(); stopwatch.Stop(); // Assert this.WriteTimeElapsed(stopwatch); var redisValue = RedisHelpers.ConnectionMultiplexer.GetDatabase().StringGet("DEFAULT_ACS_KeyToStore"); Assert.That(redisValue.HasValue, Is.True); Console.WriteLine(redisValue); }
public async Task Code_Request_Contains_Code_Verifier_But_Client_Flow_Is_Not_PKCE(string clientId) { var client = await _clients.FindClientByIdAsync(clientId); var store = new InMemoryAuthorizationCodeStore(); var options = new IdentityServerOptions(); var code = new AuthorizationCode { Client = client, Subject = IdentityServerPrincipal.Create("123", "bob"), RedirectUri = "https://server/cb", RequestedScopes = new List<Scope> { new Scope { Name = "openid" } } }; await store.StoreAsync("valid", code); var validator = Factory.CreateTokenRequestValidator( authorizationCodeStore: store); var parameters = new NameValueCollection(); parameters.Add(Constants.TokenRequest.GrantType, Constants.GrantTypes.AuthorizationCode); parameters.Add(Constants.TokenRequest.Code, "valid"); parameters.Add(Constants.TokenRequest.RedirectUri, "https://server/cb"); parameters.Add(Constants.TokenRequest.CodeVerifier, "x".Repeat(options.InputLengthRestrictions.CodeVerifierMinLength)); var result = await validator.ValidateRequestAsync(parameters, client); result.IsError.Should().BeTrue(); result.Error.Should().Be(Constants.TokenErrors.InvalidGrant); }