Skip to content

Commit

Permalink
🌱 Add OKTA_MFA_CHOICE in config.properties
Browse files Browse the repository at this point in the history
 - Allow MFA choice to be specified as provider and factor type to use

 - Exs: OKTA.token:software:totp, GOOGLE.token:software:totp, OTKA.push

Resolves oktadev#258
  • Loading branch information
AlainODea committed Jan 5, 2019
1 parent 13bccfe commit cb68001
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 21 deletions.
1 change: 1 addition & 0 deletions Readme.MD
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Here is the list of parameters that can be environment variables or settings in
- ```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.
- ```OKTA_MFA_CHOICE``` is the provider and factor type to use if prompted for MFA. Example: ```OKTA.push```. See [Factors documentation](https://developer.okta.com/docs/api/resources/factors#factor-type) for values. (default: use single factor or prompt user to select from usable factors).
- **Obtaining the AWS app url**
- Navigate to the ```Admin Dashboard``` of you Okta organization
Expand Down
9 changes: 5 additions & 4 deletions src/main/java/com/okta/tools/ListRoles.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,22 @@
package com.okta.tools;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.okta.tools.authentication.OktaAuthentication;
import com.okta.tools.authentication.OktaMFA;
import com.okta.tools.helpers.CookieHelper;
import com.okta.tools.helpers.RoleHelper;
import com.okta.tools.models.AccountOption;
import com.okta.tools.saml.OktaSaml;

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

public class ListRoles {
public static void main(String[] args) throws Exception {
OktaAwsCliEnvironment environment = OktaAwsConfig.loadEnvironment();
CookieHelper cookieHelper = new CookieHelper(environment);
OktaSaml oktaSaml = new OktaSaml(environment, cookieHelper);
OktaMFA oktaMFA = new OktaMFA(environment);
OktaAuthentication oktaAuthentication = new OktaAuthentication(environment, oktaMFA);
OktaSaml oktaSaml = new OktaSaml(environment, cookieHelper, oktaAuthentication);
String samlResponse = oktaSaml.getSamlResponse();
RoleHelper roleHelper = new RoleHelper(environment);
List<AccountOption> availableRoles = roleHelper.getAvailableRoles(samlResponse);
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/com/okta/tools/OktaAwsCliAssumeRole.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.Optional;

import com.amazonaws.services.securitytoken.model.Credentials;
import com.okta.tools.authentication.OktaAuthentication;
import com.okta.tools.authentication.OktaMFA;
import com.okta.tools.helpers.*;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -62,8 +64,10 @@ private void init() throws Exception {
roleHelper = new RoleHelper(environment);
credentialsHelper = new CredentialsHelper(environment);
profileHelper = new ProfileHelper(credentialsHelper, environment);
OktaMFA oktaMFA = new OktaMFA(environment);
OktaAuthentication oktaAuthentication = new OktaAuthentication(environment, oktaMFA);

oktaSaml = new OktaSaml(environment, cookieHelper);
oktaSaml = new OktaSaml(environment, cookieHelper, oktaAuthentication);

currentSession = sessionHelper.getCurrentSession();

Expand Down
6 changes: 4 additions & 2 deletions src/main/java/com/okta/tools/OktaAwsCliEnvironment.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,19 @@ public class OktaAwsCliEnvironment {

public int stsDuration;
public final String awsRegion;
public final String oktaMfaChoice;
public boolean oktaEnvMode;

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

public OktaAwsCliEnvironment(boolean browserAuth, String oktaOrg,
String oktaUsername, Supplier<String> oktaPassword, String oktaCookiesPath,
String oktaProfile, String oktaAwsAppUrl, String awsRoleToAssume,
int stsDuration, String awsRegion,
boolean oktaEnvMode) {
String oktaMfaChoice, boolean oktaEnvMode) {
this.browserAuth = browserAuth;
this.oktaOrg = oktaOrg;
this.oktaUsername = oktaUsername;
Expand All @@ -38,6 +39,7 @@ public OktaAwsCliEnvironment(boolean browserAuth, String oktaOrg,
this.awsRoleToAssume = awsRoleToAssume;
this.stsDuration = stsDuration;
this.awsRegion = awsRegion;
this.oktaMfaChoice = oktaMfaChoice;
this.oktaEnvMode = oktaEnvMode;
}
}
1 change: 1 addition & 0 deletions src/main/java/com/okta/tools/OktaAwsConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static OktaAwsCliEnvironment loadEnvironment(String profile) {
getEnvOrConfig(properties, "OKTA_AWS_ROLE_TO_ASSUME"),
getStsDurationOrDefault(getEnvOrConfig(properties, "OKTA_STS_DURATION")),
getAwsRegionOrDefault(getEnvOrConfig(properties, "OKTA_AWS_REGION")),
getEnvOrConfig(properties, "OKTA_MFA_CHOICE"),
Boolean.parseBoolean(getEnvOrConfig(properties, "OKTA_ENV_MODE"))
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ public final class OktaAuthentication {
private static final Logger logger = LogManager.getLogger(OktaAuthentication.class);

private final OktaAwsCliEnvironment environment;
private final OktaMFA oktaMFA;

public OktaAuthentication(OktaAwsCliEnvironment environment) {
public OktaAuthentication(OktaAwsCliEnvironment environment, OktaMFA oktaMFA) {
this.environment = environment;
this.oktaMFA = oktaMFA;
}

/**
Expand Down Expand Up @@ -87,7 +89,7 @@ public String getOktaSessionToken() throws IOException {
throw new IllegalStateException("Invalid value - should never happen.");
case MFA_REQUIRED:
// Handle second-factor
return OktaMFA.promptForFactor(primaryAuthResult);
return oktaMFA.promptForFactor(primaryAuthResult);
case SUCCESS:
if (primaryAuthResult.has(sessionProperty)) {
return primaryAuthResult.getString(sessionProperty);
Expand Down Expand Up @@ -213,7 +215,7 @@ private String getPassword() {
private String promptForPassword() {
if (System.console() == null) { // hack to be able to debug in an IDE
System.err.print("Password: ");
return new Scanner(System.in).next();
return new Scanner(System.in).nextLine();
} else {
return new String(System.console().readPassword("Password: "));
}
Expand Down
29 changes: 22 additions & 7 deletions src/main/java/com/okta/tools/authentication/OktaMFA.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.okta.tools.authentication;

import com.okta.tools.OktaAwsCliEnvironment;
import com.okta.tools.helpers.HttpHelper;
import com.okta.tools.helpers.MenuHelper;
import org.apache.http.client.methods.CloseableHttpResponse;
Expand All @@ -35,13 +36,19 @@
import java.util.Scanner;

public class OktaMFA {
private final OktaAwsCliEnvironment environment;

public OktaMFA(OktaAwsCliEnvironment environment) {
this.environment = environment;
}

/**
* Prompt the user for 2FA after primary authentication
*
* @param primaryAuthResponse The response from primary auth
* @return The session token
*/
public static String promptForFactor(JSONObject primaryAuthResponse) {
public String promptForFactor(JSONObject primaryAuthResponse) {
try {
// User selects which factor to use
JSONObject factor = selectFactor(primaryAuthResponse);
Expand Down Expand Up @@ -88,7 +95,7 @@ public static String promptForFactor(JSONObject primaryAuthResponse) {
* @param primaryAuthResponse The response from Primary Authentication
* @return The factor prompt if invalid, session token otherwise
*/
private static String handleTimeoutsAndChanges(String sessionToken, JSONObject primaryAuthResponse) {
private String handleTimeoutsAndChanges(String sessionToken, JSONObject primaryAuthResponse) {
if (sessionToken.equals("change factor")) {
System.err.println("Factor change initiated");
return promptForFactor(primaryAuthResponse);
Expand All @@ -106,9 +113,8 @@ private static String handleTimeoutsAndChanges(String sessionToken, JSONObject p
* @return A {@link JSONObject} representing the selected factor.
* @throws JSONException if a network or protocol error occurs
*/
private static JSONObject selectFactor(JSONObject primaryAuthResponse) throws JSONException {
private JSONObject selectFactor(JSONObject primaryAuthResponse) throws JSONException {
JSONArray factors = primaryAuthResponse.getJSONObject("_embedded").getJSONArray("factors");
String factorType;

List<JSONObject> supportedFactors = getUsableFactors(factors);
if (supportedFactors.isEmpty()) {
Expand All @@ -120,13 +126,22 @@ private static JSONObject selectFactor(JSONObject primaryAuthResponse) throws JS
}

if (supportedFactors.size() > 1) {
if (environment.oktaMfaChoice != null) {
for (JSONObject factor : supportedFactors) {
String provider = factor.getString("provider");
String factorType = factor.getString("factorType");
if ((provider + "." + factorType).equals(environment.oktaMfaChoice)) {
return factor;
}
}
}
System.err.println("\nMulti-Factor authentication is required. Please select a factor to use.");
System.err.println("Factors:");
for (int i = 0; i < supportedFactors.size(); i++) {
JSONObject factor = supportedFactors.get(i);
factorType = factor.getString("factorType");
factorType = getFactorDescription(factorType, factor);
System.err.println("[ " + (i + 1) + " ] : " + factorType);
String factorType = factor.getString("factorType");
String factorDescription = getFactorDescription(factorType, factor);
System.err.println("[ " + (i + 1) + " ] : " + factorDescription);
}
}

Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/okta/tools/saml/OktaSaml.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@ public class OktaSaml {

private final OktaAwsCliEnvironment environment;
private final CookieHelper cookieHelper;
private final OktaAuthentication authentication;

public OktaSaml(OktaAwsCliEnvironment environment, CookieHelper cookieHelper) {
public OktaSaml(OktaAwsCliEnvironment environment, CookieHelper cookieHelper, OktaAuthentication oktaAuthentication) {
this.environment = environment;
this.cookieHelper = cookieHelper;
this.authentication = oktaAuthentication;
}

public String getSamlResponse() throws IOException {
OktaAuthentication authentication = new OktaAuthentication(environment);

if (environment.browserAuth) {
try {
return BrowserAuthentication.login(environment);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class ProfileHelperTest {
@BeforeEach
void setUp() {
credentialsHelper = mock(CredentialsHelper.class);
environment = new OktaAwsCliEnvironment(false, null, null, null, null, null, null, null, 0, fakeAwsRegion, false);
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);
Expand Down

0 comments on commit cb68001

Please sign in to comment.