@@ -25,7 +25,6 @@ import groovy.util.logging.Slf4j
2525import java.lang.reflect.Field
2626import java.lang.reflect.Method
2727import java.lang.reflect.ReflectPermission
28- import java.util.regex.Pattern
2928import javax.annotation.Nonnull
3029import javax.jcr.Session
3130import org.apache.jackrabbit.api.security.user.Authorizable
@@ -35,7 +34,6 @@ import org.apache.jackrabbit.api.security.user.UserManager
3534import org.apache.jackrabbit.value.StringValue
3635import org.apache.sling.jcr.base.util.AccessControlUtil
3736
38-
3937/**
4038 * This class wraps a serialized node that represents an Authorizable. Authorizables are special system protected nodes, that can only be written under certain
4139 * trees, and can not be written directly by a client.
@@ -59,8 +57,8 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
5957 }
6058 Authorizable existingAuthorizable = findAuthorizable(session)
6159 Authorizable newAuthorizable = existingAuthorizable ? updateAuthorizable(existingAuthorizable, session) : createNewAuthorizable(session)
62- writeAuthorizablePieces(newAuthorizable, session)
63- return new JCRNodeDecorator (session. getNode(newAuthorizable. getPath()))
60+
61+ return new JCRNodeDecorator (session. getNode(newAuthorizable. getPath()), getID() )
6462 }
6563
6664
@@ -86,11 +84,20 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
8684 setPasswordForUser(newUser, session)
8785 }
8886 session. save()
87+ writeMandatoryPieces(session, newUser. getPath())
8988 return newUser
9089 }
91- final Group group = userManager. createGroup(authorizableID, new AuthorizablePrincipal (authorizableID), getParentPath())
90+ final Group newGroup = userManager. createGroup(authorizableID, new AuthorizablePrincipal (authorizableID), getParentPath())
91+ /*
92+ * Write all mandatory pieces, and find those that are authorizables. We then need to see if any of them have membership in this group, and add them.
93+ */
94+ final Collection<JCRNodeDecorator > authorizablePieces = writeMandatoryPieces(session, newGroup. getPath()). findAll { it. isAuthorizableType() }
95+ final Collection<JCRNodeDecorator > members = authorizablePieces. findAll { getMembershipIDs(). contains(it. getTransferredID()) }
96+ members. each { JCRNodeDecorator member ->
97+ newGroup. addMember(member as Authorizable )
98+ }
9299 session. save()
93- return group
100+ return newGroup
94101 }
95102
96103
@@ -100,22 +107,19 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
100107 * @return new instance of updated authorizable
101108 */
102109 private Authorizable updateAuthorizable (final Authorizable authorizable , final Session session ) {
110+ // We get all the declared groups of this authorizable so that we can add them back to the new, updated authorizable
111+ final Collection<Group > declaredGroups = authorizable. declaredMemberOf(). toList()
112+ for (Group group : declaredGroups) {
113+ group. removeMember(authorizable)
114+ }
103115 authorizable. remove()
104116 session. save()
105- createNewAuthorizable(session)
106- }
107-
108-
109- /**
110- * Authorizable pieces (nodes that live under Authorizables - profile, preferences, etc) get sent with the authorizable node instead of streamed independently because we do not know the client's new
111- * authorizable UUID node name at runtime. In other words, authorizables can live under different node names from server to server
112- */
113- private void writeAuthorizablePieces (final Authorizable authorizable , final Session session ) {
114- innerProtoNode. mandatoryChildNodeList. each {
115- // We replace the incoming server authorizable path, with the new authorizable path
116- createFrom(it, it. name. replaceFirst(Pattern . quote(getName()), authorizable. getPath())). writeToJcr(session)
117+ final Authorizable newAuthorizable = createNewAuthorizable(session)
118+ for (Group group : declaredGroups) {
119+ group. addMember(newAuthorizable)
117120 }
118121 session. save()
122+ return newAuthorizable
119123 }
120124
121125
@@ -135,6 +139,11 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
135139 }
136140
137141
142+ private Collection<String > getMembershipIDs () {
143+ return hasProperty(' rep:members' ) ? getStringValuesFrom(' rep:members' ) : []
144+ }
145+
146+
138147 /**
139148 * Some JVM's have a SecurityManager set, which based on configuration, can potentially inhibit our hack {@code setPasswordForUser(User, Session) } from working.
140149 * We need to check security permissions before proceeding
@@ -245,13 +254,4 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
245254 */
246255 setPasswordMethod. invoke(userManagerDelegate, getTreeMethod. invoke(authorizable), getAuthorizableID(), getStringValueFrom(' rep:password' ), false )
247256 }
248-
249-
250- /**
251- * An instance wrapper for ease of mocking
252- * @see super.createFrom
253- */
254- ProtoNodeDecorator createFrom (final ProtoNode protoNode , final String nameOverride ) {
255- super . createFrom(protoNode, nameOverride)
256- }
257257}
0 commit comments