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);
        }