Skip to content

Commit

Permalink
[OASv3] - OAuth for Okta (#753)
Browse files Browse the repository at this point in the history
* wip - oauth for okta

* fix unit test failure

* fix unit test failure
  • Loading branch information
arvindkrishnakumar-okta authored Aug 25, 2022
1 parent 361e42a commit 11657ec
Show file tree
Hide file tree
Showing 8 changed files with 1,036 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
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.OAuth2ClientCredentials;
import com.okta.sdk.impl.util.ConfigUtil;
import com.okta.sdk.impl.util.DefaultBaseUrlResolver;
import org.apache.http.HttpHost;
Expand Down Expand Up @@ -73,7 +76,11 @@
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Arrays;
Expand Down Expand Up @@ -117,6 +124,8 @@ public class DefaultClientBuilder implements ClientBuilder {

private ClientConfiguration clientConfig = new ClientConfiguration();

private AccessTokenRetrieverService accessTokenRetrieverService;

public DefaultClientBuilder() {
this(new DefaultResourceFactory());
}
Expand Down Expand Up @@ -272,21 +281,57 @@ public ApiClient build() {
this.clientConfig.setBaseUrlResolver(new DefaultBaseUrlResolver(this.clientConfig.getBaseUrl()));
}

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 apiClient = new ApiClient(restTemplate(this.clientConfig));
apiClient.setBasePath(this.clientConfig.getBaseUrl());
apiClient.setApiKey((String) this.clientConfig.getClientCredentialsResolver().getClientCredentials().getCredentials());
// for beta release, we support only SSWS, OAuth2 support planned to be added in later release
apiClient.setApiKeyPrefix("SSWS");

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.setBasePath(this.clientConfig.getBaseUrl());
apiClient.setApiKeyPrefix("SSWS");
apiClient.setApiKey((String) this.clientConfig.getClientCredentialsResolver().getClientCredentials().getCredentials());
} else {
this.clientConfig.setAuthenticationScheme(AuthenticationScheme.OAUTH2_PRIVATE_KEY);

validateOAuth2ClientConfig(this.clientConfig);

accessTokenRetrieverService = new AccessTokenRetrieverServiceImpl(clientConfig, apiClient);

OAuth2ClientCredentials oAuth2ClientCredentials =
new OAuth2ClientCredentials(accessTokenRetrieverService);

this.clientConfig.setClientCredentialsResolver(new DefaultClientCredentialsResolver(oAuth2ClientCredentials));
}

return apiClient;
}

/**
* @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();
Assert.hasText(privateKey, "privateKey cannot be null (either PEM file path (or) full PEM content must be supplied)");

if (!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 RestTemplate restTemplate(ClientConfiguration clientConfig) {

ObjectMapper objectMapper = new ObjectMapper();
Expand Down Expand Up @@ -460,6 +505,10 @@ public ClientBuilder setKid(String kid) {
return this;
}

boolean isOAuth2Flow() {
return this.getClientConfiguration().getAuthorizationMode() == AuthorizationMode.PRIVATE_KEY;
}

public ClientConfiguration getClientConfiguration() {
return clientConfig;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Copyright 2020-Present 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.oauth2;

import java.io.IOException;
import java.security.InvalidKeyException;

/**
* Abstraction for OAuth2 access token retrieval service function.
*
* @since 1.6.0
*/
public interface AccessTokenRetrieverService {
/**
* Obtain OAuth2 access token from Authorization Server endpoint.
*
* @return {@link OAuth2AccessToken}
* @throws IOException if problems are encountered extracting the input private key
* @throws InvalidKeyException if supplied private key is invalid
* @throws OAuth2TokenRetrieverException if token could not be retrieved
*/
OAuth2AccessToken getOAuth2AccessToken() throws IOException, InvalidKeyException, OAuth2TokenRetrieverException;
}
Loading

0 comments on commit 11657ec

Please sign in to comment.