Skip to content

Commit

Permalink
🌱 Add support for EnvVars integration
Browse files Browse the repository at this point in the history
 - Introduce OKTA_ENV_MODE

 - Add documentation for OKTA_ENV_MODE

 - Run sub-process with env vars instead of saved profiles

 - 🐛 Defer password command

 - 🎨 Use boolean not Boolean

Resolves oktadev#177
  • Loading branch information
AlainODea committed Aug 22, 2018
1 parent 084209d commit d881db0
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 28 deletions.
3 changes: 2 additions & 1 deletion Readme.MD
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ Here is the list of parameters that can be environment variables or settings in
- ```OKTA_ORG``` which is the url of your Okta org (starting with https://).
- ```OKTA_AWS_APP_URL``` is the url link of your Okta AWS application url (see below for more info)
- ```OKTA_USERNAME``` is the username to use. If present will skip username input.
- ```OKTA_PASSWORD_CMD``` is the command to fetch your password instead of showing a password prompt. [Read more...](docs/OKTA_PASSWORD_CMD.md)
- ```OKTA_PASSWORD_CMD``` is the command to fetch your password instead of showing a password prompt. [Read more...](docs/OKTA_PASSWORD_CMD.md)
- ```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 (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)
Expand Down
30 changes: 25 additions & 5 deletions src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.time.temporal.ChronoUnit;
import java.util.Optional;

import com.amazonaws.services.securitytoken.model.Credentials;
import com.okta.tools.helpers.*;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -77,19 +78,35 @@ private void init() throws Exception {
currentProfile = sessionHelper.getFromMultipleProfiles();
}

String run(Instant startInstant) throws Exception {
RunResult run(Instant startInstant) throws Exception {
init();

environment.awsRoleToAssume = currentProfile.map(profile1 -> profile1.roleArn).orElse(null);

if (currentSession.isPresent() && sessionHelper.sessionIsActive(startInstant, currentSession.get()) &&
StringUtils.isBlank(environment.oktaProfile)) {
return currentSession.get().profileName;
RunResult runResult = new RunResult();
runResult.profileName = currentSession.get().profileName;
return runResult;
}

ProfileSAMLResult profileSAMLResult = doRequest(startInstant);

return profileSAMLResult.profileName;
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();

return runResult;
}

class RunResult {
String profileName;
String accessKeyId;
String secretAccessKey;
String sessionToken;
}

AssumeRoleWithSAMLResult getAssumeRoleWithSAMLResult(Instant startInstant) throws Exception {
Expand All @@ -107,9 +124,12 @@ private ProfileSAMLResult doRequest(Instant startInstant) throws IOException {
AssumeRoleWithSAMLRequest assumeRequest = roleHelper.chooseAwsRoleToAssume(samlResponse);
Instant sessionExpiry = startInstant.plus(assumeRequest.getDurationSeconds() - 30, ChronoUnit.SECONDS);
AssumeRoleWithSAMLResult assumeResult = roleHelper.assumeChosenAwsRole(assumeRequest);
String profileName = profileHelper.createAwsProfile(assumeResult);

updateConfig(assumeRequest, sessionExpiry, profileName);
String profileName = profileHelper.getProfileName(assumeResult, environment.oktaProfile);
if (!environment.oktaEnvMode) {
profileHelper.createAwsProfile(assumeResult, profileName);
updateConfig(assumeRequest, sessionExpiry, profileName);
}

return new ProfileSAMLResult(assumeResult, profileName);
}
Expand Down
12 changes: 8 additions & 4 deletions src/main/java/com/okta/tools/OktaAwsCliEnvironment.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
package com.okta.tools;

import java.util.function.Supplier;

public class OktaAwsCliEnvironment {
private static final String DEFAULT_PROFILE_PREFIX = "profile ";
private static final String DEFAULT_CREDENTIALS_SUFFIX = "_source";

public final boolean browserAuth;
public final String oktaOrg;
public final String oktaUsername;
public final String oktaPassword;
public final Supplier<String> oktaPassword;
public final String oktaCookiesPath;
public String oktaProfile;

Expand All @@ -18,18 +20,19 @@ public class OktaAwsCliEnvironment {
public int stsDuration;
public final String awsRegion;
public final String profilePrefix;
public final boolean oktaEnvMode;
public final String credentialsSuffix;

public OktaAwsCliEnvironment()
{
this(false, null, null, null, null, null, null, null, 0, null, null, null);
this(false, null, null, null, null, null, null, null, 0, null, null, false, null);
}

public OktaAwsCliEnvironment(boolean browserAuth, String oktaOrg,
String oktaUsername, String oktaPassword, String oktaCookiesPath,
String oktaUsername, Supplier<String> oktaPassword, String oktaCookiesPath,
String oktaProfile, String oktaAwsAppUrl, String awsRoleToAssume,
int stsDuration, String awsRegion, String profilePrefix,
String credentialsSuffix) {
boolean oktaEnvMode, String credentialsSuffix) {
this.browserAuth = browserAuth;
this.oktaOrg = oktaOrg;
this.oktaUsername = oktaUsername;
Expand All @@ -41,6 +44,7 @@ public OktaAwsCliEnvironment(boolean browserAuth, String oktaOrg,
this.stsDuration = stsDuration;
this.awsRegion = awsRegion;
this.profilePrefix = profilePrefix == null ? DEFAULT_PROFILE_PREFIX : profilePrefix;
this.oktaEnvMode = oktaEnvMode;
this.credentialsSuffix = credentialsSuffix == null ? DEFAULT_CREDENTIALS_SUFFIX : credentialsSuffix;
}
}
12 changes: 9 additions & 3 deletions src/main/java/com/okta/tools/OktaAwsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.nio.file.Paths;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Supplier;
import java.util.stream.Collectors;

final class OktaAwsConfig {
Expand Down Expand Up @@ -46,23 +47,28 @@ static OktaAwsCliEnvironment loadEnvironment(String profile) {
}

return new OktaAwsCliEnvironment(
Boolean.valueOf(getEnvOrConfig(properties, "OKTA_BROWSER_AUTH")),
Boolean.parseBoolean(getEnvOrConfig(properties, "OKTA_BROWSER_AUTH")),
getEnvOrConfig(properties, "OKTA_ORG"),
getEnvOrConfig(properties, "OKTA_USERNAME"),
runProgram(getEnvOrConfig(properties, "OKTA_PASSWORD_CMD")),
deferProgram(getEnvOrConfig(properties, "OKTA_PASSWORD_CMD")),
getEnvOrConfig(properties, "OKTA_COOKIES_PATH"),
getProfile(profile, getEnvOrConfig(properties, "OKTA_PROFILE")),
getEnvOrConfig(properties, "OKTA_AWS_APP_URL"),
getEnvOrConfig(properties, "OKTA_AWS_ROLE_TO_ASSUME"),
getStsDurationOrDefault(getEnvOrConfig(properties, "OKTA_STS_DURATION")),
getAwsRegionOrDefault(getEnvOrConfig(properties, "OKTA_AWS_REGION")),
getEnvOrConfig(properties, "OKTA_PROFILE_PREFIX"),
Boolean.parseBoolean(getEnvOrConfig(properties, "OKTA_ENV_MODE")),
getEnvOrConfig(properties, "OKTA_CREDENTIALS_SUFFIX")
);
}

private static String runProgram(String oktaPasswordCommand) {
private static Supplier<String> deferProgram(String oktaPasswordCommand) {
if (oktaPasswordCommand == null) return null;
return () -> runProgram(oktaPasswordCommand);
}

private static String runProgram(String oktaPasswordCommand) {
ProcessBuilder processBuilder = new ProcessBuilder();
if (SystemUtils.IS_OS_WINDOWS) {
processBuilder.command("cmd", "/C", oktaPasswordCommand);
Expand Down
34 changes: 32 additions & 2 deletions src/main/java/com/okta/tools/WithOkta.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.okta.tools;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/*
* Copyright 2017 Okta
Expand All @@ -21,10 +24,37 @@
public class WithOkta {
public static void main(String[] args) throws Exception {
if (LogoutHandler.handleLogout(args)) return;
OktaAwsCliAssumeRole.withEnvironment(OktaAwsConfig.loadEnvironment()).run(Instant.now());
ProcessBuilder awsProcessBuilder = new ProcessBuilder().inheritIO().command(args);
OktaAwsCliEnvironment environment = OktaAwsConfig.loadEnvironment();
OktaAwsCliAssumeRole.RunResult runResult = OktaAwsCliAssumeRole.withEnvironment(environment).run(Instant.now());
ProcessBuilder awsProcessBuilder = new ProcessBuilder().inheritIO();
if (environment.oktaEnvMode) {
Map<String, String> awsEnvironment = awsProcessBuilder.environment();
awsEnvironment.put("AWS_ACCESS_KEY_ID", runResult.accessKeyId);
awsEnvironment.put("AWS_SECRET_ACCESS_KEY", runResult.secretAccessKey);
awsEnvironment.put("AWS_SESSION_TOKEN", runResult.sessionToken);
args = removeProfileArguments(args);
}
awsProcessBuilder.command(args);
Process awsSubProcess = awsProcessBuilder.start();
int exitCode = awsSubProcess.waitFor();
System.exit(exitCode);
}

private static String[] removeProfileArguments(String[] args) {
List<String> 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 {
argsList.add(arg);
}
}
return argsList.toArray(new String[] {});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,10 @@ private String getUsername() {
}

private String getPassword() {
if (environment.oktaPassword == null || environment.oktaPassword.isEmpty()) {
if (environment.oktaPassword == null) {
return promptForPassword();
} else {
return environment.oktaPassword;
return environment.oktaPassword.get();
}
}

Expand Down
19 changes: 15 additions & 4 deletions src/main/java/com/okta/tools/awscli.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class awscli {
public static void main(String[] args) throws Exception {
Expand All @@ -36,13 +37,23 @@ public static void main(String[] args) throws Exception {
hasProfile = "--profile".equals(arg);
}

OktaAwsCliEnvironment environment = OktaAwsConfig.loadEnvironment(profile);
OktaAwsCliAssumeRole.RunResult runResult = OktaAwsCliAssumeRole.withEnvironment(environment).run(Instant.now());
ProcessBuilder awsProcessBuilder = new ProcessBuilder().inheritIO();

List<String> awsCommand = new ArrayList<>();
String profileName = OktaAwsCliAssumeRole.withEnvironment(OktaAwsConfig.loadEnvironment(profile)).run(Instant.now());
awsCommand.add("aws");
awsCommand.add("--profile");
awsCommand.add(profileName);
if (environment.oktaEnvMode) {
Map<String, String> awsEnvironment = awsProcessBuilder.environment();
awsEnvironment.put("AWS_ACCESS_KEY_ID", runResult.accessKeyId);
awsEnvironment.put("AWS_SECRET_ACCESS_KEY", runResult.secretAccessKey);
awsEnvironment.put("AWS_SESSION_TOKEN", runResult.sessionToken);
} else {
awsCommand.add("--profile");
awsCommand.add(runResult.profileName);
}
awsCommand.addAll(Arrays.asList(args));
ProcessBuilder awsProcessBuilder = new ProcessBuilder().inheritIO().command(awsCommand);
awsProcessBuilder.command(awsCommand);
Process awsSubProcess = awsProcessBuilder.start();
int exitCode = awsSubProcess.waitFor();
System.exit(exitCode);
Expand Down
7 changes: 2 additions & 5 deletions src/main/java/com/okta/tools/helpers/ProfileHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public ProfileHelper(CredentialsHelper credentialsHelper, OktaAwsCliEnvironment
this.environment = environment;
}

public String createAwsProfile(AssumeRoleWithSAMLResult assumeResult) throws IOException {
public void createAwsProfile(AssumeRoleWithSAMLResult assumeResult, String credentialsProfileName) throws IOException {
BasicSessionCredentials temporaryCredentials =
new BasicSessionCredentials(
assumeResult.getCredentials().getAccessKeyId(),
Expand All @@ -28,13 +28,10 @@ public String createAwsProfile(AssumeRoleWithSAMLResult assumeResult) throws IOE
String awsSecretKey = temporaryCredentials.getAWSSecretKey();
String awsSessionToken = temporaryCredentials.getSessionToken();

String credentialsProfileName = getProfileName(assumeResult, environment.oktaProfile);
credentialsHelper.updateCredentialsFile(credentialsProfileName, awsAccessKey, awsSecretKey, awsSessionToken);

return credentialsProfileName;
}

private String getProfileName(AssumeRoleWithSAMLResult assumeResult, String oktaProfile) {
public String getProfileName(AssumeRoleWithSAMLResult assumeResult, String oktaProfile) {
String credentialsProfileName;
if (StringUtils.isNotBlank(oktaProfile)) {
credentialsProfileName = oktaProfile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class ConfigurationTest {
private OktaAwsCliEnvironment environmentWithCustomPrefix =
new OktaAwsCliEnvironment(false, null, null,
null, null, null, null, null,
0, null, "custom ", null);
0, null, "custom ", false, null);

/*
* Test writing a new profile to a blank configuration file.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class CredentialsTest {
new OktaAwsCliEnvironment(false, null, null,
null, null, null, null,
null, 0, null,
null, "_custom");
null, false, "_custom");

/*
* Test writing a new credentials profile to a blank credentials file.
Expand Down

0 comments on commit d881db0

Please sign in to comment.