diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml new file mode 100644 index 0000000..b880b6c --- /dev/null +++ b/.github/workflows/pull_request.yaml @@ -0,0 +1,18 @@ +name: PR Build and Test + +on: + pull_request + +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Set up JDK 14 + uses: actions/setup-java@v1 + with: + java-version: 14 + java-package: jdk+fx + architecture: x64 + - name: Run package + run: mvn --batch-mode --update-snapshots verify diff --git a/.idea/.name b/.idea/.name deleted file mode 100644 index 94579e6..0000000 --- a/.idea/.name +++ /dev/null @@ -1 +0,0 @@ -okta-aws-cli \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml index b26911b..fade66b 100644 --- a/.idea/encodings.xml +++ b/.idea/encodings.xml @@ -2,5 +2,6 @@ + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 0000000..7f0aa78 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index a59d74b..a268c13 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -11,4 +11,4 @@ - \ No newline at end of file + diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..cb1ba7f --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Readme.MD b/Readme.MD index ac0057b..719c6a0 100644 --- a/Readme.MD +++ b/Readme.MD @@ -153,7 +153,7 @@ Here is the list of parameters that can be environment variables or settings in - ```OKTA_ENV_MODE``` set to **true** to run sub-command with **AWS_ACCESS_KEY_ID**, **AWS_SECRET_ACCESS_KEY**, and **AWS_SESSION_TOKEN** env vars set. Temporary credentials are shared in memory and kept off disk in this mode. (default: **false**) - ```OKTA_BROWSER_AUTH``` set to **true** to use integrated web browser for authentication (default: **false**) - ```OKTA_COOKIES_PATH``` is directory path to store cookies.properties for Okta. This is particularly useful when running this tool in many concurrent processes like you might with **OKTA_ENV_MODE** (default: ~/.okta) - - ```OKTA_PROFILE``` is the name of the AWS profile to create/reuse. May also be specified on the commandline by ```--profile```. (default: get AWS profile name based on per-session STS user name) + - ```OKTA_PROFILE``` is the name of the AWS profile to create/reuse. (default: get AWS profile name based on per-session STS user name) - ```OKTA_AWS_REGION``` is the default AWS region to store with the created profile. - ```OKTA_AWS_ROLE_TO_ASSUME``` is the IAM Role ARN to use. If present will try to match okta account's retrieved role list and use it. Will still prompt if no match found. (ex: **arn:aws:iam::123456789012:role/EC2-Admins**) - ```OKTA_STS_DURATION``` is the duration the role will be assumed, in seconds. The maximum session duration allowed by AWS is 12 hours and this needs to be set on the role as well. Defaults to 1hr. diff --git a/THIRD_PARTY_NOTICES b/THIRD_PARTY_NOTICES index d37fa62..4fd11c4 100644 --- a/THIRD_PARTY_NOTICES +++ b/THIRD_PARTY_NOTICES @@ -1,6 +1,6 @@ This document contains third party open source licenses and notices for the Okta AWS CLI Assume Role Tool product. Certain licenses and notices may appear in other parts of the product in accordance with the applicable license requirements. -The Okta product that this document references does not necessarily use all the open source software packages referred to below and may also only use portions of a given package. +The Okta product that this document references does not necessarily use all the open source software packages referred to below and may also only use portions of a given package. Third Party Notices ------------------- @@ -39,7 +39,7 @@ See Open Source Licenses below for complete copy of the Apache 2.0 license AWS Java SDK Version (if any): -1.11.515 +2.15.69 https://github.com/aws/aws-sdk-java-v2/tree/2.15.69 Brief Description: The AWS SDK for Java enables Java developers to easily work with Amazon Web Services and build scalable solutions with Amazon S3, Amazon @@ -47,11 +47,7 @@ DynamoDB, Amazon Glacier, and more. AWS SDK for Java -Copyright 2010-2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. - -This product includes software developed by Amazon Technologies, Inc (http://www.amazon.com/). - -See Open Source Licenses below for complete copy of the Apache 2.0 license +https://github.com/aws/aws-sdk-java-v2/blob/2.15.69/LICENSE.txt ------------------- @@ -562,10 +558,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI Disclaimer and Limitation of Liability -Disclaimer. OKTA AND ITS SUPPLIERS HEREBY DISCLAIM ALL (AND HAVE NOT AUTHORIZED ANYONE TO MAKE ANY) WARRANTIES EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF NON-INFRINGEMENT OF THIRD PARTY RIGHTS WITH RESPECT TO OPEN SOURCE SOFTWARE, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE PARTIES ARE NOT RELYING AND HAVE NOT RELIED ON ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER REGARDING OKTA AND OKTA MAKES NO WARRANTY REGARDING ANY THIRD PARTY SOFTWARE. +Disclaimer. OKTA AND ITS SUPPLIERS HEREBY DISCLAIM ALL (AND HAVE NOT AUTHORIZED ANYONE TO MAKE ANY) WARRANTIES EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF NON-INFRINGEMENT OF THIRD PARTY RIGHTS WITH RESPECT TO OPEN SOURCE SOFTWARE, TITLE, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE PARTIES ARE NOT RELYING AND HAVE NOT RELIED ON ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER REGARDING OKTA AND OKTA MAKES NO WARRANTY REGARDING ANY THIRD PARTY SOFTWARE. -Limitation of Liability. OKTA AND ITS SUPPLIERS, SHALL NOT BE RESPONSIBLE OR LIABLE UNDER ANY CONTRACT, NEGLIGENCE, STRICT LIABILITY OR OTHER THEORY ARISING OUT OF OR RELATED TO OPEN SOURCE SOFWARE (A) FOR ERROR OR INTERRUPTION OF USE, LOSS OR INACCURACY OR CORRUPTION OF DATA, (B) FOR COST OF PROCUREMENT OF SUBSTITUTE GOODS, SERVICES, RIGHTS, OR TECHNOLOGY, (C) FOR ANY LOST PROFITS OR REVENUES, OR FOR ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES, WHETHER OR NOT A OKTA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -IN NO EVENT WILL OKTA NOR ITS SUPPLIER’S AGGREGATE AND CUMULATIVE LIABILITY FOR ANY CLAIMS ARISING OUT OF OR RELATED TO OPEN SOURCE SOFTWARE EXCEED ONE HUNDRED DOLLARS ($100). +Limitation of Liability. OKTA AND ITS SUPPLIERS, SHALL NOT BE RESPONSIBLE OR LIABLE UNDER ANY CONTRACT, NEGLIGENCE, STRICT LIABILITY OR OTHER THEORY ARISING OUT OF OR RELATED TO OPEN SOURCE SOFWARE (A) FOR ERROR OR INTERRUPTION OF USE, LOSS OR INACCURACY OR CORRUPTION OF DATA, (B) FOR COST OF PROCUREMENT OF SUBSTITUTE GOODS, SERVICES, RIGHTS, OR TECHNOLOGY, (C) FOR ANY LOST PROFITS OR REVENUES, OR FOR ANY INDIRECT, SPECIAL, INCIDENTAL, CONSEQUENTIAL OR PUNITIVE DAMAGES, WHETHER OR NOT A OKTA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +IN NO EVENT WILL OKTA NOR ITS SUPPLIER’S AGGREGATE AND CUMULATIVE LIABILITY FOR ANY CLAIMS ARISING OUT OF OR RELATED TO OPEN SOURCE SOFTWARE EXCEED ONE HUNDRED DOLLARS ($100). Any provisions provided by Okta which differ from those in any third party license are provided by Okta alone. diff --git a/bin/install.sh b/bin/install.sh index 7085d40..7020b0e 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -132,22 +132,14 @@ mkdir -p "${PREFIX}/bin" # Create withokta command cat <"${PREFIX}/bin/withokta" #!/bin/bash -command="\$1" -profile=\$2 -shift; -shift; -if [ "$1" == "logout" ] -then - command="logout" -fi if [ -n "\$https_proxy" ]; then readonly URI_REGEX='^(([^:/?#]+):)?(//((([^:/?#]+)@)?([^:/?#]+)(:([0-9]+))?))?(/([^?#]*))(\?([^#]*))?(#(.*))?' [[ \$https_proxy =~ \${URI_REGEX} ]] && PROXY_CONFIG="-Dhttps.proxyHost=\${BASH_REMATCH[7]} -Dhttps.proxyPort=\${BASH_REMATCH[9]}" fi -env OKTA_PROFILE=\$profile java \${PROXY_CONFIG} \\ +java \${PROXY_CONFIG} \\ -Djava.util.logging.config.file=${PREFIX}/logging.properties \\ -classpath ${PREFIX}/okta-aws-cli.jar \\ - com.okta.tools.WithOkta \$command "\$@" + com.okta.tools.WithOkta \$@ EOF chmod +x "${PREFIX}/bin/withokta" diff --git a/pom.xml b/pom.xml index 84b9353..e190f0a 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.okta.developer okta-aws-cli - 2.0.5 + 3.0.0-SNAPSHOT jar @@ -33,28 +33,37 @@ UTF-8 - 1.11.515 - 1.2.0 - 20180813 + 2.15.69 + 20200518 2.7 4.5.13 5.4.0 0.5.4 1.11.3 - 3.4.2 + 3.4.5 1.7.26 12.0.1 - com.amazonaws - aws-java-sdk-core + software.amazon.awssdk + protocol-core ${aws-java-sdk.version} - com.amazonaws - aws-java-sdk-sts + software.amazon.awssdk + aws-json-protocol + ${aws-java-sdk.version} + + + software.amazon.awssdk + iam + ${aws-java-sdk.version} + + + software.amazon.awssdk + sts ${aws-java-sdk.version} @@ -188,7 +197,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.0 + 3.2.4 package diff --git a/src/main/java/com/okta/tools/AWSCredentialsUtil.java b/src/main/java/com/okta/tools/AWSCredentialsUtil.java index 2be0470..d0ceac5 100644 --- a/src/main/java/com/okta/tools/AWSCredentialsUtil.java +++ b/src/main/java/com/okta/tools/AWSCredentialsUtil.java @@ -18,28 +18,26 @@ import java.io.IOException; import java.time.Instant; -import com.amazonaws.auth.AWSCredentials; -import com.amazonaws.auth.AWSSessionCredentials; -import com.amazonaws.auth.BasicSessionCredentials; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLResult; -import com.amazonaws.services.securitytoken.model.Credentials; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlResponse; +import software.amazon.awssdk.services.sts.model.Credentials; public interface AWSCredentialsUtil { - static AWSCredentials getAWSCredential() throws IOException, InterruptedException { - AssumeRoleWithSAMLResult samlResult = OktaAwsCliAssumeRole.withEnvironment(OktaAwsConfig.loadEnvironment()).getAssumeRoleWithSAMLResult(Instant.now()); + static AwsSessionCredentials getAWSCredential() throws IOException, InterruptedException { + AssumeRoleWithSamlResponse samlResult = OktaAwsCliAssumeRole.withEnvironment(OktaAwsConfig.loadEnvironment()).getAssumeRoleWithSAMLResult(Instant.now()); - Credentials credentials = samlResult.getCredentials(); + Credentials credentials = samlResult.credentials(); - return new BasicSessionCredentials(credentials.getAccessKeyId(), credentials.getSecretAccessKey(), credentials.getSessionToken()); + return AwsSessionCredentials.create(credentials.accessKeyId(), credentials.secretAccessKey(), credentials.sessionToken()); } - - static AWSSessionCredentials getAWSCredential (OktaAwsCliEnvironment environment) throws IOException, InterruptedException { - AssumeRoleWithSAMLResult samlResult = OktaAwsCliAssumeRole.withEnvironment(environment).getAssumeRoleWithSAMLResult(Instant.now()); - - Credentials credentials = samlResult.getCredentials(); - - return new BasicSessionCredentials(credentials.getAccessKeyId(), credentials.getSecretAccessKey(), credentials.getSessionToken()); + + static AwsSessionCredentials getAWSCredential (OktaAwsCliEnvironment environment) throws IOException, InterruptedException { + AssumeRoleWithSamlResponse samlResult = OktaAwsCliAssumeRole.withEnvironment(environment).getAssumeRoleWithSAMLResult(Instant.now()); + + Credentials credentials = samlResult.credentials(); + + return AwsSessionCredentials.create(credentials.accessKeyId(), credentials.secretAccessKey(), credentials.sessionToken()); } } diff --git a/src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java b/src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java index 04ed6df..79c763d 100644 --- a/src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java +++ b/src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java @@ -20,21 +20,21 @@ import java.time.temporal.ChronoUnit; import java.util.Optional; -import com.amazonaws.services.securitytoken.model.Credentials; import com.okta.tools.authentication.*; import com.okta.tools.helpers.*; import com.okta.tools.saml.OktaAppClient; import com.okta.tools.saml.OktaAppClientImpl; import org.apache.commons.lang.StringUtils; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLRequest; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLResult; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlRequest; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlResponse; import com.okta.tools.models.Profile; import com.okta.tools.models.Session; import com.okta.tools.saml.OktaSaml; +import software.amazon.awssdk.services.sts.model.Credentials; final class OktaAwsCliAssumeRole { - private OktaAwsCliEnvironment environment; + final private OktaAwsCliEnvironment environment; private SessionHelper sessionHelper; private RoleHelper roleHelper; @@ -103,10 +103,10 @@ RunResult run(Instant startInstant) throws IOException, InterruptedException { RunResult runResult = new RunResult(); runResult.profileName = profileSAMLResult.profileName; - Credentials credentials = profileSAMLResult.assumeRoleWithSAMLResult.getCredentials(); - runResult.accessKeyId = credentials.getAccessKeyId(); - runResult.secretAccessKey = credentials.getSecretAccessKey(); - runResult.sessionToken = credentials.getSessionToken(); + Credentials credentials = profileSAMLResult.assumeRoleWithSAMLResult.credentials(); + runResult.accessKeyId = credentials.accessKeyId(); + runResult.secretAccessKey = credentials.secretAccessKey(); + runResult.sessionToken = credentials.sessionToken(); return runResult; } @@ -118,7 +118,7 @@ class RunResult { String sessionToken; } - AssumeRoleWithSAMLResult getAssumeRoleWithSAMLResult(Instant startInstant) throws IOException, InterruptedException { + AssumeRoleWithSamlResponse getAssumeRoleWithSAMLResult(Instant startInstant) throws IOException, InterruptedException { init(); environment.awsRoleToAssume = currentProfile.map(profile1 -> profile1.roleArn).orElse(environment.awsRoleToAssume); @@ -130,9 +130,9 @@ AssumeRoleWithSAMLResult getAssumeRoleWithSAMLResult(Instant startInstant) throw private ProfileSAMLResult doRequest(Instant startInstant) throws IOException, InterruptedException { String samlResponse = oktaSaml.getSamlResponse(); - AssumeRoleWithSAMLRequest assumeRequest = roleHelper.chooseAwsRoleToAssume(samlResponse); - Instant sessionExpiry = startInstant.plus((long) assumeRequest.getDurationSeconds() - (long) 30, ChronoUnit.SECONDS); - AssumeRoleWithSAMLResult assumeResult = roleHelper.assumeChosenAwsRole(assumeRequest); + AssumeRoleWithSamlRequest assumeRequest = roleHelper.chooseAwsRoleToAssume(samlResponse); + Instant sessionExpiry = startInstant.plus((long) assumeRequest.durationSeconds() - (long) 30, ChronoUnit.SECONDS); + AssumeRoleWithSamlResponse assumeResult = roleHelper.assumeChosenAwsRole(assumeRequest); String profileName = profileHelper.getProfileName(assumeResult); if (!environment.oktaEnvMode) { @@ -143,19 +143,19 @@ private ProfileSAMLResult doRequest(Instant startInstant) throws IOException, In return new ProfileSAMLResult(assumeResult, profileName); } - private void updateConfig(AssumeRoleWithSAMLRequest assumeRequest, Instant sessionExpiry, String profileName) throws IOException { + private void updateConfig(AssumeRoleWithSamlRequest assumeRequest, Instant sessionExpiry, String profileName) throws IOException { environment.oktaProfile = profileName; - environment.awsRoleToAssume = assumeRequest.getRoleArn(); + environment.awsRoleToAssume = assumeRequest.roleArn(); sessionHelper.addOrUpdateProfile(sessionExpiry); sessionHelper.updateCurrentSession(sessionExpiry, profileName); } // Holds the values for the profile name and SAML result shared by CLI and SDK implementations - private class ProfileSAMLResult { + static private class ProfileSAMLResult { String profileName; - AssumeRoleWithSAMLResult assumeRoleWithSAMLResult; + AssumeRoleWithSamlResponse assumeRoleWithSAMLResult; - ProfileSAMLResult(AssumeRoleWithSAMLResult pAssumeRoleWithSAMLResult, String pProfileName) { + ProfileSAMLResult(AssumeRoleWithSamlResponse pAssumeRoleWithSAMLResult, String pProfileName) { assumeRoleWithSAMLResult = pAssumeRoleWithSAMLResult; profileName = pProfileName; } diff --git a/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java b/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java index 7c8284e..977d1df 100644 --- a/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java +++ b/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java @@ -15,6 +15,8 @@ */ package com.okta.tools; +import software.amazon.awssdk.regions.Region; + public class OktaAwsCliEnvironment { public final boolean browserAuth; public final String oktaOrg; @@ -28,7 +30,7 @@ public class OktaAwsCliEnvironment { public String awsRoleToAssume; public int stsDuration; - public final String awsRegion; + public final Region awsRegion; public final String oktaMfaChoice; public boolean oktaEnvMode; @@ -42,7 +44,7 @@ public OktaAwsCliEnvironment() public OktaAwsCliEnvironment(boolean browserAuth, String oktaOrg, String oktaUsername, InterruptibleSupplier oktaPassword, String oktaCookiesPath, String oktaProfile, String oktaAwsAppUrl, String awsRoleToAssume, - int stsDuration, String awsRegion, + int stsDuration, Region awsRegion, String oktaMfaChoice, boolean oktaEnvMode, String oktaIgnoreSaml) { this.browserAuth = browserAuth; this.oktaOrg = oktaOrg; diff --git a/src/main/java/com/okta/tools/OktaAwsConfig.java b/src/main/java/com/okta/tools/OktaAwsConfig.java index 39a6f48..f404c68 100644 --- a/src/main/java/com/okta/tools/OktaAwsConfig.java +++ b/src/main/java/com/okta/tools/OktaAwsConfig.java @@ -17,9 +17,9 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.SystemUtils; +import software.amazon.awssdk.regions.Region; import java.io.*; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -162,7 +162,7 @@ private static Integer getStsDurationOrDefault(String stsDuration) { return (stsDuration == null) ? 3600 : Integer.parseInt(stsDuration); } - private static String getAwsRegionOrDefault(String region) { - return (region == null) ? "us-east-1" : region; + private static Region getAwsRegionOrDefault(String region) { + return Region.of((region == null) ? "us-east-1" : region); } } diff --git a/src/main/java/com/okta/tools/WithOkta.java b/src/main/java/com/okta/tools/WithOkta.java index b93f4d7..8e49d12 100644 --- a/src/main/java/com/okta/tools/WithOkta.java +++ b/src/main/java/com/okta/tools/WithOkta.java @@ -16,15 +16,13 @@ package com.okta.tools; import java.time.Instant; -import java.util.ArrayList; -import java.util.List; import java.util.Map; import java.util.logging.Logger; public class WithOkta { private static final Logger logger = Logger.getLogger(WithOkta.class.getName()); - public static void main(String[] args) throws Exception { + public static void main(final String[] args) throws Exception { if (LogoutHandler.handleLogout(args)) return; OktaAwsCliEnvironment environment = OktaAwsConfig.loadEnvironment(); OktaAwsCliAssumeRole.RunResult runResult = OktaAwsCliAssumeRole.withEnvironment(environment).run(Instant.now()); @@ -34,9 +32,7 @@ public static void main(String[] args) throws Exception { awsEnvironment.put("AWS_ACCESS_KEY_ID", runResult.accessKeyId); awsEnvironment.put("AWS_SECRET_ACCESS_KEY", runResult.secretAccessKey); awsEnvironment.put("AWS_SESSION_TOKEN", runResult.sessionToken); - awsEnvironment.put("AWS_DEFAULT_REGION", environment.awsRegion); - // Cleanup command line arguments if present - args = removeProfileArguments(args); + awsEnvironment.put("AWS_DEFAULT_REGION", environment.awsRegion.id()); } if(args.length == 0) { @@ -50,24 +46,4 @@ public static void main(String[] args) throws Exception { int exitCode = awsSubProcess.waitFor(); System.exit(exitCode); } - - private static String[] removeProfileArguments(String[] args) { - List argsList = new ArrayList<>(args.length); - boolean profileArg = false; - for (String arg : args) { - if ("--profile".equals(arg)) { - // skip the profile flag and note to skip its argument - profileArg = true; - } - else if (profileArg) { - // skip the profile argument - profileArg = false; - } else if (arg.startsWith("--profile=")) { - // skip the single argument profile flag - } else { - argsList.add(arg); - } - } - return argsList.toArray(new String[] {}); - } } diff --git a/src/main/java/com/okta/tools/aws/settings/Credentials.java b/src/main/java/com/okta/tools/aws/settings/Credentials.java index 80e4f8e..ec7b5eb 100644 --- a/src/main/java/com/okta/tools/aws/settings/Credentials.java +++ b/src/main/java/com/okta/tools/aws/settings/Credentials.java @@ -15,6 +15,8 @@ */ package com.okta.tools.aws.settings; +import software.amazon.awssdk.regions.Region; + import java.io.IOException; import java.io.Reader; @@ -51,10 +53,10 @@ public Credentials(Reader reader) throws IOException { * @param awsRegion The region to use for the profile. * @param awsSessionToken The session token to use for the profile. */ - public void addOrUpdateProfile(String name, String awsAccessKey, String awsSecretKey, String awsRegion, String awsSessionToken) { + public void addOrUpdateProfile(String name, String awsAccessKey, String awsSecretKey, Region awsRegion, String awsSessionToken) { setProperty(name, ACCESS_KEY_ID, awsAccessKey); setProperty(name, SECRET_ACCESS_KEY, awsSecretKey); - setProperty(name, AWS_DEFAULT_REGION, awsRegion); + setProperty(name, AWS_DEFAULT_REGION, awsRegion.id()); setProperty(name, SESSION_TOKEN, awsSessionToken); } diff --git a/src/main/java/com/okta/tools/aws/settings/MultipleProfile.java b/src/main/java/com/okta/tools/aws/settings/MultipleProfile.java index 851afbb..0a8c421 100644 --- a/src/main/java/com/okta/tools/aws/settings/MultipleProfile.java +++ b/src/main/java/com/okta/tools/aws/settings/MultipleProfile.java @@ -15,6 +15,8 @@ */ package com.okta.tools.aws.settings; +import software.amazon.awssdk.regions.Region; + import java.io.IOException; import java.io.Reader; import java.time.Instant; @@ -69,10 +71,10 @@ private String getRoleArn(String profile) { * @param awsRegion Region to use for assumption * @param expiry expiry time of the profile session. */ - public void addOrUpdateProfile(String name, String roleArn, String awsRegion, Instant expiry) { + public void addOrUpdateProfile(String name, String roleArn, Region awsRegion, Instant expiry) { setProperty(name, SOURCE_PROFILE, name); setProperty(name, OKTA_ROLE_ARN, roleArn); - setProperty(name, AWS_DEFAULT_REGION, awsRegion); + setProperty(name, AWS_DEFAULT_REGION, awsRegion.id()); setProperty(name, PROFILE_EXPIRY, expiry.toString()); } } diff --git a/src/main/java/com/okta/tools/helpers/CredentialsHelper.java b/src/main/java/com/okta/tools/helpers/CredentialsHelper.java index 37ce212..e497c57 100644 --- a/src/main/java/com/okta/tools/helpers/CredentialsHelper.java +++ b/src/main/java/com/okta/tools/helpers/CredentialsHelper.java @@ -16,6 +16,7 @@ package com.okta.tools.helpers; import com.okta.tools.aws.settings.Credentials; +import software.amazon.awssdk.regions.Region; import java.io.IOException; @@ -31,7 +32,7 @@ public class CredentialsHelper { * @param awsSessionToken The session token to use * @throws IOException if a file system or permissions error occurs */ - void updateCredentialsFile(String profileName, String awsAccessKey, String awsSecretKey, String awsRegion, String awsSessionToken) + void updateCredentialsFile(String profileName, String awsAccessKey, String awsSecretKey, Region awsRegion, String awsSessionToken) throws IOException { FileHelper.usingPath(FileHelper.getAwsDirectory().resolve("credentials"), reader -> { Credentials credentials = new Credentials(reader); diff --git a/src/main/java/com/okta/tools/helpers/ProfileHelper.java b/src/main/java/com/okta/tools/helpers/ProfileHelper.java index ce7041f..4f833e1 100644 --- a/src/main/java/com/okta/tools/helpers/ProfileHelper.java +++ b/src/main/java/com/okta/tools/helpers/ProfileHelper.java @@ -15,10 +15,11 @@ */ package com.okta.tools.helpers; -import com.amazonaws.auth.BasicSessionCredentials; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLResult; import com.okta.tools.OktaAwsCliEnvironment; import org.apache.commons.lang.StringUtils; +import software.amazon.awssdk.auth.credentials.AwsSessionCredentials; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlResponse; import java.io.IOException; import java.util.regex.Matcher; @@ -29,36 +30,36 @@ public class ProfileHelper { private final CredentialsHelper credentialsHelper; private OktaAwsCliEnvironment environment; private final Pattern assumedRoleUserPattern = Pattern.compile( - "^arn:aws:sts::(?\\d{12}):assumed-role/(?[^/]*)/(?.*$)"); + "^arn:aws(|-gov):sts::(?\\d{12}):assumed-role/(?[^/]*)/(?.*$)"); public ProfileHelper(CredentialsHelper credentialsHelper, OktaAwsCliEnvironment environment) { this.credentialsHelper = credentialsHelper; this.environment = environment; } - public void createAwsProfile(AssumeRoleWithSAMLResult assumeResult, String credentialsProfileName) throws IOException { - BasicSessionCredentials temporaryCredentials = - new BasicSessionCredentials( - assumeResult.getCredentials().getAccessKeyId(), - assumeResult.getCredentials().getSecretAccessKey(), - assumeResult.getCredentials().getSessionToken()); + public void createAwsProfile(AssumeRoleWithSamlResponse assumeResult, String credentialsProfileName) throws IOException { + AwsSessionCredentials temporaryCredentials = + AwsSessionCredentials.create( + assumeResult.credentials().accessKeyId(), + assumeResult.credentials().secretAccessKey(), + assumeResult.credentials().sessionToken()); - String awsAccessKey = temporaryCredentials.getAWSAccessKeyId(); - String awsSecretKey = temporaryCredentials.getAWSSecretKey(); - String awsSessionToken = temporaryCredentials.getSessionToken(); + String awsAccessKey = temporaryCredentials.accessKeyId(); + String awsSecretKey = temporaryCredentials.secretAccessKey(); + String awsSessionToken = temporaryCredentials.sessionToken(); + + Region awsRegion = environment.awsRegion; - String awsRegion = environment.awsRegion; - credentialsHelper.updateCredentialsFile(credentialsProfileName, awsAccessKey, awsSecretKey, awsRegion, awsSessionToken); } - public String getProfileName(AssumeRoleWithSAMLResult assumeResult) { + public String getProfileName(AssumeRoleWithSamlResponse assumeResult) { if (StringUtils.isNotBlank(environment.oktaProfile)) { return environment.oktaProfile; } - String credentialsProfileName = assumeResult.getAssumedRoleUser().getArn(); + String credentialsProfileName = assumeResult.assumedRoleUser().arn(); Matcher matcher = assumedRoleUserPattern.matcher(credentialsProfileName); if (matcher.matches()) { return matcher.group("roleName") + "_" + matcher.group("account"); diff --git a/src/main/java/com/okta/tools/helpers/RoleHelper.java b/src/main/java/com/okta/tools/helpers/RoleHelper.java index 5f5d1db..8f7f803 100644 --- a/src/main/java/com/okta/tools/helpers/RoleHelper.java +++ b/src/main/java/com/okta/tools/helpers/RoleHelper.java @@ -15,19 +15,17 @@ */ package com.okta.tools.helpers; -import com.amazonaws.auth.AWSCredentialsProvider; -import com.amazonaws.auth.AWSStaticCredentialsProvider; -import com.amazonaws.auth.BasicAWSCredentials; -import com.amazonaws.services.securitytoken.AWSSecurityTokenService; -import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLRequest; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLResult; import com.okta.tools.OktaAwsCliEnvironment; import com.okta.tools.models.AccountOption; import com.okta.tools.models.RoleOption; import com.okta.tools.saml.AwsSamlRoleUtils; import com.okta.tools.saml.AwsSamlSigninParser; import org.jsoup.nodes.Document; +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.services.sts.StsClient; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlRequest; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlResponse; import java.io.IOException; import java.util.ArrayList; @@ -37,24 +35,23 @@ public class RoleHelper { - private OktaAwsCliEnvironment environment; + final private OktaAwsCliEnvironment environment; public RoleHelper(OktaAwsCliEnvironment environment) { this.environment = environment; } - public AssumeRoleWithSAMLResult assumeChosenAwsRole(AssumeRoleWithSAMLRequest assumeRequest) { - BasicAWSCredentials nullCredentials = new BasicAWSCredentials("", ""); - AWSCredentialsProvider nullCredentialsProvider = new AWSStaticCredentialsProvider(nullCredentials); - AWSSecurityTokenService sts = AWSSecurityTokenServiceClientBuilder - .standard() - .withRegion(environment.awsRegion) - .withCredentials(nullCredentialsProvider) + public AssumeRoleWithSamlResponse assumeChosenAwsRole(AssumeRoleWithSamlRequest assumeRequest) { + AwsBasicCredentials nullCredentials = AwsBasicCredentials.create("empty", "empty"); + StaticCredentialsProvider nullCredentialsProvider = StaticCredentialsProvider.create(nullCredentials); + StsClient sts = StsClient.builder() + .region(environment.awsRegion) + .credentialsProvider(nullCredentialsProvider) .build(); return sts.assumeRoleWithSAML(assumeRequest); } - public AssumeRoleWithSAMLRequest chooseAwsRoleToAssume(String samlResponse) throws IOException { + public AssumeRoleWithSamlRequest chooseAwsRoleToAssume(String samlResponse) throws IOException { Map roleIdpPairs = AwsSamlRoleUtils.getRoles(samlResponse); List roleArns = new ArrayList<>(); @@ -111,11 +108,12 @@ public AssumeRoleWithSAMLRequest chooseAwsRoleToAssume(String samlResponse) thro int stsDuration = environment.stsDuration; - return new AssumeRoleWithSAMLRequest() - .withPrincipalArn(principalArn) - .withRoleArn(roleArn) - .withSAMLAssertion(samlResponse) - .withDurationSeconds(stsDuration); + return AssumeRoleWithSamlRequest.builder() + .principalArn(principalArn) + .roleArn(roleArn) + .samlAssertion(samlResponse) + .durationSeconds(stsDuration) + .build(); } public List getAvailableRoles(String samlResponse) throws IOException { diff --git a/src/test/java/com/okta/tools/aws/settings/CredentialsTest.java b/src/test/java/com/okta/tools/aws/settings/CredentialsTest.java index c99fb26..6f0abc4 100644 --- a/src/test/java/com/okta/tools/aws/settings/CredentialsTest.java +++ b/src/test/java/com/okta/tools/aws/settings/CredentialsTest.java @@ -16,6 +16,7 @@ package com.okta.tools.aws.settings; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; import java.io.IOException; import java.io.StringReader; @@ -34,7 +35,7 @@ class CredentialsTest { private String roleName = "newrole"; private String accessKey = "accesskey"; private String secretKey = "secretkey"; - private String awsRegion = "region"; + private Region awsRegion = Region.of("region"); private String sessionToken = "sessiontoken"; private String manualRole = "[" + roleName + "]\n" + Credentials.ACCESS_KEY_ID + " = " + accessKey + "\n" diff --git a/src/test/java/com/okta/tools/helpers/ProfileHelperTest.java b/src/test/java/com/okta/tools/helpers/ProfileHelperTest.java index cded3ee..fd6ab18 100644 --- a/src/test/java/com/okta/tools/helpers/ProfileHelperTest.java +++ b/src/test/java/com/okta/tools/helpers/ProfileHelperTest.java @@ -15,16 +15,16 @@ */ package com.okta.tools.helpers; -import com.amazonaws.services.securitytoken.model.AssumeRoleWithSAMLResult; -import com.amazonaws.services.securitytoken.model.AssumedRoleUser; -import com.amazonaws.services.securitytoken.model.Credentials; import com.okta.tools.OktaAwsCliEnvironment; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.sts.model.AssumeRoleWithSamlResponse; +import software.amazon.awssdk.services.sts.model.AssumedRoleUser; +import software.amazon.awssdk.services.sts.model.Credentials; import java.io.IOException; import java.time.Instant; -import java.util.Date; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.mock; @@ -34,18 +34,19 @@ class ProfileHelperTest { private static final String fakeAccessKey = "Fake-access-key"; private static final String fakeSecretKey = "Fake-secret-key"; - private static final String fakeAwsRegion = "Fake-region"; + private static final Region fakeAwsRegion = Region.of("Fake-region"); private static final String fakeSessionToken = "Fake-session-token"; private static final String fakeCredentialsProfileName = "arn:aws:sts::123456789012:assumed-role/FakeRole/fakey.mcfakerson@fake.example.com"; + private static final String fakeGovCloudCredentialsProfileName = "arn:aws-gov:sts::123456789012:assumed-role/FakeRole/fakey.mcfakerson@fake.example.com"; private static final String fakeAssumeRoleUserArn = "arn:aws:sts::123456789012:assumed-role/FakeRole/fakey.mcfakerson@fake.example.com"; private static final String expectedGeneratedProfileName = "FakeRole_123456789012"; - private static final Date fakeExpiryDate = Date.from(Instant.EPOCH); + private static final Instant fakeExpiryDate = Instant.EPOCH; private static final String specifiedOktaProfile = "test"; private static final String tempProfileNameFallback = "temp"; private ProfileHelper profileHelper; private CredentialsHelper credentialsHelper; - private AssumeRoleWithSAMLResult assumeRoleWithSAMLResult; + private AssumeRoleWithSamlResponse assumeRoleWithSamlResult; private OktaAwsCliEnvironment environment; @BeforeEach @@ -53,24 +54,29 @@ void setUp() { credentialsHelper = mock(CredentialsHelper.class); environment = new OktaAwsCliEnvironment(false, null, null, null, null, null, null, null, 0, fakeAwsRegion, null, false, null); profileHelper = new ProfileHelper(credentialsHelper, environment); - assumeRoleWithSAMLResult = new AssumeRoleWithSAMLResult(); - Credentials credentials = new Credentials(fakeAccessKey, fakeSecretKey, fakeSessionToken, fakeExpiryDate); - assumeRoleWithSAMLResult.setCredentials(credentials); - AssumedRoleUser assumedRoleUser = new AssumedRoleUser(); - assumedRoleUser.setArn(fakeAssumeRoleUserArn); - assumeRoleWithSAMLResult.setAssumedRoleUser(assumedRoleUser); + Credentials credentials = Credentials.builder() + .accessKeyId(fakeAccessKey) + .secretAccessKey(fakeSecretKey) + .sessionToken(fakeSessionToken) + .expiration(fakeExpiryDate) + .build(); + AssumedRoleUser assumedRoleUser = AssumedRoleUser.builder().arn(fakeAssumeRoleUserArn).build(); + assumeRoleWithSamlResult = AssumeRoleWithSamlResponse.builder() + .credentials(credentials) + .assumedRoleUser(assumedRoleUser) + .build(); } @Test void createAwsProfile() throws IOException { - profileHelper.createAwsProfile(assumeRoleWithSAMLResult, fakeCredentialsProfileName); + profileHelper.createAwsProfile(assumeRoleWithSamlResult, fakeCredentialsProfileName); verify(credentialsHelper).updateCredentialsFile(fakeCredentialsProfileName, fakeAccessKey, fakeSecretKey, fakeAwsRegion, fakeSessionToken); } @Test void getProfileName() { - String profileName = profileHelper.getProfileName(assumeRoleWithSAMLResult); + String profileName = profileHelper.getProfileName(assumeRoleWithSamlResult); assertEquals(expectedGeneratedProfileName, profileName); } @@ -79,17 +85,32 @@ void getProfileName() { void getProfileNameWithSpecifiedOktaProfile() { environment.oktaProfile = specifiedOktaProfile; - String profileName = profileHelper.getProfileName(assumeRoleWithSAMLResult); + String profileName = profileHelper.getProfileName(assumeRoleWithSamlResult); assertEquals(specifiedOktaProfile, profileName); } @Test void getProfileNameWithBrokenAssumedUserArnUsesTemp() { - assumeRoleWithSAMLResult.getAssumedRoleUser().setArn("brokenARN"); + AssumedRoleUser assumedRoleUser = AssumedRoleUser.builder().arn("brokenARN").build(); + AssumeRoleWithSamlResponse newResult = assumeRoleWithSamlResult.toBuilder() + .assumedRoleUser(assumedRoleUser) + .build(); - String profileName = profileHelper.getProfileName(assumeRoleWithSAMLResult); + String profileName = profileHelper.getProfileName(newResult); assertEquals(tempProfileNameFallback, profileName); } + + @Test + void getProfileNameWithGovCloudAssumedUserArn() { + AssumedRoleUser assumedRoleUser = AssumedRoleUser.builder().arn(fakeGovCloudCredentialsProfileName).build(); + AssumeRoleWithSamlResponse newResult = assumeRoleWithSamlResult.toBuilder() + .assumedRoleUser(assumedRoleUser) + .build(); + + String profileName = profileHelper.getProfileName(newResult); + + assertEquals(expectedGeneratedProfileName, profileName); + } }