All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.okta.sdk.impl.client.DefaultClientBuilder Maven / Gradle / Ivy

/*
 * Copyright 2014 Stormpath, Inc.
 * Modifications Copyright 2018 Okta, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.okta.sdk.impl.client;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.okta.commons.configcheck.ConfigurationValidator;
import com.okta.commons.http.config.Proxy;
import com.okta.commons.lang.ApplicationInfo;
import com.okta.commons.lang.Assert;
import com.okta.commons.lang.Classes;
import com.okta.commons.lang.Strings;
import com.okta.sdk.authc.credentials.ClientCredentials;
import com.okta.sdk.cache.CacheConfigurationBuilder;
import com.okta.sdk.cache.CacheManager;
import com.okta.sdk.cache.CacheManagerBuilder;
import com.okta.sdk.cache.Caches;
import com.okta.sdk.client.AuthenticationScheme;
import com.okta.sdk.client.AuthorizationMode;
import com.okta.sdk.client.ClientBuilder;
import com.okta.sdk.impl.api.DefaultClientCredentialsResolver;
import com.okta.sdk.impl.config.*;
import com.okta.sdk.impl.deserializer.GroupProfileDeserializer;
import com.okta.sdk.impl.deserializer.UserProfileDeserializer;
import com.okta.sdk.impl.io.ClasspathResource;
import com.okta.sdk.impl.io.DefaultResourceFactory;
import com.okta.sdk.impl.io.Resource;
import com.okta.sdk.impl.io.ResourceFactory;
import com.okta.sdk.impl.oauth2.AccessTokenRetrieverService;
import com.okta.sdk.impl.oauth2.AccessTokenRetrieverServiceImpl;
import com.okta.sdk.impl.oauth2.DPoPInterceptor;
import com.okta.sdk.impl.oauth2.OAuth2ClientCredentials;
import com.okta.sdk.impl.serializer.GroupProfileSerializer;
import com.okta.sdk.impl.serializer.UserProfileSerializer;
import com.okta.sdk.impl.util.ConfigUtil;
import com.okta.sdk.impl.util.DefaultBaseUrlResolver;

import com.okta.sdk.impl.retry.OktaHttpRequestRetryStrategy;
import com.okta.sdk.resource.model.GroupProfile;
import org.apache.hc.client5.http.auth.AuthScope;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
import org.apache.hc.client5.http.impl.DefaultConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
import org.apache.hc.client5.http.impl.classic.DefaultBackoffStrategy;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.impl.DefaultConnectionReuseStrategy;
import org.apache.hc.core5.util.Timeout;

import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;

import com.okta.sdk.resource.client.ApiClient;

import com.okta.sdk.resource.model.UserProfile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.security.PrivateKey;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;

/**
 * 

The default {@link ClientBuilder} implementation. This looks for configuration files * in the following locations and order of precedence (last one wins).

*
    *
  • classpath:com/okta/sdk/config/okta.properties
  • *
  • classpath:com/okta/sdk/config/okta.yaml
  • *
  • classpath:okta.properties
  • *
  • classpath:okta.yaml
  • *
  • ~/.okta/okta.yaml
  • *
  • Environment Variables (with dot notation converted to uppercase + underscores)
  • *
  • System Properties
  • *
  • Programmatically
  • *
* * Please be aware that, in general, loading secrets (such as api-keys or PEM-content) from environment variables * or system properties can lead to those secrets being leaked. * * @since 0.5.0 */ public class DefaultClientBuilder implements ClientBuilder { private static final Logger log = LoggerFactory.getLogger(DefaultClientBuilder.class); private static final String ENVVARS_TOKEN = "envvars"; private static final String SYSPROPS_TOKEN = "sysprops"; private static final String OKTA_CONFIG_CP = "com/okta/sdk/config/"; private static final String OKTA_YAML = "okta.yaml"; private static final String OKTA_PROPERTIES = "okta.properties"; private CacheManager cacheManager; private ClientCredentials clientCredentials; private boolean allowNonHttpsForTesting = false; private final ClientConfiguration clientConfig = new ClientConfiguration(); private AccessTokenRetrieverService accessTokenRetrieverService; public DefaultClientBuilder() { this(new DefaultResourceFactory()); } DefaultClientBuilder(ResourceFactory resourceFactory) { Collection sources = new ArrayList<>(); for (String location : configSources()) { if (ENVVARS_TOKEN.equalsIgnoreCase(location)) { sources.add(EnvironmentVariablesPropertiesSource.oktaFilteredPropertiesSource()); } else if (SYSPROPS_TOKEN.equalsIgnoreCase(location)) { sources.add(SystemPropertiesSource.oktaFilteredPropertiesSource()); } else { Resource resource = resourceFactory.createResource(location); PropertiesSource wrappedSource; if (Strings.endsWithIgnoreCase(location, ".yaml")) { wrappedSource = new YAMLPropertiesSource(resource); } else { wrappedSource = new ResourcePropertiesSource(resource); } PropertiesSource propertiesSource = new OptionalPropertiesSource(wrappedSource); sources.add(propertiesSource); } } Map props = new LinkedHashMap<>(); for (PropertiesSource source : sources) { Map srcProps = source.getProperties(); props.putAll(srcProps); } // check to see if property value is null before setting value // if != null, allow it to override previously set values if (Strings.hasText(props.get(DEFAULT_CLIENT_API_TOKEN_PROPERTY_NAME))) { clientConfig.setApiToken(props.get(DEFAULT_CLIENT_API_TOKEN_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_CACHE_ENABLED_PROPERTY_NAME))) { clientConfig.setCacheManagerEnabled(Boolean.parseBoolean(props.get(DEFAULT_CLIENT_CACHE_ENABLED_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_CACHE_TTL_PROPERTY_NAME))) { clientConfig.setCacheManagerTtl(Long.parseLong(props.get(DEFAULT_CLIENT_CACHE_TTL_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_CACHE_TTI_PROPERTY_NAME))) { clientConfig.setCacheManagerTti(Long.parseLong(props.get(DEFAULT_CLIENT_CACHE_TTI_PROPERTY_NAME))); } for (String prop : props.keySet()) { boolean isPrefix = prop.length() == DEFAULT_CLIENT_CACHE_CACHES_PROPERTY_NAME.length(); if (!isPrefix && prop.startsWith(DEFAULT_CLIENT_CACHE_CACHES_PROPERTY_NAME)) { // get class from prop name String cacheClass = prop.substring(DEFAULT_CLIENT_CACHE_CACHES_PROPERTY_NAME.length() + 1, prop.length() - 4); String cacheTti = props.get(DEFAULT_CLIENT_CACHE_CACHES_PROPERTY_NAME + "." + cacheClass + ".tti"); String cacheTtl = props.get(DEFAULT_CLIENT_CACHE_CACHES_PROPERTY_NAME + "." + cacheClass + ".ttl"); CacheConfigurationBuilder cacheBuilder = Caches.forResource(Classes.forName(cacheClass)); if (Strings.hasText(cacheTti)) { cacheBuilder.withTimeToIdle(Long.parseLong(cacheTti), TimeUnit.SECONDS); } if (Strings.hasText(cacheTtl)) { cacheBuilder.withTimeToLive(Long.parseLong(cacheTtl), TimeUnit.SECONDS); } if (!clientConfig.getCacheManagerCaches().containsKey(cacheClass)) { clientConfig.getCacheManagerCaches().put(cacheClass, cacheBuilder); } } } if (Strings.hasText(props.get(DEFAULT_CLIENT_TESTING_DISABLE_HTTPS_CHECK_PROPERTY_NAME))) { allowNonHttpsForTesting = Boolean.parseBoolean(props.get(DEFAULT_CLIENT_TESTING_DISABLE_HTTPS_CHECK_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_ORG_URL_PROPERTY_NAME))) { String baseUrl = props.get(DEFAULT_CLIENT_ORG_URL_PROPERTY_NAME); // remove backslashes that can end up in file when it's written programmatically, e.g. in a test baseUrl = baseUrl.replace("\\:", ":"); ConfigurationValidator.assertOrgUrl(baseUrl, allowNonHttpsForTesting); clientConfig.setBaseUrl(baseUrl); } if (Strings.hasText(props.get(DEFAULT_CLIENT_CONNECTION_TIMEOUT_PROPERTY_NAME))) { clientConfig.setConnectionTimeout(Integer.parseInt(props.get(DEFAULT_CLIENT_CONNECTION_TIMEOUT_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_AUTHENTICATION_SCHEME_PROPERTY_NAME))) { clientConfig.setAuthenticationScheme(Enum.valueOf(AuthenticationScheme.class, props.get(DEFAULT_CLIENT_AUTHENTICATION_SCHEME_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_PROXY_PORT_PROPERTY_NAME))) { clientConfig.setProxyPort(Integer.parseInt(props.get(DEFAULT_CLIENT_PROXY_PORT_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_PROXY_HOST_PROPERTY_NAME))) { clientConfig.setProxyHost(props.get(DEFAULT_CLIENT_PROXY_HOST_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_PROXY_USERNAME_PROPERTY_NAME))) { clientConfig.setProxyUsername(props.get(DEFAULT_CLIENT_PROXY_USERNAME_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_PROXY_PASSWORD_PROPERTY_NAME))) { clientConfig.setProxyPassword(props.get(DEFAULT_CLIENT_PROXY_PASSWORD_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_AUTHORIZATION_MODE_PROPERTY_NAME))) { clientConfig.setAuthorizationMode(AuthorizationMode.getAuthorizationMode(props.get(DEFAULT_CLIENT_AUTHORIZATION_MODE_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_ID_PROPERTY_NAME))) { clientConfig.setClientId(props.get(DEFAULT_CLIENT_ID_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_SCOPES_PROPERTY_NAME))) { Set scopes = new HashSet<>(Arrays.asList(props.get(DEFAULT_CLIENT_SCOPES_PROPERTY_NAME).split("[\\s,]+"))); clientConfig.setScopes(scopes); } if (Strings.hasText(props.get(DEFAULT_CLIENT_PRIVATE_KEY_PROPERTY_NAME))) { clientConfig.setPrivateKey(props.get(DEFAULT_CLIENT_PRIVATE_KEY_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_OAUTH2_ACCESS_TOKEN_PROPERTY_NAME))) { clientConfig.setOAuth2AccessToken(props.get(DEFAULT_CLIENT_OAUTH2_ACCESS_TOKEN_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_KID_PROPERTY_NAME))) { clientConfig.setKid(props.get(DEFAULT_CLIENT_KID_PROPERTY_NAME)); } if (Strings.hasText(props.get(DEFAULT_CLIENT_REQUEST_TIMEOUT_PROPERTY_NAME))) { clientConfig.setRetryMaxElapsed(Integer.parseInt(props.get(DEFAULT_CLIENT_REQUEST_TIMEOUT_PROPERTY_NAME))); } if (Strings.hasText(props.get(DEFAULT_CLIENT_RETRY_MAX_ATTEMPTS_PROPERTY_NAME))) { clientConfig.setRetryMaxAttempts(Integer.parseInt(props.get(DEFAULT_CLIENT_RETRY_MAX_ATTEMPTS_PROPERTY_NAME))); } } @Override public ClientBuilder setProxy(Proxy proxy) { if (proxy == null) { throw new IllegalArgumentException("proxy argument cannot be null."); } clientConfig.setProxyHost(proxy.getHost()); clientConfig.setProxyPort(proxy.getPort()); clientConfig.setProxyUsername(proxy.getUsername()); clientConfig.setProxyPassword(proxy.getPassword()); return this; } @Override public ClientBuilder setCacheManager(CacheManager cacheManager) { this.cacheManager = cacheManager; return this; } @Override public ClientBuilder setConnectionTimeout(int timeout) { Assert.isTrue(timeout >= 0, "Timeout cannot be a negative number."); this.clientConfig.setConnectionTimeout(timeout); return this; } @Override public ClientBuilder setClientCredentials(ClientCredentials clientCredentials) { Assert.isInstanceOf(ClientCredentials.class, clientCredentials); this.clientCredentials = clientCredentials; return this; } @Override public ClientBuilder setRetryMaxElapsed(int maxElapsed) { this.clientConfig.setRetryMaxElapsed(maxElapsed); return this; } @Override public ClientBuilder setRetryMaxAttempts(int maxAttempts) { this.clientConfig.setRetryMaxAttempts(maxAttempts); return this; } @Override public ApiClient build() { if (!this.clientConfig.isCacheManagerEnabled()) { log.debug("CacheManager disabled. Defaulting to DisabledCacheManager"); this.cacheManager = Caches.newDisabledCacheManager(); } else if (this.cacheManager == null) { log.debug("No CacheManager configured. Defaulting to in-memory CacheManager with default TTL and TTI of five minutes."); CacheManagerBuilder cacheManagerBuilder = Caches.newCacheManager() .withDefaultTimeToIdle(this.clientConfig.getCacheManagerTti(), TimeUnit.SECONDS) .withDefaultTimeToLive(this.clientConfig.getCacheManagerTtl(), TimeUnit.SECONDS); if (this.clientConfig.getCacheManagerCaches().size() > 0) { for (CacheConfigurationBuilder builder : this.clientConfig.getCacheManagerCaches().values()) { cacheManagerBuilder.withCache(builder); } } this.cacheManager = cacheManagerBuilder.build(); } if (this.clientConfig.getBaseUrlResolver() == null) { ConfigurationValidator.assertOrgUrl(this.clientConfig.getBaseUrl(), allowNonHttpsForTesting); this.clientConfig.setBaseUrlResolver(new DefaultBaseUrlResolver(this.clientConfig.getBaseUrl())); } HttpClientBuilder httpClientBuilder = createHttpClientBuilder(clientConfig); if (clientConfig.getProxy() != null) { setProxy(httpClientBuilder, clientConfig); } ApiClient apiClient = new ApiClient(httpClientBuilder.build(), this.cacheManager); apiClient.setBasePath(this.clientConfig.getBaseUrl()); String userAgentValue = ApplicationInfo.get().entrySet().stream() .map(entry -> entry.getKey() + "/" + entry.getValue()) .collect(Collectors.joining(" ")); apiClient.setUserAgent(userAgentValue); addCustomSerializerAndDeserializers(apiClient); if (!isOAuth2Flow()) { if (this.clientConfig.getClientCredentialsResolver() == null && this.clientCredentials != null) { this.clientConfig.setClientCredentialsResolver(new DefaultClientCredentialsResolver(this.clientCredentials)); } else if (this.clientConfig.getClientCredentialsResolver() == null) { this.clientConfig.setClientCredentialsResolver(new DefaultClientCredentialsResolver(this.clientConfig)); } apiClient.setApiKeyPrefix(AuthenticationScheme.SSWS.name()); apiClient.setApiKey((String) this.clientConfig.getClientCredentialsResolver().getClientCredentials().getCredentials()); } else { this.clientConfig.setAuthenticationScheme(AuthenticationScheme.OAUTH2_PRIVATE_KEY); validateOAuth2ClientConfig(this.clientConfig); if (hasAccessToken()) { log.debug("Will use client provided Access token for OAuth2 authentication (private key, if supplied would be ignored)"); apiClient.setAccessToken(this.clientConfig.getOAuth2AccessToken()); } else { log.debug("Will retrieve Access Token automatically from Okta for OAuth2 authentication"); accessTokenRetrieverService = new AccessTokenRetrieverServiceImpl(clientConfig, apiClient); OAuth2ClientCredentials oAuth2ClientCredentials = new OAuth2ClientCredentials(accessTokenRetrieverService); // replace the default OAuth authentication with an auto-refreshing one apiClient.replaceAuthentication("oauth2", oAuth2ClientCredentials); oAuth2ClientCredentials.refreshOAuth2AccessToken(); this.clientConfig.setClientCredentialsResolver(new DefaultClientCredentialsResolver(oAuth2ClientCredentials)); } } return apiClient; } /** * Override to customize the client, allowing one to add additional interceptors. * @param clientConfig the current ClientConfiguration * @return an {@link HttpClientBuilder} initialized with default configuration */ protected HttpClientBuilder createHttpClientBuilder(ClientConfiguration clientConfig) { HttpClientBuilder httpClientBuilder = HttpClients.custom() .setDefaultRequestConfig(createHttpRequestConfigBuilder(clientConfig).build()) .setConnectionManager(createHttpClientConnectionManagerBuilder(clientConfig).build()) .setRetryStrategy(new OktaHttpRequestRetryStrategy(clientConfig.getRetryMaxAttempts())) .setConnectionBackoffStrategy(new DefaultBackoffStrategy()) .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) .setConnectionReuseStrategy(new DefaultConnectionReuseStrategy()) .disableCookieManagement(); if (isOAuth2Flow() && !hasAccessToken()) { httpClientBuilder.addExecInterceptorLast("dpop", new DPoPInterceptor()); } return httpClientBuilder; } /** * Override to customize the request config * @param clientConfig the current clientConfig * @return a {@link RequestConfig.Builder} initialized with default configuration */ protected RequestConfig.Builder createHttpRequestConfigBuilder(ClientConfiguration clientConfig) { return RequestConfig.custom() .setResponseTimeout(Timeout.ofSeconds(clientConfig.getConnectionTimeout())) .setConnectionRequestTimeout(Timeout.ofSeconds(clientConfig.getConnectionTimeout())); } /** * Override to customize the connection manager, allowing the increase of max connections * @param clientConfig the current clientConfig * @return a {@link PoolingHttpClientConnectionManagerBuilder} initialized with default configuration */ protected PoolingHttpClientConnectionManagerBuilder createHttpClientConnectionManagerBuilder(ClientConfiguration clientConfig) { return PoolingHttpClientConnectionManagerBuilder.create() .setDefaultConnectionConfig(ConnectionConfig.custom() .setConnectTimeout(Timeout.ofSeconds(clientConfig.getConnectionTimeout())) .build()); } private void setProxy(HttpClientBuilder clientBuilder, ClientConfiguration clientConfig) { clientBuilder.useSystemProperties(); clientBuilder.setProxy(new HttpHost(clientConfig.getProxyHost(), clientConfig.getProxyPort())); if (clientConfig.getProxyUsername() != null) { final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); AuthScope authScope = new AuthScope(clientConfig.getProxyHost(), clientConfig.getProxyPort()); UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials(clientConfig.getProxyUsername(), clientConfig.getProxyPassword().toCharArray()); credentialsProvider.setCredentials(authScope, usernamePasswordCredentials); clientBuilder.setDefaultCredentialsProvider(credentialsProvider); clientBuilder.setProxyAuthenticationStrategy(new DefaultAuthenticationStrategy()); } } /** * @since 1.6.0 */ private void validateOAuth2ClientConfig(ClientConfiguration clientConfiguration) { Assert.notNull(clientConfiguration.getClientId(), "clientId cannot be null"); Assert.isTrue(clientConfiguration.getScopes() != null && !clientConfiguration.getScopes().isEmpty(), "At least one scope is required"); String privateKey = clientConfiguration.getPrivateKey(); String oAuth2AccessToken = clientConfiguration.getOAuth2AccessToken(); UnaryOperator jwtSigner = clientConfiguration.getJwtSigner(); String jwtSigningAlgorithm = clientConfiguration.getJwtSigningAlgorithm(); Assert.isTrue(Objects.nonNull(privateKey) || Objects.nonNull(oAuth2AccessToken) || Objects.nonNull(jwtSigner) && Objects.nonNull(jwtSigningAlgorithm), "Either Private Key (or) Access Token (or) JWT Signer + Algorithm" + " must be supplied for OAuth2 Authentication mode"); if (Strings.hasText(privateKey) && !ConfigUtil.hasPrivateKeyContentWrapper(privateKey)) { // privateKey is a file path, check if the file exists Path privateKeyPemFilePath; try { privateKeyPemFilePath = Paths.get(privateKey); } catch (InvalidPathException ipe) { throw new IllegalArgumentException("Invalid privateKey file path", ipe); } boolean privateKeyPemFileExists = Files.exists(privateKeyPemFilePath, LinkOption.NOFOLLOW_LINKS); Assert.isTrue(privateKeyPemFileExists, "privateKey file does not exist"); } } private void addCustomSerializerAndDeserializers(ApiClient apiClient) { ObjectMapper mapper = apiClient.getObjectMapper(); SimpleModule module = new SimpleModule(); module.addSerializer(UserProfile.class, new UserProfileSerializer()); module.addDeserializer(UserProfile.class, new UserProfileDeserializer()); module.addSerializer(GroupProfile.class, new GroupProfileSerializer()); module.addDeserializer(GroupProfile.class, new GroupProfileDeserializer()); mapper.registerModule(module); } @Override public ClientBuilder setOrgUrl(String baseUrl) { ConfigurationValidator.assertOrgUrl(baseUrl, allowNonHttpsForTesting); this.clientConfig.setBaseUrl(baseUrl); return this; } @Override public ClientBuilder setAuthorizationMode(AuthorizationMode authorizationMode) { this.clientConfig.setAuthorizationMode(authorizationMode); this.clientConfig.setAuthenticationScheme(authorizationMode.getAuthenticationScheme()); return this; } @Override public ClientBuilder setScopes(Set scopes) { Assert.isTrue(scopes != null && !scopes.isEmpty(), "At least one scope is required"); this.clientConfig.setScopes(scopes); return this; } @Override public ClientBuilder setPrivateKey(String privateKey) { Assert.notNull(privateKey, "Missing privateKey"); this.clientConfig.setPrivateKey(privateKey); return this; } @Override public ClientBuilder setPrivateKey(Path privateKeyPath) { Assert.notNull(privateKeyPath, "Missing privateKeyPath"); this.clientConfig.setPrivateKey(getFileContent(privateKeyPath)); return this; } @Override public ClientBuilder setPrivateKey(InputStream privateKeyStream) { Assert.notNull(privateKeyStream, "Missing privateKeyStream"); this.clientConfig.setPrivateKey(getFileContent(privateKeyStream)); return this; } @Override public ClientBuilder setPrivateKey(PrivateKey privateKey) { Assert.notNull(privateKey, "Missing privateKey"); String algorithm = privateKey.getAlgorithm(); if (algorithm.equals("RSA")) { PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); try { ASN1Primitive primitive = privateKeyInfo.parsePrivateKey().toASN1Primitive(); String encodedString = ConfigUtil.RSA_PRIVATE_KEY_HEADER + "\n" + Base64.getEncoder().encodeToString(primitive.getEncoded()) + "\n" + ConfigUtil.RSA_PRIVATE_KEY_FOOTER; this.clientConfig.setPrivateKey(encodedString); } catch (IOException e) { throw new IllegalArgumentException("Could not parse private key"); } } else if(algorithm.equals("EC")) { String encodedString = ConfigUtil.EC_PRIVATE_KEY_HEADER + "\n" + Base64.getEncoder().encodeToString(privateKey.getEncoded()) + "\n" + ConfigUtil.EC_PRIVATE_KEY_FOOTER; this.clientConfig.setPrivateKey(encodedString); } else { throw new IllegalArgumentException("Supplied privateKey is not an RSA or EC key - " + algorithm); } return this; } private String getFileContent(File file) { try (InputStream inputStream = Files.newInputStream(file.toPath())) { return readFromInputStream(inputStream); } catch (IOException e) { throw new IllegalArgumentException("Could not read from supplied private key file"); } } private String getFileContent(Path path) { Assert.notNull(path, "The path to the privateKey cannot be null."); return getFileContent(path.toFile()); } private String getFileContent(InputStream privateKeyStream) { try { return readFromInputStream(privateKeyStream); } catch (IOException e) { throw new IllegalArgumentException("Could not read from supplied privateKey input stream"); } } private String readFromInputStream(InputStream inputStream) throws IOException { Assert.notNull(inputStream, "InputStream cannot be null."); StringBuilder resultStringBuilder = new StringBuilder(); try (BufferedReader br = new BufferedReader(new InputStreamReader( inputStream, StandardCharsets.UTF_8))) { String line; while ((line = br.readLine()) != null) { resultStringBuilder.append(line).append("\n"); } } return resultStringBuilder.toString(); } @Override public ClientBuilder setCustomJwtSigner(UnaryOperator jwtSigner, String algorithm) { Assert.notNull(jwtSigner, "jwtSigner cannot be null."); Assert.notNull(algorithm, "algorithm cannot be null."); clientConfig.setJwtSigner(jwtSigner, algorithm); return this; } @Override public ClientBuilder setClientId(String clientId) { ConfigurationValidator.assertClientId(clientId); this.clientConfig.setClientId(clientId); return this; } @Override public ClientBuilder setOAuth2AccessToken(String oAuth2AccessToken) { Assert.notNull(oAuth2AccessToken, "oAuth2AccessToken cannot be null."); this.clientConfig.setOAuth2AccessToken(oAuth2AccessToken); return this; } @Override public ClientBuilder setKid(String kid) { Assert.notNull(kid, "kid cannot be null."); this.clientConfig.setKid(kid); return this; } boolean isOAuth2Flow() { return this.getClientConfiguration().getAuthorizationMode() == AuthorizationMode.PRIVATE_KEY; } private boolean hasAccessToken() { return Strings.hasText(this.clientConfig.getOAuth2AccessToken()); } public ClientConfiguration getClientConfiguration() { return clientConfig; } private static String[] configSources() { // lazy load the config sources as the user.home system prop could change for testing return new String[] { ClasspathResource.SCHEME_PREFIX + OKTA_CONFIG_CP + OKTA_PROPERTIES, ClasspathResource.SCHEME_PREFIX + OKTA_CONFIG_CP + OKTA_YAML, ClasspathResource.SCHEME_PREFIX + OKTA_PROPERTIES, ClasspathResource.SCHEME_PREFIX + OKTA_YAML, System.getProperty("user.home") + File.separatorChar + ".okta" + File.separatorChar + OKTA_YAML, ENVVARS_TOKEN, SYSPROPS_TOKEN }; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy