public void GenerateECSignedJWT()
        {
            var mockPrivateKeyConfiguration = TestCryptoKeys.GetMockECPrivateKeyConfiguration();

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = mockPrivateKeyConfiguration;
            configuration.Scopes            = new List <string> {
                "foo"
            };

            var signedJwt = new DefaultJwtGenerator(configuration).GenerateSignedJWT();

            // Verify signature with public key
            var claimsPrincipal = new JwtSecurityTokenHandler().ValidateToken(
                signedJwt,
                new TokenValidationParameters
            {
                ValidAudience    = $"{configuration.OktaDomain}oauth2/v1/token",
                ValidIssuer      = configuration.ClientId,
                IssuerSigningKey = TestCryptoKeys.GetMockECPublicKey(),
            }, out _);

            claimsPrincipal.Should().NotBeNull();
        }
        public async Task FailIfAccessTokenNotFound()
        {
            var response       = @"{""foo"":""bar""}";
            var messageHandler = new MockHttpMessageHandler(response, HttpStatusCode.OK);
            var httpClient     = new HttpClient(messageHandler);

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = TestCryptoKeys.GetMockRSAPrivateKeyConfiguration();
            configuration.Scopes            = new List <string> {
                "foo"
            };

            var oktaClient = new OktaClient(configuration);
            var logger     = Substitute.For <ILogger>();

            var resourceFactory = new ResourceFactory(oktaClient, logger);
            var tokenProvider   = new DefaultOAuthTokenProvider(configuration, resourceFactory, httpClient);

            Func <Task <string> > function = async() => await tokenProvider.GetAccessTokenAsync();

            function.Should().Throw <MissingFieldException>();
        }
        public async Task FailIfStatusCodeIs4xx(HttpStatusCode statusCode)
        {
            var response       = @"{""error"":""invalid_client"",""error_description"":""The audience claim for client_assertion must be the endpoint invoked for the request.""}";
            var messageHandler = new MockHttpMessageHandler(response, statusCode);
            var httpClient     = new HttpClient(messageHandler);

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = TestCryptoKeys.GetMockRSAPrivateKeyConfiguration();
            configuration.Scopes            = new List <string> {
                "foo"
            };

            var oktaClient = new OktaClient(configuration);
            var logger     = Substitute.For <ILogger>();

            var resourceFactory = new ResourceFactory(oktaClient, logger);
            var tokenProvider   = new DefaultOAuthTokenProvider(configuration, resourceFactory, httpClient);

            Func <Task <string> > function = async() => await tokenProvider.GetAccessTokenAsync();

            function.Should().Throw <OktaOAuthException>().Where(x => x.StatusCode == (int)statusCode && x.Error == "invalid_client" && x.ErrorDescription == "The audience claim for client_assertion must be the endpoint invoked for the request.");
        }
        public async Task ReturnAccessTokenWhenRequestSuccess()
        {
            var response       = @"{""token_type"":""Bearer"",""expires_in"":3600,""access_token"":""foo"",""scope"":""okta.users.read okta.users.manage""}";
            var messageHandler = new MockHttpMessageHandler(response, HttpStatusCode.OK);
            var httpClient     = new HttpClient(messageHandler);

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = TestCryptoKeys.GetMockRSAPrivateKeyConfiguration();
            configuration.Scopes            = new List <string> {
                "foo"
            };

            var oktaClient = new OktaClient(configuration);
            var logger     = Substitute.For <ILogger>();

            var resourceFactory = new ResourceFactory(oktaClient, logger);
            var tokenProvider   = new DefaultOAuthTokenProvider(configuration, resourceFactory, httpClient);

            var token = await tokenProvider.GetAccessTokenAsync();

            token.Should().Be("foo");
        }
        public async Task NotRetryRequestOnceWhenResponseIsNot401AndAuthorizationModeIsPrivateKeyAsync(HttpStatusCode statusCode)
        {
            var requestMessageHandler = new MockHttpMessageHandler(string.Empty, statusCode);
            var httpClientRequest     = new HttpClient(requestMessageHandler);

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = TestCryptoKeys.GetMockRSAPrivateKeyConfiguration();
            configuration.Scopes            = new List <string> {
                "foo"
            };

            var oktaClient = new OktaClient(configuration);
            var logger     = Substitute.For <ILogger>();

            var resourceFactory = new ResourceFactory(oktaClient, logger);

            var tokenResponse       = @"{""token_type"":""Bearer"",""expires_in"":3600,""access_token"":""foo"",""scope"":""okta.users.read okta.users.manage""}";
            var tokenMessageHandler = new MockHttpMessageHandler(tokenResponse, HttpStatusCode.OK);
            var httpClientToken     = new HttpClient(tokenMessageHandler);
            var tokenProvider       = new DefaultOAuthTokenProvider(configuration, resourceFactory, httpClientToken);

            var requestExecutor = new DefaultRequestExecutor(configuration, httpClientRequest, logger, new NoRetryStrategy(), tokenProvider);

            var response = await requestExecutor.GetAsync("foo", null, default(CancellationToken));

            response.StatusCode.Should().Be((int)statusCode);
            tokenMessageHandler.NumberOfCalls.Should().Be(1);
            requestMessageHandler.NumberOfCalls.Should().Be(1);
        }
        public void FailForUnsupportedKty(string kty)
        {
            var mockPrivateKeyConfiguration = TestCryptoKeys.GetMockRSAPrivateKeyConfiguration();

            mockPrivateKeyConfiguration.Kty = kty;

            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = mockPrivateKeyConfiguration;
            configuration.Scopes            = new List <string> {
                "foo"
            };

            Action action = () => new DefaultJwtGenerator(configuration).GenerateSignedJWT();

            action.Should().Throw <NotSupportedException>();
        }