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.");
        }
예제 #2
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OktaClient"/> class.
        /// </summary>
        /// <param name="apiClientConfiguration">
        /// The client configuration. If <c>null</c>, the library will attempt to load
        /// configuration from an <c>okta.yaml</c> file or environment variables.
        /// </param>
        /// <param name="logger">The logging interface to use, if any.</param>
        /// <param name="serializer">The JSON serializer to use, if any. Using the <c>DefaultSerializer</c> is still strongly recommended since it has all the behavior this SDK needs to work properly.
        /// If a custom serializer is used, the developer is responsible to add the required logic for this SDK to continue working properly. See <see cref="DefaultSerializer"/> to check out what can be configured.
        /// </param>
        public OktaClient(OktaClientConfiguration apiClientConfiguration = null, ILogger logger = null, ISerializer serializer = null)
        {
            Configuration = GetConfigurationOrDefault(apiClientConfiguration);
            OktaClientConfigurationValidator.Validate(Configuration);

            logger     = logger ?? NullLogger.Instance;
            serializer = serializer ?? new DefaultSerializer();

            var defaultClient = DefaultHttpClient.Create(
                Configuration.ConnectionTimeout,
                Configuration.Proxy,
                logger);

            var resourceFactory = new ResourceFactory(this, logger);
            IOAuthTokenProvider oAuthTokenProvider = (Configuration.AuthorizationMode == AuthorizationMode.PrivateKey) ? new DefaultOAuthTokenProvider(Configuration, resourceFactory, logger: logger) : NullOAuthTokenProvider.Instance;
            var requestExecutor = new DefaultRequestExecutor(Configuration, defaultClient, logger, oAuthTokenProvider: oAuthTokenProvider);

            _dataStore = new DefaultDataStore(
                requestExecutor,
                serializer,
                resourceFactory,
                logger);

            PayloadHandler.TryRegister <PkixCertPayloadHandler>();
            PayloadHandler.TryRegister <PemFilePayloadHandler>();
            PayloadHandler.TryRegister <X509CaCertPayloadHandler>();
        }
        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 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>();
        }
예제 #5
0
        private static IDataStore PrepareIDataStore(OktaClientConfiguration apiClientConfiguration)
        {
            OktaClientConfiguration oktaClientConfiguration = PrepareOktaClientConfiguration(apiClientConfiguration);

            Microsoft.Extensions.Logging.ILogger logger = Microsoft.Extensions.Logging.Abstractions.NullLogger.Instance;

            HttpClient httpClient = DefaultHttpClient.Create(
                oktaClientConfiguration.ConnectionTimeout,
                oktaClientConfiguration.Proxy,
                logger);

            AbstractResourceTypeResolverFactory resourceTypeResolverFactory = null;
            BaseOktaClient baseOktaClient  = new BaseOktaClient();
            dynamic        resourceFactory = new ResourceFactory(baseOktaClient, logger, resourceTypeResolverFactory);
            var            requestExecutor = new DefaultRequestExecutor(oktaClientConfiguration, httpClient, logger);

            UserAgentBuilder userAgentBuilder = new UserAgentBuilder(
                "custom", typeof(CustomAuthnClient).GetTypeInfo().Assembly.GetName().Version);

            IDataStore dataStore = new DefaultDataStore(
                requestExecutor,
                new DefaultSerializer(),
                resourceFactory,
                logger,
                userAgentBuilder);

            return(dataStore);
        }
예제 #6
0
        private static OktaClientConfiguration GetConfigurationOrDefault(OktaClientConfiguration apiClientConfiguration = null)
        {
            string configurationFileRoot = Directory.GetCurrentDirectory();

            var homeOktaYamlLocation = HomePath.Resolve("~", ".okta", "okta.yaml");

            var applicationAppSettingsLocation = Path.Combine(configurationFileRoot ?? string.Empty, "appsettings.json");
            var applicationOktaYamlLocation    = Path.Combine(configurationFileRoot ?? string.Empty, "okta.yaml");

            var configBuilder = new ConfigurationBuilder()
                                .AddYamlFile(homeOktaYamlLocation, optional: true)
                                .AddJsonFile(applicationAppSettingsLocation, optional: true)
                                .AddYamlFile(applicationOktaYamlLocation, optional: true)
                                .AddEnvironmentVariables("okta", "_", root: "okta")
                                .AddEnvironmentVariables("okta_testing", "_", root: "okta")
                                .AddObject(apiClientConfiguration, root: "okta:client")
                                .AddObject(apiClientConfiguration, root: "okta:testing")
                                .AddObject(apiClientConfiguration);

            var compiledConfig = new OktaClientConfiguration();

            configBuilder.Build().GetSection("okta").GetSection("client").Bind(compiledConfig);
            configBuilder.Build().GetSection("okta").GetSection("testing").Bind(compiledConfig);
            configBuilder.Build().Bind(compiledConfig);

            return(compiledConfig);
        }
        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 async Task CallRequestMessageProviderOnPostAsync()
        {
            var httpClientRequest = new HttpClient();
            var configuration     = new OktaClientConfiguration
            {
                OktaDomain = "https://okta.okta.com",
                Token      = "foo",
            };
            var logger = Substitute.For <ILogger>();
            var mockHttpRequestMessageProvider = Substitute.For <IHttpRequestMessageProvider>();

            mockHttpRequestMessageProvider
            .CreateHttpRequestMessage(Arg.Any <HttpRequest>(), Arg.Any <string>())
            .Returns(new HttpRequestMessage());

            var testRequestExecutor = new DefaultRequestExecutor(configuration, httpClientRequest, logger, new NoRetryStrategy(), null, mockHttpRequestMessageProvider);
            var testHttpRequest     = new HttpRequest {
                Uri = "/api/v1"
            };
            await testRequestExecutor.PostAsync(testHttpRequest, CancellationToken.None);

            mockHttpRequestMessageProvider
            .Received(1)
            .CreateHttpRequestMessage(Arg.Is(testHttpRequest), Arg.Is <string>("api/v1"));
        }
        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();
        }
예제 #10
0
        /// <summary>
        /// Initializes a new instance of the <see cref="BaseOktaClient"/> class, called internally from this or any derived class's constructor.
        /// </summary>
        /// <param name="apiClientConfiguration">
        /// The client configuration. If <c>null</c>, the library will attempt to load
        /// configuration from an <c>okta.yaml</c> file or environment variables.
        /// </param>
        /// <param name="httpClient">The HTTP client to use for requests to the Okta API.</param>
        /// <param name="logger">The logging interface to use, if any.</param>
        /// <param name="userAgentBuilder">The builder for the user agent, which would be specific to any derived classes</param>
        /// <param name="resourceTypeResolverFactory">The factory with can resolve and enumerate all Resources in the assembly</param>
        protected BaseOktaClient(
            OktaClientConfiguration apiClientConfiguration,
            HttpClient httpClient,
            ILogger logger,
            UserAgentBuilder userAgentBuilder,
            AbstractResourceTypeResolverFactory resourceTypeResolverFactory)
        {
            Configuration = GetConfigurationOrDefault(apiClientConfiguration);
            OktaClientConfigurationValidator.Validate(Configuration);

            logger = logger ?? NullLogger.Instance;

            httpClient = httpClient ?? DefaultHttpClient.Create(
                Configuration.ConnectionTimeout,
                Configuration.Proxy,
                logger);

            var requestExecutor = new DefaultRequestExecutor(Configuration, httpClient, logger);
            var resourceFactory = new ResourceFactory(this, logger, resourceTypeResolverFactory);

            _dataStore = new DefaultDataStore(
                requestExecutor,
                new DefaultSerializer(),
                resourceFactory,
                logger,
                userAgentBuilder);
        }
예제 #11
0
        public static (IDataStore, OktaClientConfiguration, RequestContext) GetDefaultCustomClientParams(OktaClientConfiguration oktaClientConfiguration)
        {
            OktaClientConfiguration clientConfiguration = PrepareOktaClientConfiguration(oktaClientConfiguration);
            IDataStore     dataStore      = PrepareIDataStore(clientConfiguration);
            RequestContext requestContext = null;

            return(dataStore, clientConfiguration, requestContext);
        }
예제 #12
0
 public TestDefaultRequestExecutor(OktaClientConfiguration configuration, HttpClient httpClient, ILogger logger, IRetryStrategy retryStrategy = null, IOAuthTokenProvider oAuthTokenProvider = null)
 {
     VerbExecutionCounts = new Dictionary <HttpVerb, int>
     {
         { HttpVerb.Get, 0 },
         { HttpVerb.Post, 0 },
         { HttpVerb.Put, 0 },
         { HttpVerb.Delete, 0 },
     };
 }
예제 #13
0
        public void FailIfOktaDomainHasTypo(string oktaDomain)
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain = oktaDomain;

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentException>().Where(e => e.ParamName == nameof(configuration.OktaDomain));
        }
예제 #14
0
        public void NotFailIfOktaDomainIsNotStartingWithHttpsAndDisableHttpsCheckIsTrue(string oktaDomain)
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = oktaDomain;
            configuration.DisableHttpsCheck = true;

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().NotThrow <ArgumentException>();
        }
예제 #15
0
        public void FailIfTokenIsNullOrEmpty(string token)
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain = "https://foo.oktapreview.com";
            configuration.Token      = token;

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentNullException>().Where(e => e.ParamName == nameof(configuration.Token));
        }
예제 #16
0
        public void FailIfOktaDomainContainsAdminKeyword(string oktaDomain)
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain = oktaDomain;
            configuration.Token      = "foo";

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentException>().Where(e => e.ParamName == nameof(configuration.OktaDomain));
        }
예제 #17
0
        public void FailIfOktaDomainIsNotStartingWithHttps(string oktaDomain)
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = oktaDomain;
            configuration.DisableHttpsCheck = false;

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentException>().Where(e => e.ParamName == nameof(configuration.OktaDomain));
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultOAuthTokenProvider"/> class.
        /// </summary>
        /// <param name="configuration">The Okta configuration.</param>
        /// <param name="resourceFactory">The resource factory.</param>
        /// <param name="httpClient">The http client.</param>
        /// <param name="jwtGenerator">The JWT generator.</param>
        /// <param name="logger">The logger.</param>
        public DefaultOAuthTokenProvider(OktaClientConfiguration configuration, ResourceFactory resourceFactory, HttpClient httpClient = null, IJwtGenerator jwtGenerator = null, ILogger logger = null)
        {
            Configuration    = configuration;
            _resourceFactory = resourceFactory;
            _logger          = logger ?? NullLogger.Instance;

            _httpClient             = httpClient ?? new HttpClient();
            _httpClient.BaseAddress = new Uri(Configuration.OktaDomain);
            _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

            _jwtGenerator = jwtGenerator ?? new DefaultJwtGenerator(configuration);
        }
예제 #19
0
        private static void ThrowIfInvalidConfiguration(OktaClientConfiguration configuration)
        {
            if (string.IsNullOrEmpty(configuration.OrgUrl))
            {
                throw new ArgumentNullException(nameof(configuration.OrgUrl), "You must supply an Okta Org URL, like https://dev-12345.oktapreview.com");
            }

            if (string.IsNullOrEmpty(configuration.Token))
            {
                throw new ArgumentNullException(nameof(configuration.Token), "You must supply an Okta API token. You can create one in the Okta developer dashboard.");
            }
        }
예제 #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="AuthenticationClient"/> class using the specified <see cref="HttpClient"/>.
 /// </summary>
 /// <param name="apiClientConfiguration">
 /// The client configuration. If <c>null</c>, the library will attempt to load
 /// configuration from an <c>okta.yaml</c> file or environment variables.
 /// </param>
 /// <param name="httpClient">The HTTP client to use for requests to the Okta API.</param>
 /// <param name="logger">The logging interface to use, if any.</param>
 public AuthenticationClient(
     OktaClientConfiguration apiClientConfiguration = null,
     HttpClient httpClient = null,
     ILogger logger        = null)
     : base(
         apiClientConfiguration,
         httpClient,
         logger,
         new UserAgentBuilder("okta-auth-dotnet", typeof(AuthenticationClient).GetTypeInfo().Assembly.GetName().Version),
         new AbstractResourceTypeResolverFactory(ResourceTypeHelper.GetAllDefinedTypes(typeof(Resource))))
 {
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultRequestExecutor"/> class.
        /// </summary>
        /// <param name="configuration">The client configuration.</param>
        /// <param name="httpClient">The HTTP client to use, if any.</param>
        /// <param name="logger">The logging interface.</param>
        public DefaultRequestExecutor(OktaClientConfiguration configuration, HttpClient httpClient, ILogger logger)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            _oktaDomain = configuration.OktaDomain;
            _logger     = logger;
            _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));

            ApplyDefaultClientSettings(_httpClient, _oktaDomain, configuration);
        }
        public void ThrowForNullScopesWhenAuthorizationModeIsPrivateKey()
        {
            var configuration = new OktaClientConfiguration();

            configuration.OktaDomain        = "https://myOktaDomain.oktapreview.com";
            configuration.AuthorizationMode = AuthorizationMode.PrivateKey;
            configuration.ClientId          = "foo";
            configuration.PrivateKey        = new JsonWebKeyConfiguration();
            configuration.Scopes            = null;

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentNullException>();
        }
예제 #23
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultJwtGenerator"/> class.
        /// </summary>
        /// <param name="configuration">The Okta client configuration.</param>
        public DefaultJwtGenerator(OktaClientConfiguration configuration)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException("The Okta configuration cannot be null.");
            }

            if (!_supportedKeys.Contains(configuration.PrivateKey?.Kty))
            {
                throw new NotSupportedException($"The kty {configuration.PrivateKey?.Kty} is not supported. Use 'EC' or 'RSA'.");
            }

            _configuration = configuration;
        }
        internal static OktaConnectionContext GetConnectionContext(KeyedCollection <string, ConfigParameter> configParameters)
        {
            ProxyConfiguration proxyConfig = null;

            if (!string.IsNullOrWhiteSpace(OktaMAConfigSection.Configuration.ProxyUrl))
            {
                proxyConfig = new ProxyConfiguration()
                {
                    Host = OktaMAConfigSection.Configuration.ProxyUrl
                };
                logger.Info($"Using proxy host {proxyConfig.Host}");
            }

            logger.Info($"Setting up connection to {configParameters[ConfigParameterNames.TenantUrl].Value}");

            System.Net.ServicePointManager.DefaultConnectionLimit = OktaMAConfigSection.Configuration.ConnectionLimit;
            GlobalSettings.ExportThreadCount = OktaMAConfigSection.Configuration.ExportThreads;

            NLog.Extensions.Logging.NLogLoggerProvider f = new NLog.Extensions.Logging.NLogLoggerProvider();
            ILogger nlogger = f.CreateLogger("ext-logger");

            OktaClientConfiguration oktaConfig = new OktaClientConfiguration
            {
                OktaDomain        = configParameters[ConfigParameterNames.TenantUrl].Value,
                Token             = configParameters[ConfigParameterNames.ApiKey].SecureValue.ConvertToUnsecureString(),
                Proxy             = proxyConfig,
                ConnectionTimeout = OktaMAConfigSection.Configuration.HttpClientTimeout,
                MaxRetries        = 8,
            };

            HttpClient httpClient;

            if (OktaMAConfigSection.Configuration.HttpDebugEnabled)
            {
                logger.Warn("WARNING: HTTPS Debugging enabled. Service certificate validation is disabled");

                httpClient = OktaConnectionContext.CreateDebugHttpClient(nlogger, oktaConfig);
            }
            else
            {
                httpClient = DefaultHttpClient.Create(oktaConfig.ConnectionTimeout, proxyConfig, nlogger);
            }

            return(new OktaConnectionContext()
            {
                Client = new OktaClient(oktaConfig, httpClient, nlogger, new DefaultRetryStrategy(oktaConfig.MaxRetries ?? 8, 0, 1))
            });
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultRequestExecutor"/> class.
        /// </summary>
        /// <param name="configuration">The client configuration.</param>
        /// <param name="httpClient">The HTTP client to use, if any.</param>
        /// <param name="logger">The logging interface.</param>
        /// <param name="retryStrategy">The retry strategy interface.</param>
        /// <param name="oAuthTokenProvider">The OAuth token provider interface.</param>
        public DefaultRequestExecutor(OktaClientConfiguration configuration, HttpClient httpClient, ILogger logger, IRetryStrategy retryStrategy = null, IOAuthTokenProvider oAuthTokenProvider = null, IHttpRequestMessageProvider httpRequestMessageProvider = null)
        {
            if (configuration == null)
            {
                throw new ArgumentNullException(nameof(configuration));
            }

            _oktaDomain                 = configuration.OktaDomain;
            _logger                     = logger;
            _httpClient                 = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
            _retryStrategy              = retryStrategy ?? new DefaultRetryStrategy(configuration.MaxRetries.Value, configuration.RequestTimeout.Value);
            _oAuthTokenProvider         = oAuthTokenProvider ?? NullOAuthTokenProvider.Instance;
            _oktaConfiguration          = configuration;
            _httpRequestMessageProvider = httpRequestMessageProvider ?? HttpRequestMessageProvider.Default;
            ApplyDefaultClientSettings(_httpClient, _oktaDomain, configuration);
        }
예제 #26
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OktaClient"/> class using the specified <see cref="HttpClient"/>.
        /// </summary>
        /// <param name="apiClientConfiguration">
        /// The client configuration. If <c>null</c>, the library will attempt to load
        /// configuration from an <c>okta.yaml</c> file or environment variables.
        /// </param>
        /// <param name="httpClient">The HTTP client to use for requests to the Okta API.</param>
        /// <param name="logger">The logging interface to use, if any.</param>
        public OktaClient(OktaClientConfiguration apiClientConfiguration, HttpClient httpClient, ILogger logger = null)
        {
            Configuration = GetConfigurationOrDefault(apiClientConfiguration);
            ThrowIfInvalidConfiguration(Configuration);

            logger = logger ?? NullLogger.Instance;

            var requestExecutor = new DefaultRequestExecutor(Configuration, httpClient, logger);
            var resourceFactory = new ResourceFactory(this, logger);

            _dataStore = new DefaultDataStore(
                requestExecutor,
                new DefaultSerializer(),
                resourceFactory,
                logger);
        }
        public void FailForEmptyOrInvalidClientIdWhenAuthorizationModeIsPrivateKey(string clientId)
        {
            var configuration = new OktaClientConfiguration();

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

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().Throw <ArgumentNullException>();
        }
        public void NotFailWhenValidConfigWhenAuthorizationModeIsPrivateKey()
        {
            var configuration = new OktaClientConfiguration();

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

            Action action = () => OktaClientConfigurationValidator.Validate(configuration);

            action.Should().NotThrow();
        }
예제 #29
0
        /// <summary>
        /// Initializes a new instance of the <see cref="OktaClient"/> class.
        /// </summary>
        /// <param name="apiClientConfiguration">The client configuration.</param>
        /// <param name="logger">The logging interface.</param>
        /// <remarks>
        /// Configuration can also be specified with a YAML file, or by environment variables.
        /// </remarks>
        public OktaClient(OktaClientConfiguration apiClientConfiguration = null, ILogger logger = null)
        {
            var compiled = CompileFromConfigurationSources(apiClientConfiguration);
            var config   = new OktaClientConfiguration();

            compiled.GetSection("okta").GetSection("client").Bind(config);

            ThrowIfInvalidConfiguration(config);
            Configuration = config.DeepClone();

            logger = logger ?? NullLogger.Instance;

            var requestExecutor = new DefaultRequestExecutor(config, logger);
            var resourceFactory = new ResourceFactory(this, logger);

            _dataStore = new DefaultDataStore(requestExecutor, new DefaultSerializer(), resourceFactory, logger);
        }
        /// <summary>
        /// Validates the OktaClient configuration
        /// </summary>
        /// <param name="configuration">The configuration to be validated</param>
        public static void Validate(OktaClientConfiguration configuration)
        {
            if (string.IsNullOrEmpty(configuration.OktaDomain))
            {
                throw new ArgumentNullException(nameof(configuration.OktaDomain), "Your Okta URL is missing. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain");
            }

            configuration.OktaDomain = EnsureTrailingSlash(configuration.OktaDomain);

            if (!configuration.DisableHttpsCheck && !configuration.OktaDomain.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
            {
                throw new ArgumentException($"Your Okta URL must start with https. Current value: {configuration.OktaDomain}. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain", nameof(configuration.OktaDomain));
            }

            if (configuration.OktaDomain.IndexOf("{yourOktaDomain}", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                throw new ArgumentNullException(nameof(configuration.OktaDomain), "Replace {yourOktaDomain} with your Okta domain. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain");
            }

            if (configuration.OktaDomain.IndexOf("-admin.okta.com", StringComparison.OrdinalIgnoreCase) >= 0 ||
                configuration.OktaDomain.IndexOf("-admin.oktapreview.com", StringComparison.OrdinalIgnoreCase) >= 0 ||
                configuration.OktaDomain.IndexOf("-admin.okta-emea.com", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                throw new ArgumentNullException(nameof(configuration.OktaDomain), $"Your Okta domain should not contain -admin. Current value: {configuration.OktaDomain}. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain");
            }

            if (configuration.OktaDomain.IndexOf(".com.com", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                throw new ArgumentNullException(nameof(configuration.OktaDomain), $"It looks like there's a typo in your Okta domain. Current value: {configuration.OktaDomain}. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain");
            }

            if (Regex.Matches(configuration.OktaDomain, "://").Count != 1)
            {
                throw new ArgumentNullException(nameof(configuration.OktaDomain), $"It looks like there's a typo in your Okta domain. Current value: {configuration.OktaDomain}. You can copy your domain from the Okta Developer Console. Follow these instructions to find it: https://bit.ly/finding-okta-domain");
            }

            if (string.IsNullOrEmpty(configuration.Token))
            {
                throw new ArgumentNullException(nameof(configuration.Token), "Your Okta API token is missing. You can generate one in the Okta Developer Console. Follow these instructions: https://bit.ly/get-okta-api-token");
            }

            if (configuration.Token.IndexOf("{apiToken}", StringComparison.OrdinalIgnoreCase) >= 0)
            {
                throw new ArgumentException("Replace {apiToken} with your Okta API token. You can generate one in the Okta Developer Console. Follow these instructions: https://bit.ly/get-okta-api-token", nameof(configuration.Token));
            }
        }