public async Task ProcessSigninResponse_AdHocAuthorizationIsAutomaticallyCreated()
        {
            // Arrange
            var token = new OpenIddictToken();

            var manager = CreateAuthorizationManager(instance =>
            {
                instance.Setup(mock => mock.FindByIdAsync("1AF06AB2-A0FC-4E3D-86AF-E04DA8C7BE70", It.IsAny <CancellationToken>()))
                .ReturnsAsync(new OpenIddictAuthorization());
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(CreateApplicationManager(instance =>
                {
                    var application = new OpenIddictApplication();

                    instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny <CancellationToken>()))
                    .ReturnsAsync(application);

                    instance.Setup(mock => mock.ValidateRedirectUriAsync(application, "http://www.fabrikam.com/path", It.IsAny <CancellationToken>()))
                    .ReturnsAsync(true);

                    instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny <CancellationToken>()))
                    .ReturnsAsync(OpenIddictConstants.ClientTypes.Public);

                    instance.Setup(mock => mock.GetIdAsync(application, It.IsAny <CancellationToken>()))
                    .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
                }));

                builder.Services.AddSingleton(CreateTokenManager(instance =>
                {
                    instance.Setup(mock => mock.CreateAsync(It.IsAny <OpenIddictTokenDescriptor>(), It.IsAny <CancellationToken>()))
                    .ReturnsAsync(token);

                    instance.Setup(mock => mock.GetIdAsync(token, It.IsAny <CancellationToken>()))
                    .ReturnsAsync("3E228451-1555-46F7-A471-951EFBA23A56");
                }));

                builder.Services.AddSingleton(manager);
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(AuthorizationEndpoint, new OpenIdConnectRequest
            {
                ClientId     = "Fabrikam",
                RedirectUri  = "http://www.fabrikam.com/path",
                ResponseType = OpenIdConnectConstants.ResponseTypes.Code,
            });

            // Assert
            Assert.NotNull(response.Code);

            Mock.Get(manager).Verify(mock => mock.CreateAsync(
                                         It.Is <OpenIddictAuthorizationDescriptor>(descriptor =>
                                                                                   descriptor.ApplicationId == "3E228451-1555-46F7-A471-951EFBA23A56" &&
                                                                                   descriptor.Subject == "Bob le Magnifique" &&
                                                                                   descriptor.Type == OpenIddictConstants.AuthorizationTypes.AdHoc),
                                         It.IsAny <CancellationToken>()), Times.Once());
        }
        public async Task HandleTokenRequest_AuthorizationCodeIsAutomaticallyRevoked()
        {
            // Arrange
            var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur");

            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);

            ticket.SetPresenters("Fabrikam");
            ticket.SetTicketId("3E228451-1555-46F7-A471-951EFBA23A56");
            ticket.SetUsage(OpenIdConnectConstants.Usages.AuthorizationCode);

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Unprotect("SplxlOBeZQQYbYS6WxSbIA"))
            .Returns(ticket);

            var token = new OpenIddictToken();

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(CreateApplicationManager(instance =>
                {
                    var application = new OpenIddictApplication();

                    instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny <CancellationToken>()))
                    .ReturnsAsync(application);

                    instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny <CancellationToken>()))
                    .ReturnsAsync(OpenIddictConstants.ClientTypes.Public);
                }));

                builder.Services.AddSingleton(manager);

                builder.Configure(options => options.AuthorizationCodeFormat = format.Object);
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest
            {
                ClientId    = "Fabrikam",
                Code        = "SplxlOBeZQQYbYS6WxSbIA",
                GrantType   = OpenIdConnectConstants.GrantTypes.AuthorizationCode,
                RedirectUri = "http://www.fabrikam.com/path"
            });

            // Assert
            Mock.Get(manager).Verify(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny <CancellationToken>()), Times.Once());
            Mock.Get(manager).Verify(mock => mock.RevokeAsync(token, It.IsAny <CancellationToken>()), Times.Once());
        }
        public async Task ProcessSigninResponse_ReturnsErrorResponseWhenExtendingLifetimeOfExistingTokenFailed()
        {
            // Arrange
            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(),
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);

            ticket.SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103");
            ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.RefreshToken);
            ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.OfflineAccess);

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Protect(It.IsAny <AuthenticationTicket>()))
            .Returns("8xLOxBtZp8");

            format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
            .Returns(ticket);

            var token = new OpenIddictToken();

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.IsRedeemedAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(false);

                instance.Setup(mock => mock.IsValidAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(true);

                instance.Setup(mock => mock.ExtendAsync(token, It.IsAny <DateTimeOffset?>(), It.IsAny <CancellationToken>()))
                .ThrowsAsync(new Exception());
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(manager);

                builder.Configure(options =>
                {
                    options.SystemClock = Mock.Of <ISystemClock>(mock => mock.UtcNow ==
                                                                 new DateTimeOffset(2017, 01, 05, 00, 00, 00, TimeSpan.Zero));
                    options.RefreshTokenLifetime = TimeSpan.FromDays(10);
                    options.RefreshTokenFormat   = format.Object;
                });
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest
            {
                GrantType    = OpenIdConnectConstants.GrantTypes.RefreshToken,
                RefreshToken = "8xLOxBtZp8"
            });

            // Assert
            Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
            Assert.Equal("The specified refresh token is no longer valid.", response.ErrorDescription);

            Mock.Get(manager).Verify(mock => mock.ExtendAsync(token,
                                                              new DateTimeOffset(2017, 01, 15, 00, 00, 00, TimeSpan.Zero),
                                                              It.IsAny <CancellationToken>()), Times.Once());
        }
        public async Task ProcessSigninResponse_ReturnsErrorResponseWhenRedeemingRefreshTokenFails()
        {
            // Arrange
            var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur");

            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);

            ticket.SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103");
            ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.RefreshToken);
            ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.OfflineAccess);

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Protect(It.IsAny <AuthenticationTicket>()))
            .Returns("8xLOxBtZp8");

            format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
            .Returns(ticket);

            var token = new OpenIddictToken();

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.IsRedeemedAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(false);

                instance.Setup(mock => mock.IsValidAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(true);

                instance.Setup(mock => mock.RedeemAsync(token, It.IsAny <CancellationToken>()))
                .ThrowsAsync(new Exception());
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(manager);

                builder.UseRollingTokens();

                builder.Configure(options => options.RefreshTokenFormat = format.Object);
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest
            {
                GrantType    = OpenIdConnectConstants.GrantTypes.RefreshToken,
                RefreshToken = "8xLOxBtZp8"
            });

            // Assert
            Assert.Equal(OpenIdConnectConstants.Errors.InvalidGrant, response.Error);
            Assert.Equal("The specified authorization code is no longer valid.", response.ErrorDescription);

            Mock.Get(manager).Verify(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny <CancellationToken>()), Times.Exactly(2));
            Mock.Get(manager).Verify(mock => mock.RedeemAsync(token, It.IsAny <CancellationToken>()), Times.Once());
        }
        public async Task ProcessSigninResponse_AuthenticationPropertiesAreAutomaticallyRestored()
        {
            // Arrange
            var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur");

            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                OpenIdConnectServerDefaults.AuthenticationScheme);

            ticket.SetTokenId("60FFF7EA-F98E-437B-937E-5073CC313103");
            ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.RefreshToken);
            ticket.SetScopes(OpenIdConnectConstants.Scopes.OpenId, OpenIdConnectConstants.Scopes.OfflineAccess);
            ticket.SetProperty("custom_property_in_original_ticket", "original_value");

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Protect(It.IsAny <AuthenticationTicket>()))
            .Returns("8xLOxBtZp8");

            format.Setup(mock => mock.Unprotect("8xLOxBtZp8"))
            .Returns(ticket);

            var token = new OpenIddictToken();

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByIdAsync("60FFF7EA-F98E-437B-937E-5073CC313103", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.IsRedeemedAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(false);

                instance.Setup(mock => mock.IsValidAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(true);
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(manager);

                builder.UseRollingTokens();

                builder.Configure(options => options.RefreshTokenFormat = format.Object);
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(TokenEndpoint, new OpenIdConnectRequest
            {
                GrantType    = OpenIdConnectConstants.GrantTypes.RefreshToken,
                RefreshToken = "8xLOxBtZp8",
                ["do-not-flow-original-properties"] = true
            });

            // Assert
            Assert.NotNull(response.IdToken);
            Assert.NotNull(response.RefreshToken);

            format.Verify(mock => mock.Protect(
                              It.Is <AuthenticationTicket>(value =>
                                                           value.Properties.Items["custom_property_in_original_ticket"] == "original_value" &&
                                                           value.Properties.Items["custom_property_in_new_ticket"] == "new_value")));
        }
        public async Task DecryptToken_ReturnsValidResultForValidReferenceToken()
        {
            // Arrange
            var token = new OpenIddictToken();

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Unprotect("valid-reference-token-payload"))
            .Returns(delegate
            {
                var identity = new ClaimsIdentity(OpenIddictValidationDefaults.AuthenticationScheme);
                identity.AddClaim(new Claim(OAuthValidationConstants.Claims.Subject, "Fabrikam"));

                return(new AuthenticationTicket(
                           new ClaimsPrincipal(identity),
                           OpenIddictValidationDefaults.AuthenticationScheme));
            });

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByReferenceIdAsync("valid-reference-token-id", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.GetPayloadAsync(token, It.IsAny <CancellationToken>()))
                .Returns(new ValueTask <string>("valid-reference-token-payload"));

                instance.Setup(mock => mock.GetCreationDateAsync(token, It.IsAny <CancellationToken>()))
                .Returns(new ValueTask <DateTimeOffset?>(new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero)));

                instance.Setup(mock => mock.GetExpirationDateAsync(token, It.IsAny <CancellationToken>()))
                .Returns(new ValueTask <DateTimeOffset?>(new DateTimeOffset(2918, 01, 01, 00, 00, 00, TimeSpan.Zero)));
            });

            var server = CreateResourceServer(builder =>
            {
                builder.Services.AddSingleton(manager);
                builder.Configure(options => options.AccessTokenFormat = format.Object);
            });

            var client = server.CreateClient();

            var request = new HttpRequestMessage(HttpMethod.Get, "/ticket");

            request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", "valid-reference-token-id");

            // Act
            var response = await client.SendAsync(request);

            var ticket     = JObject.Parse(await response.Content.ReadAsStringAsync());
            var properties = (from property in ticket.Value <JArray>("Properties")
                              select new
            {
                Name = property.Value <string>("Name"),
                Value = property.Value <string>("Value")
            }).ToDictionary(property => property.Name, property => property.Value);

            // Assert
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            Assert.Equal(
                new DateTimeOffset(2018, 01, 01, 00, 00, 00, TimeSpan.Zero),
                DateTimeOffset.Parse(properties[".issued"], CultureInfo.InvariantCulture));
            Assert.Equal(
                new DateTimeOffset(2918, 01, 01, 00, 00, 00, TimeSpan.Zero),
                DateTimeOffset.Parse(properties[".expires"], CultureInfo.InvariantCulture));

            Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("valid-reference-token-id", It.IsAny <CancellationToken>()), Times.Once());
            Mock.Get(manager).Verify(mock => mock.GetPayloadAsync(token, It.IsAny <CancellationToken>()), Times.Once());
            Mock.Get(manager).Verify(mock => mock.GetCreationDateAsync(token, It.IsAny <CancellationToken>()), Times.Once());
            Mock.Get(manager).Verify(mock => mock.GetExpirationDateAsync(token, It.IsAny <CancellationToken>()), Times.Once());
            format.Verify(mock => mock.Unprotect("valid-reference-token-payload"), Times.Once());
        }
        public async Task HandleIntrospectionRequest_RequestIsRejectedWhenReferenceTokenIsInvalid()
        {
            // Arrange
            var identity = new ClaimsIdentity(OpenIddictServerDefaults.AuthenticationScheme);

            identity.AddClaim(OpenIdConnectConstants.Claims.Subject, "Bob le Bricoleur");

            var ticket = new AuthenticationTicket(
                new ClaimsPrincipal(identity),
                new AuthenticationProperties(),
                OpenIddictServerDefaults.AuthenticationScheme);

            ticket.SetAudiences("Fabrikam");
            ticket.SetProperty(OpenIddictConstants.Properties.InternalTokenId, "3E228451-1555-46F7-A471-951EFBA23A56");
            ticket.SetTokenUsage(OpenIdConnectConstants.TokenUsages.AccessToken);

            var format = new Mock <ISecureDataFormat <AuthenticationTicket> >();

            format.Setup(mock => mock.Unprotect("2YotnFZFEjr1zCsicMWpAA"))
            .Returns(ticket);

            var token = new OpenIddictToken();

            var manager = CreateTokenManager(instance =>
            {
                instance.Setup(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.GetIdAsync(token, It.IsAny <CancellationToken>()))
                .Returns(new ValueTask <string>("3E228451-1555-46F7-A471-951EFBA23A56"));

                instance.Setup(mock => mock.GetPayloadAsync(token, It.IsAny <CancellationToken>()))
                .Returns(new ValueTask <string>("2YotnFZFEjr1zCsicMWpAA"));

                instance.Setup(mock => mock.FindByIdAsync("3E228451-1555-46F7-A471-951EFBA23A56", It.IsAny <CancellationToken>()))
                .ReturnsAsync(token);

                instance.Setup(mock => mock.IsValidAsync(token, It.IsAny <CancellationToken>()))
                .ReturnsAsync(false);
            });

            var server = CreateAuthorizationServer(builder =>
            {
                builder.Services.AddSingleton(CreateApplicationManager(instance =>
                {
                    var application = new OpenIddictApplication();

                    instance.Setup(mock => mock.FindByClientIdAsync("Fabrikam", It.IsAny <CancellationToken>()))
                    .ReturnsAsync(application);

                    instance.Setup(mock => mock.GetClientTypeAsync(application, It.IsAny <CancellationToken>()))
                    .Returns(new ValueTask <string>(OpenIddictConstants.ClientTypes.Confidential));

                    instance.Setup(mock => mock.ValidateClientSecretAsync(application, "7Fjfp0ZBr1KtDRbnfVdmIw", It.IsAny <CancellationToken>()))
                    .ReturnsAsync(true);
                }));

                builder.Services.AddSingleton(manager);

                builder.Configure(options => options.AccessTokenFormat = format.Object);

                builder.UseReferenceTokens();
            });

            var client = new OpenIdConnectClient(server.CreateClient());

            // Act
            var response = await client.PostAsync(IntrospectionEndpoint, new OpenIdConnectRequest
            {
                ClientId     = "Fabrikam",
                ClientSecret = "7Fjfp0ZBr1KtDRbnfVdmIw",
                Token        = "QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI"
            });

            // Assert
            Assert.Single(response.GetParameters());
            Assert.False((bool)response[OpenIdConnectConstants.Claims.Active]);

            Mock.Get(manager).Verify(mock => mock.FindByReferenceIdAsync("QaTk2f6UPe9trKismGBJr0OIs0KqpvNrqRsJqGuJAAI", It.IsAny <CancellationToken>()), Times.Once());
            Mock.Get(manager).Verify(mock => mock.IsValidAsync(token, It.IsAny <CancellationToken>()), Times.Once());
        }