diff --git a/MIGRATING.md b/MIGRATING.md index b0c06f06da7..605abad5566 100644 --- a/MIGRATING.md +++ b/MIGRATING.md @@ -18,6 +18,15 @@ Below methods have been added. - `UserSchema updateApplicationUserProfile(String appInstanceId, UserSchema userSchema)` - `UserSchema updateApplicationUserProfile(String appInstanceId)` - `UserSchema updateUserProfile(String schemaId, UserSchema userSchema)` + +Below method has been removed. +- `ForgotPasswordResponse apiV1UsersUserIdCredentialsForgotPasswordPost(String userId)` + +One of below listed methods could be used instead: +- `User.forgotPasswordGenerateOneTimeToken(Boolean sendEmail)` +- `User.forgotPasswordGenerateOneTimeToken()` +- `User.forgotPasswordSetNewPassword(UserCredentials userCredentials, Boolean sendEmail)` +- `User.forgotPasswordSetNewPassword(UserCredentials userCredentials)` ### Package `com.okta.sdk.resource.user.type.UserType` @@ -304,6 +313,11 @@ Below method has undergone a signature change in the interest of naming consiste - `void addAllAppsAsTargetToRole()` to `void addAllAppsAsTarget(String roleId)` - `void deleteFactor()` to `void deleteFactor(String factorId)` +Below methods have been added. +- `ForgotPasswordResponse forgotPasswordGenerateOneTimeToken(Boolean sendEmail)` +- `ForgotPasswordResponse forgotPasswordGenerateOneTimeToken()` +- `ForgotPasswordResponse forgotPasswordSetNewPassword(UserCredentials userCredentials, Boolean sendEmail)` +- `ForgotPasswordResponse forgotPasswordSetNewPassword(UserCredentials userCredentials)` ## Migrating from 2.x.x to 3.0.0 diff --git a/integration-tests/src/test/groovy/com/okta/sdk/tests/it/UsersIT.groovy b/integration-tests/src/test/groovy/com/okta/sdk/tests/it/UsersIT.groovy index cf884af81ab..f2f5ae32495 100644 --- a/integration-tests/src/test/groovy/com/okta/sdk/tests/it/UsersIT.groovy +++ b/integration-tests/src/test/groovy/com/okta/sdk/tests/it/UsersIT.groovy @@ -33,6 +33,7 @@ import com.okta.sdk.resource.role.AssignRoleRequest import com.okta.sdk.resource.role.RoleType import com.okta.sdk.resource.user.AuthenticationProviderType import com.okta.sdk.resource.user.ChangePasswordRequest +import com.okta.sdk.resource.user.ForgotPasswordResponse import com.okta.sdk.resource.user.PasswordCredential import com.okta.sdk.resource.user.RecoveryQuestionCredential import com.okta.sdk.resource.user.ResetPasswordToken @@ -761,6 +762,67 @@ class UsersIT extends ITSupport implements CrudTestSupport { assertThat user.getCredentials().getProvider().getType(), is(AuthenticationProviderType.IMPORT) } + @Test + @Scenario("user-forgot-password-generate-one-time-token") + void forgotPasswordGenerateOttTest() { + + def password = 'Passw0rd!2@3#' + def firstName = 'John' + def lastName = 'Forgot-Password' + def email = "john-${uniqueTestName}@example.com" + + // 1. Create a user + User user = UserBuilder.instance() + .setEmail(email) + .setFirstName(firstName) + .setLastName(lastName) + .setPassword(password.toCharArray()) + .setActive(true) + .setSecurityQuestion("How many roads must a man walk down?") + .setSecurityQuestionAnswer("forty two") + .buildAndCreate(client) + registerForCleanup(user) + validateUser(user, firstName, lastName, email) + + ForgotPasswordResponse response = user.forgotPasswordGenerateOneTimeToken(false) + assertThat response.getResetPasswordUrl(), containsString("/signin/reset-password/") + } + + @Test + @Scenario("user-forgot-password-set-new-password") + void forgotPasswordSetNewPasswordTest() { + + def password = 'OldPassw0rd!2@3#' + def firstName = 'John' + def lastName = 'Forgot-Password' + def email = "john-${uniqueTestName}@example.com" + + // 1. Create a user + User user = UserBuilder.instance() + .setEmail(email) + .setFirstName(firstName) + .setLastName(lastName) + .setPassword(password.toCharArray()) + .setActive(true) + .setSecurityQuestion("How many roads must a man walk down?") + .setSecurityQuestionAnswer("forty two") + .buildAndCreate(client) + registerForCleanup(user) + validateUser(user, firstName, lastName, email) + + UserCredentials userCredentials = client.instantiate(UserCredentials) + .setPassword(client.instantiate(PasswordCredential) + .setValue('NewPassw0rd!2@3#'.toCharArray())) + .setRecoveryQuestion(client.instantiate(RecoveryQuestionCredential) + .setQuestion('How many roads must a man walk down?') + .setAnswer('forty two')) + + ForgotPasswordResponse response = user.forgotPasswordSetNewPassword(userCredentials, false) + assertThat response.get("recovery_question")["question"], equalTo("How many roads must a man walk down?") + assertThat response.get("provider")["type"], equalTo("OKTA") + assertThat response.get("provider")["name"], equalTo("OKTA") + } + private void ensureCustomProperties() { def userSchemaUri = "/api/v1/meta/schemas/user/default" diff --git a/swagger-templates/src/main/java/com/okta/swagger/codegen/AbstractOktaJavaClientCodegen.java b/swagger-templates/src/main/java/com/okta/swagger/codegen/AbstractOktaJavaClientCodegen.java index 6fd148a60d4..054362eb47c 100644 --- a/swagger-templates/src/main/java/com/okta/swagger/codegen/AbstractOktaJavaClientCodegen.java +++ b/swagger-templates/src/main/java/com/okta/swagger/codegen/AbstractOktaJavaClientCodegen.java @@ -35,10 +35,12 @@ import io.swagger.models.Response; import io.swagger.models.Swagger; import io.swagger.models.parameters.BodyParameter; +import io.swagger.models.parameters.Parameter; import io.swagger.models.properties.ArrayProperty; import io.swagger.models.properties.Property; import io.swagger.models.properties.RefProperty; import io.swagger.parser.SwaggerException; +import io.swagger.util.Json; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -338,17 +340,36 @@ private void handleOktaLinkedOperations(Swagger swagger) { swagger.getPaths().forEach((pathName, path) -> { Optional> operationEntry = path.getOperationMap().entrySet().stream().filter( - e -> e.getValue().getOperationId() != null && - e.getValue().getOperationId().equals(operationId)).findFirst(); + oper -> { + //Looking for an operationId in paths:path:operationId + if (oper.getValue().getOperationId() != null + && oper.getValue().getOperationId().equals(operationId)) { + return true; + } + //Looking for an operationId in paths:path:method:x-okta-multi-operation:operationId + List xOktaMultiOperation = getOktaMultiOperationObject(oper.getValue()); + if (xOktaMultiOperation != null && + xOktaMultiOperation + .stream() + .anyMatch(multiOper -> multiOper.getOperationId().equals(operationId)) + ) { + return true; + } + return false; + } + ).findFirst(); if (operationEntry.isPresent()) { Operation operation = operationEntry.get().getValue(); + //Trying to get an Operation from x-okta-multi-operation + Operation xOktaMultiOperation = produceOperationFromXOktaMultiOperation(operation, operationId); + CodegenOperation cgOperation = fromOperation( pathName, operationEntry.get().getKey().name().toLowerCase(), - operation, + xOktaMultiOperation != null ? xOktaMultiOperation : operation, swagger.getDefinitions(), swagger); @@ -465,6 +486,77 @@ else if ("read".equals(alias) || "create".equals(alias)) { }); } + private List getOktaMultiOperationObject(Operation operation) { + Object multiOperationObject = operation.getVendorExtensions().get("x-okta-multi-operation"); + List xOktaMultiOperationList = new ArrayList<>(); + if (multiOperationObject instanceof List) { + for(Object node : (List)multiOperationObject) { + Operation multiOperation = Json.mapper().convertValue(node, Operation.class); + xOktaMultiOperationList.add(multiOperation); + } + return xOktaMultiOperationList; + } + return null; + } + + private Operation produceOperationFromXOktaMultiOperation(Operation operation, String operationId) { + + Operation xOktaMultiOperation = null; + + List xOktaMultiOperationList = getOktaMultiOperationObject(operation); + if (xOktaMultiOperationList != null) { + Optional operationFromXOktaMultiOperation = xOktaMultiOperationList.stream() + .filter(multiOper -> multiOper.getOperationId().equals(operationId)).findFirst(); + + if (operationFromXOktaMultiOperation.isPresent()) { + Operation xOktaMultiOperationTmp = operationFromXOktaMultiOperation.get(); + xOktaMultiOperation = new Operation(); + + // VendorExtensions deep copy + Map vendorExtensions = new LinkedHashMap<>(operation.getVendorExtensions()); + xOktaMultiOperation.setVendorExtensions(vendorExtensions); + + // Tags deep copy + List tags = new ArrayList<>(operation.getTags()); + xOktaMultiOperation.setTags(tags); + + xOktaMultiOperation.setSummary(operation.getSummary()); + xOktaMultiOperation.setDescription(xOktaMultiOperationTmp.getDescription()); + xOktaMultiOperation.setOperationId(xOktaMultiOperationTmp.getOperationId()); + + // Consumes deep copy + List consumes = new ArrayList<>(operation.getConsumes()); + xOktaMultiOperation.setConsumes(consumes); + + // Produces deep copy + List produces = new ArrayList<>(operation.getProduces()); + xOktaMultiOperation.setProduces(produces); + + // Parameters deep copy + List parameters = new ArrayList<>(operation.getParameters()); + xOktaMultiOperation.setParameters(parameters); + + // Responses deep copy + Map responses = new LinkedHashMap<>(operation.getResponses()); + xOktaMultiOperation.setResponses(responses); + + // Security deep copy + List>> security = new ArrayList<>(operation.getSecurity()); + xOktaMultiOperation.setSecurity(security); + + //Add params defined in x-okta-multi-operation + for(Parameter p: xOktaMultiOperationTmp.getParameters()) { + if (p instanceof BodyParameter && ((BodyParameter) p).getSchema() != null) { + xOktaMultiOperation.getParameters().add(p); + } else if (!(p instanceof BodyParameter)) { + xOktaMultiOperation.getParameters().add(p); + } + } + } + } + return xOktaMultiOperation; + } + private Map createArgMap(ObjectNode n) { Map argMap = new LinkedHashMap<>();