From e33283520845bb3931fa076b041b3c0605ddff35 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Mon, 25 Jan 2021 17:54:55 -0700 Subject: [PATCH 1/3] Updating to use the AWS 2.0 SDK --- .github/workflows/pull_request.yaml | 18 ++++++ .idea/.name | 1 - .idea/encodings.xml | 1 + .idea/jarRepositories.xml | 30 ++++++++++ .idea/misc.xml | 2 +- .idea/modules.xml | 8 +++ Readme.MD | 2 +- THIRD_PARTY_NOTICES | 16 ++---- bin/install.sh | 6 +- pom.xml | 31 ++++++---- .../com/okta/tools/AWSCredentialsUtil.java | 30 +++++----- .../com/okta/tools/OktaAwsCliAssumeRole.java | 34 +++++------ .../com/okta/tools/OktaAwsCliEnvironment.java | 6 +- .../java/com/okta/tools/OktaAwsConfig.java | 6 +- src/main/java/com/okta/tools/WithOkta.java | 28 +-------- .../okta/tools/aws/settings/Credentials.java | 6 +- .../tools/aws/settings/MultipleProfile.java | 6 +- .../okta/tools/helpers/CredentialsHelper.java | 3 +- .../com/okta/tools/helpers/ProfileHelper.java | 33 +++++------ .../com/okta/tools/helpers/RoleHelper.java | 41 +++++++------ .../tools/aws/settings/CredentialsTest.java | 3 +- .../okta/tools/helpers/ProfileHelperTest.java | 57 +++++++++++++------ 22 files changed, 215 insertions(+), 153 deletions(-) create mode 100644 .github/workflows/pull_request.yaml delete mode 100644 .idea/.name create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/modules.xml 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 02c208a..4859018 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 15f4ebf..224facb 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -132,8 +132,6 @@ mkdir -p "${PREFIX}/bin" # Create withokta command cat <"${PREFIX}/bin/withokta" #!/bin/bash -command="\$1" -profile=\$2 shift; shift; if [ "$1" == "logout" ] @@ -144,10 +142,10 @@ 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 02ec03c..fb08bb3 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ com.okta.developer okta-aws-cli - 2.0.5-SNAPSHOT + 3.0.0-SNAPSHOT jar @@ -33,28 +33,37 @@ UTF-8 - 1.11.515 - 1.2.0 - 20180813 + 2.15.69 + 20200518 2.4 - 4.5.5 + 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 8c136e5..39f887b 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; @@ -40,7 +42,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) { 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 4b25401..f874c0e 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; @@ -161,7 +161,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..6656678 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,24 @@ 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); + System.out.println(environment.awsRegion.id()); + 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 +109,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 eee2958..d3228c6 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); 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); + } } From 63b880957e0d64cd3387e1fbf16e6aa7e808db65 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Tue, 26 Jan 2021 10:47:34 -0700 Subject: [PATCH 2/3] Forward the arguments as is --- bin/install.sh | 8 +------- src/main/java/com/okta/tools/helpers/RoleHelper.java | 1 - 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/bin/install.sh b/bin/install.sh index 224facb..653379a 100755 --- a/bin/install.sh +++ b/bin/install.sh @@ -132,12 +132,6 @@ mkdir -p "${PREFIX}/bin" # Create withokta command cat <"${PREFIX}/bin/withokta" #!/bin/bash -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]}" @@ -145,7 +139,7 @@ fi java \${PROXY_CONFIG} \\ -Djava.util.logging.config.file=${PREFIX}/logging.properties \\ -classpath ${PREFIX}/okta-aws-cli.jar \\ - com.okta.tools.WithOkta "\$@" + com.okta.tools.WithOkta \$@ EOF chmod +x "${PREFIX}/bin/withokta" diff --git a/src/main/java/com/okta/tools/helpers/RoleHelper.java b/src/main/java/com/okta/tools/helpers/RoleHelper.java index 6656678..8f7f803 100644 --- a/src/main/java/com/okta/tools/helpers/RoleHelper.java +++ b/src/main/java/com/okta/tools/helpers/RoleHelper.java @@ -44,7 +44,6 @@ public RoleHelper(OktaAwsCliEnvironment environment) { public AssumeRoleWithSamlResponse assumeChosenAwsRole(AssumeRoleWithSamlRequest assumeRequest) { AwsBasicCredentials nullCredentials = AwsBasicCredentials.create("empty", "empty"); StaticCredentialsProvider nullCredentialsProvider = StaticCredentialsProvider.create(nullCredentials); - System.out.println(environment.awsRegion.id()); StsClient sts = StsClient.builder() .region(environment.awsRegion) .credentialsProvider(nullCredentialsProvider) From 715eb49efe47527ab7bcc0f2d1975db31a1f3b71 Mon Sep 17 00:00:00 2001 From: David Tanner Date: Wed, 7 Jul 2021 12:58:35 -0600 Subject: [PATCH 3/3] Fix conflicts --- src/main/java/com/okta/tools/OktaAwsCliEnvironment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java b/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java index 8779606..977d1df 100644 --- a/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java +++ b/src/main/java/com/okta/tools/OktaAwsCliEnvironment.java @@ -44,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;