From 4161745f1941fc29ce7be54aa087e591dede3fca Mon Sep 17 00:00:00 2001
From: Jean-Noël Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 16 Nov 2015 16:35:19 +0000
Subject: [PATCH] OPENDJ-2383 REST interface: Implement password modify action
---
opendj-sdk/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java | 93 ++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 89 insertions(+), 4 deletions(-)
diff --git a/opendj-sdk/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java b/opendj-sdk/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
index 0c42180..a3fb0ae 100644
--- a/opendj-sdk/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
+++ b/opendj-sdk/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/LDAPCollectionResourceProvider.java
@@ -27,10 +27,12 @@
import static org.forgerock.opendj.rest2ldap.Utils.i18n;
import static org.forgerock.opendj.rest2ldap.Utils.toFilter;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
@@ -38,6 +40,7 @@
import org.forgerock.json.JsonPointer;
import org.forgerock.json.JsonValue;
+import org.forgerock.json.JsonValueException;
import org.forgerock.json.resource.ActionRequest;
import org.forgerock.json.resource.ActionResponse;
import org.forgerock.json.resource.CollectionResourceProvider;
@@ -79,12 +82,17 @@
import org.forgerock.opendj.ldap.controls.SubtreeDeleteRequestControl;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldap.requests.PasswordModifyExtendedRequest;
+import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.responses.PasswordModifyExtendedResult;
import org.forgerock.opendj.ldap.responses.Result;
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.ldap.responses.SearchResultReference;
import org.forgerock.opendj.ldif.ChangeRecord;
+import org.forgerock.services.context.ClientContext;
import org.forgerock.services.context.Context;
+import org.forgerock.services.context.SecurityContext;
import org.forgerock.util.AsyncFunction;
import org.forgerock.util.Function;
import org.forgerock.util.promise.ExceptionHandler;
@@ -134,8 +142,82 @@
@Override
public Promise<ActionResponse, ResourceException> actionInstance(
final Context context, final String resourceId, final ActionRequest request) {
+ String actionId = request.getAction();
+ if (actionId.equals("passwordModify")) {
+ return passwordModify(context, resourceId, request);
+ }
return Promises.<ActionResponse, ResourceException> newExceptionPromise(
- new NotSupportedException("Not yet implemented"));
+ new NotSupportedException("The action '" + actionId + "' is not supported"));
+ }
+
+ private Promise<ActionResponse, ResourceException> passwordModify(
+ final Context context, final String resourceId, final ActionRequest request) {
+ if (!context.containsContext(ClientContext.class)
+ || !context.asContext(ClientContext.class).isSecure()) {
+ return Promises.newExceptionPromise(ResourceException.newResourceException(
+ ResourceException.FORBIDDEN, "Password modify requires a secure connection."));
+ }
+ if (!context.containsContext(SecurityContext.class)
+ || context.asContext(SecurityContext.class).getAuthenticationId() == null) {
+ return Promises.newExceptionPromise(ResourceException.newResourceException(
+ ResourceException.FORBIDDEN, "Password modify requires user to be authenticated."));
+ }
+
+ final JsonValue jsonContent = request.getContent();
+ final String oldPassword;
+ final String newPassword;
+ try {
+ oldPassword = jsonContent.get("oldPassword").asString();
+ newPassword = jsonContent.get("newPassword").asString();
+ } catch (JsonValueException e) {
+ return Promises.newExceptionPromise(
+ ResourceException.newResourceException(ResourceException.BAD_REQUEST, e.getLocalizedMessage(), e));
+ }
+
+ final RequestState requestState = wrap(context);
+ return requestState.getConnection()
+ .thenAsync(new AsyncFunction<Connection, ActionResponse, ResourceException>() {
+ @Override
+ public Promise<ActionResponse, ResourceException> apply(final Connection connection)
+ throws ResourceException {
+ List<JsonPointer> attrs = Collections.emptyList();
+ return connection.searchSingleEntryAsync(searchRequest(requestState, resourceId, attrs))
+ .thenAsync(new AsyncFunction<SearchResultEntry, ActionResponse, ResourceException>() {
+ @Override
+ public Promise<ActionResponse, ResourceException> apply(
+ final SearchResultEntry entry) {
+ PasswordModifyExtendedRequest pwdModifyRequest =
+ Requests.newPasswordModifyExtendedRequest();
+ pwdModifyRequest.setUserIdentity("dn: " + entry.getName());
+ pwdModifyRequest.setOldPassword(asBytes(oldPassword));
+ pwdModifyRequest.setNewPassword(asBytes(newPassword));
+ return connection.extendedRequestAsync(pwdModifyRequest)
+ .thenAsync(new AsyncFunction<PasswordModifyExtendedResult,
+ ActionResponse, ResourceException>() {
+ @Override
+ public Promise<ActionResponse, ResourceException> apply(
+ PasswordModifyExtendedResult value) throws ResourceException {
+ JsonValue result = new JsonValue(new LinkedHashMap<>());
+ byte[] generatedPwd = value.getGeneratedPassword();
+ if (generatedPwd != null) {
+ result = result.put("generatedPassword", ByteString.valueOfBytes(generatedPwd).toString());
+ }
+ return Responses.newActionResponse(result).asPromise();
+ }
+ }, ldapExceptionToResourceException());
+ }
+ }, ldapExceptionToResourceException());
+ }
+
+ private AsyncFunction<LdapException, ActionResponse, ResourceException>
+ ldapExceptionToResourceException() {
+ return ldapToResourceException();
+ }
+ }).thenFinally(close(requestState));
+ }
+
+ private byte[] asBytes(final String s) {
+ return s != null ? s.getBytes(StandardCharsets.UTF_8) : null;
}
@Override
@@ -928,11 +1010,14 @@
}
private AsyncFunction<LdapException, ResourceResponse, ResourceException> ldapExceptionToResourceException() {
+ return ldapToResourceException();
+ }
+
+ private <R> AsyncFunction<LdapException, R, ResourceException> ldapToResourceException() {
// The handler which will be invoked for the LDAP add result.
- return new AsyncFunction<LdapException, ResourceResponse, ResourceException>() {
+ return new AsyncFunction<LdapException, R, ResourceException>() {
@Override
- public Promise<ResourceResponse, ResourceException> apply(final LdapException ldapException)
- throws ResourceException {
+ public Promise<R, ResourceException> apply(final LdapException ldapException) throws ResourceException {
return Promises.newExceptionPromise(asResourceException(ldapException));
}
};
--
Gitblit v1.10.0