Skip to content

Commit

Permalink
Update the registration process to use the new Okta registration API (#…
Browse files Browse the repository at this point in the history
…152)

* Update the registration process to use the new Okta registration API

- start.okta.dev is still used for listing of the samples
- There are now two properties/env vars for the ITs to set: `okta.cli.registrationUrl` and `okta.cli.apiUrl`
- registration now asks for country instead of company
- Bubble up registration error to user

* Add oie flag to trigger creation of OIE orgs

* Use JUL logging

removing slf4j-simple, it cannot be reconfigured at runtime (easily)
logback requires a bit of work to work with graal native-image

Removed the `--verbose` flag from the ITs because the JUL ConsoleHandler writes to serr

* Remove additional "User Canceled" message when user cancels registration

Not an ideal solution (handling this with a custom exception)
 the SetupService could be simplified a bit now that there is only a single client making use of this code.
  • Loading branch information
bdemers authored Feb 28, 2022
1 parent aa18e87 commit 4cfe9da
Show file tree
Hide file tree
Showing 23 changed files with 291 additions and 194 deletions.
10 changes: 1 addition & 9 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,8 @@
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<artifactId>slf4j-jdk14</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
<scope>runtime</scope>
</dependency>

<dependency>
Expand Down
7 changes: 7 additions & 0 deletions cli/src/main/graalvm/reflect-config.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@
"allPublicMethods": true,
"allPublicFields": true
},
{
"name": "com.okta.cli.common.model.UserProfileRequestWrapper",
"allDeclaredFields": true,
"allDeclaredMethods": true,
"allPublicMethods": true,
"allPublicFields": true
},
{
"name": "com.okta.cli.common.model.OrganizationResponse",
"allDeclaredFields": true,
Expand Down
17 changes: 15 additions & 2 deletions cli/src/main/java/com/okta/cli/OktaCli.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
import picocli.CommandLine.Spec;

import java.util.List;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;

@Command(name = "okta",
description = "The Okta CLI helps you configure your applications to use Okta.",
Expand Down Expand Up @@ -110,9 +114,18 @@ public void setBatch(boolean batch) {

@Option(names = "--verbose", description = "Verbose logging.")
public void setVerbose(boolean verbose) {
this.environment.setVerbose(verbose);
environment.setVerbose(verbose);
if (verbose) {
System.setProperty("org.slf4j.simpleLogger.defaultLogLevel", "debug");
// <ISO8601 date> <level> <logger> <message> <exception>
System.setProperty("java.util.logging.SimpleFormatter.format", "%1$tFT%1$tT.%1$tL%1$tz %4$s %2$s - %5$s\u001F%6$s%n");

final LogManager logManager = LogManager.getLogManager();
Logger rootLogger = logManager.getLogger("");
rootLogger.setLevel(Level.FINER);

ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINER);
rootLogger.addHandler(consoleHandler);
}
}

Expand Down
45 changes: 28 additions & 17 deletions cli/src/main/java/com/okta/cli/commands/Register.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,20 @@
import com.okta.cli.common.service.DefaultSdkConfigurationService;
import com.okta.cli.common.service.DefaultSetupService;
import com.okta.cli.common.service.SetupService;
import com.okta.cli.common.service.UserCanceledException;
import com.okta.cli.console.ConsoleOutput;
import com.okta.cli.console.Prompter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import picocli.CommandLine;
import picocli.CommandLine.Command;

@Command(name = "register",
description = "Sign up for a new Okta account")
public class Register extends BaseCommand {

private final Logger logger = LoggerFactory.getLogger(Register.class);

@CommandLine.Option(names = "--email", description = "Email used when registering a new Okta account.")
protected String email;

Expand All @@ -44,6 +49,12 @@ public class Register extends BaseCommand {
@CommandLine.Option(names = "--company", description = "Company/organization used when registering a new Okta account.")
protected String company;

@CommandLine.Option(names = "--country", description = "Country of residence")
protected String country;

@CommandLine.Option(names = "--oie", description = "Create Okta account with OIE enabled.", defaultValue = "true", hidden = true, negatable = true)
protected Boolean oie = Boolean.TRUE;

public Register() {}

private Register(OktaCli.StandardOptions standardOptions) {
Expand All @@ -70,17 +81,21 @@ public int runCommand() throws Exception {

CliRegistrationQuestions registrationQuestions = registrationQuestions();

SetupService setupService = new DefaultSetupService(OidcProperties.oktaEnv());
OrganizationResponse orgResponse = setupService.createOktaOrg(registrationQuestions,
getEnvironment().getOktaPropsFile(),
getEnvironment().isDemo(),
getEnvironment().isInteractive());

String identifier = orgResponse.getId();
setupService.verifyOktaOrg(identifier,
registrationQuestions,
getEnvironment().getOktaPropsFile());

try {
SetupService setupService = new DefaultSetupService(OidcProperties.oktaEnv());
OrganizationResponse orgResponse = setupService.createOktaOrg(registrationQuestions,
getEnvironment().getOktaPropsFile(),
getEnvironment().isDemo(),
getEnvironment().isInteractive());

String identifier = orgResponse.getDeveloperOrgCliToken();
setupService.verifyOktaOrg(identifier,
registrationQuestions,
getEnvironment().getOktaPropsFile());
} catch (UserCanceledException e) {
logger.debug("User canceled registration.", e);
return 2;
}
return 0;


Expand All @@ -104,12 +119,8 @@ public OrganizationRequest getOrganizationRequest() {
.setFirstName(prompter.promptUntilValue(firstName, "First name"))
.setLastName(prompter.promptUntilValue(lastName, "Last name"))
.setEmail(prompter.promptUntilValue(email, "Email address"))
.setOrganization(prompter.promptUntilValue(company, "Company"));
}

@Override
public String getVerificationCode() {
return prompter.promptUntilValue("Verification code");
.setCountry(prompter.promptUntilValue(country, "Country"))
.setOie(oie);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,21 @@
*/
package com.okta.cli.common.model;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class OrganizationRequest {

private String firstName;
private String lastName;
private String email;
private String organization;
private String country;

@JsonProperty("okta_oie")
private Boolean oie;
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@
@Accessors(chain = true)
public class OrganizationResponse {

private String id;
private String orgUrl;
private String email;
private String apiToken;
private String factorId;
private String updatePasswordUrl;
private String developerOrgCliToken;
private String status; // ACTIVE or PENDING

public boolean isActive() {
return "ACTIVE".equals(status);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,17 @@ public interface RegistrationQuestions {

OrganizationRequest getOrganizationRequest();

String getVerificationCode();

static RegistrationQuestions answers(boolean overwriteConfig, OrganizationRequest request, String code) {
return new SimpleRegistrationQuestions(overwriteConfig, request, code);
static RegistrationQuestions answers(boolean overwriteConfig, OrganizationRequest request) {
return new SimpleRegistrationQuestions(overwriteConfig, request);
}

class SimpleRegistrationQuestions implements RegistrationQuestions {
private final boolean overwriteConfig;
private final OrganizationRequest organizationRequest;
private final String verificationCode;

public SimpleRegistrationQuestions(boolean overwriteConfig, OrganizationRequest organizationRequest, String verificationCode) {
public SimpleRegistrationQuestions(boolean overwriteConfig, OrganizationRequest organizationRequest) {
this.overwriteConfig = overwriteConfig;
this.organizationRequest = organizationRequest;
this.verificationCode = verificationCode;
}

public boolean isOverwriteExistingConfig(String oktaBaseUrl, String configFile) {
Expand All @@ -45,9 +41,5 @@ public boolean isOverwriteExistingConfig(String oktaBaseUrl, String configFile)
public OrganizationRequest getOrganizationRequest() {
return organizationRequest;
}

public String getVerificationCode() {
return verificationCode;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.okta.cli.common;
package com.okta.cli.common.model;

import com.okta.cli.common.model.ErrorResponse;
import lombok.Data;
import lombok.experimental.Accessors;

public class FactorVerificationException extends RestException {
/**
* Okta's Registration API wraps the request in a "userProfile" node.
*/
@Data
@Accessors(chain = true)
public class UserProfileRequestWrapper {

public FactorVerificationException(ErrorResponse errorResponse, Throwable t) {
super(errorResponse, t);
}
private final OrganizationRequest userProfile;

public FactorVerificationException(ErrorResponse errorResponse) {
super(errorResponse);
public UserProfileRequestWrapper(OrganizationRequest userProfile) {
this.userProfile = userProfile;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,27 @@
*/
package com.okta.cli.common.service;

import com.okta.cli.common.FactorVerificationException;
import com.okta.cli.common.RestException;
import com.okta.cli.common.model.OrganizationRequest;
import com.okta.cli.common.model.OrganizationResponse;
import com.okta.cli.common.model.UserProfileRequestWrapper;

import java.io.IOException;

public class DefaultOktaOrganizationCreator implements OktaOrganizationCreator {

private final RestClient restClient = new DefaultStartRestClient();
private final RestClient restClient = new DefaultStartRestClient(Settings.getRegistrationBaseUrl());

private final String registrationId = Settings.getRegistrationId();

@Override
public OrganizationResponse createNewOrg(OrganizationRequest orgRequest) throws RestException, IOException {

return restClient.post("/create", orgRequest, OrganizationResponse.class);
return restClient.post("/api/v1/registration/" + registrationId + "/register", new UserProfileRequestWrapper(orgRequest), OrganizationResponse.class);
}

@Override
public OrganizationResponse verifyNewOrg(String identifier, String code) throws FactorVerificationException, IOException {

String postBody = "{\"code\":\"" + code + "\"}";

try {
return restClient.post("/verify/" + identifier, postBody, OrganizationResponse.class);
} catch (RestException e) {
throw new FactorVerificationException(e.getErrorResponse(), e);
}
public OrganizationResponse verifyNewOrg(String identifier) throws RestException, IOException {
return restClient.get("/api/internal/v1/developer/redeem/" + identifier, OrganizationResponse.class);
}

}
Loading

0 comments on commit 4cfe9da

Please sign in to comment.