Skip to content

Commit a55671d

Browse files
author
Jeff Bornemann
committed
Automatically avoid modifying admin user
1 parent a44e735 commit a55671d

File tree

4 files changed

+56
-28
lines changed

4 files changed

+56
-28
lines changed

docs/Running.adoc

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -181,20 +181,3 @@ Invalid:
181181
]
182182
}
183183
```
184-
185-
=== Syncing Users and Groups
186-
187-
Grabbit has support for syncing users and groups. One *important note* about syncing users is that you must take care to avoid syncing the _admin user_.
188-
Jackrabbit will not allow modification of the admin user, so Grabbit will fail on a job that attempts to do so. You can find the path of your admin user
189-
on your data-warehouse instance or other source instance; and add it as an exclude path as so:
190-
191-
```
192-
pathConfigurations :
193-
-
194-
path : /home/groups
195-
-
196-
path : /home/users
197-
excludePaths:
198-
- k/ki9zhpzfe #Admin user
199-
```
200-

src/main/groovy/com/twcable/grabbit/jcr/AuthorizableProtoNodeDecorator.groovy

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,13 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
5555
throw new InsufficientGrabbitPrivilegeException("JVM Permissions needed by Grabbit to sync Users/Groups were not found. See log for specific permissions needed, and add these to your security manager; or do not sync users and groups." +
5656
"Unfortunately, the way Jackrabbit goes about certain things requires us to do a bit of hacking in order to sync Authorizables securely, and efficiently.")
5757
}
58-
Authorizable existingAuthorizable = findAuthorizable(session)
59-
Authorizable newAuthorizable = existingAuthorizable ? updateAuthorizable(existingAuthorizable, session) : createNewAuthorizable(session)
58+
//the administrator is a special user that Jackrabbit will not let us mess with.
59+
if(getAuthorizableID() == 'admin') {
60+
return new JCRNodeDecorator(session.getNode(findAuthorizable(session, 'admin').getPath()))
61+
}
6062

63+
Authorizable existingAuthorizable = findAuthorizable(session, getAuthorizableID())
64+
Authorizable newAuthorizable = existingAuthorizable ? updateAuthorizable(existingAuthorizable, session) : createNewAuthorizable(session)
6165
return new JCRNodeDecorator(session.getNode(newAuthorizable.getPath()), getID())
6266
}
6367

@@ -123,9 +127,9 @@ class AuthorizableProtoNodeDecorator extends ProtoNodeDecorator {
123127
}
124128

125129

126-
private Authorizable findAuthorizable(final Session session) {
130+
private Authorizable findAuthorizable(final Session session, final String authorizableID) {
127131
final UserManager userManager = getUserManager(session)
128-
return userManager.getAuthorizable(getAuthorizableID())
132+
return userManager.getAuthorizable(authorizableID)
129133
}
130134

131135

src/main/groovy/com/twcable/grabbit/jcr/JCRNodeDecorator.groovy

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import org.apache.jackrabbit.api.security.user.UserManager
3535
import org.apache.jackrabbit.commons.flat.TreeTraverser
3636
import org.apache.jackrabbit.value.DateValue
3737
import org.apache.sling.jcr.base.util.AccessControlUtil
38+
import org.slf4j.Logger
3839

3940

4041
import static org.apache.jackrabbit.JcrConstants.JCR_CREATED
@@ -169,7 +170,7 @@ class JCRNodeDecorator {
169170
try {
170171
return new JCRNodeDecorator(getSession().getNodeByIdentifier(value.string))
171172
} catch(ItemNotFoundException ex) {
172-
log?.info "Tried following reference ${value.string} from ${getInnerNode().path}, but this node does not exist any longer. Skipping"
173+
_log().info "Tried following reference ${value.string} from ${getInnerNode().path}, but this node does not exist any longer. Skipping"
173174
}
174175
}
175176
} as Collection<JCRNodeDecorator>
@@ -345,6 +346,13 @@ class JCRNodeDecorator {
345346
return innerNode.getName().hashCode()
346347
}
347348

349+
/**
350+
* @SL4J generated log property, and @Delegate conflict on accessing log sometimes within closures. This is to get around that
351+
*/
352+
private static Logger _log() {
353+
return log
354+
}
355+
348356

349357
@CompileStatic
350358
private static class NoRootInclusionPolicy implements InclusionPolicy<JCRNode> {

src/test/groovy/com/twcable/grabbit/jcr/AuthorizableProtoNodeDecoratorSpec.groovy

Lines changed: 39 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE
4343
class AuthorizableProtoNodeDecoratorSpec extends Specification {
4444

4545

46-
AuthorizableProtoNodeDecorator theProtoNodeDecoratorForUser(boolean hasProfile, boolean hasPreferences, Closure configuration = null){
46+
AuthorizableProtoNodeDecorator theProtoNodeDecoratorForUser(boolean hasProfile, boolean hasPreferences, String id, Closure configuration = null){
4747
ProtoNodeBuilder nodeBuilder = ProtoNode.newBuilder()
4848
nodeBuilder.setName('/home/users/u/user1')
4949

@@ -70,7 +70,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
7070
.setName('rep:authorizableId')
7171
.setType(STRING)
7272
.setMultiple(false)
73-
.addValues(ProtoValue.newBuilder().setStringValue('authorizableID'))
73+
.addValues(ProtoValue.newBuilder().setStringValue(id))
7474
.build()
7575
nodeBuilder.addProperties(authorizableIdProperty)
7676

@@ -186,6 +186,39 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
186186
}
187187

188188

189+
def "Does not attempt to modify the administrator"() {
190+
when:
191+
final adminNode = Mock(Node) {
192+
getProperty(JCR_PRIMARYTYPE) >> Mock(Property) {
193+
it.getString() >> 'rep:User'
194+
}
195+
getProperties() >> Mock(PropertyIterator) {
196+
it.toList() >> []
197+
}
198+
}
199+
final session = Mock(Session) {
200+
it.getNode('/home/users/m/a') >> adminNode
201+
}
202+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'admin') {
203+
it.getSecurityManager() >> Mock(SecurityManager) {
204+
it.checkPermission(_) >> {
205+
return
206+
}
207+
}
208+
it.getUserManager(session) >> Mock(UserManager) {
209+
it.getAuthorizable('admin') >> Mock(Authorizable) {
210+
it.getPath() >> '/home/users/m/a'
211+
}
212+
}
213+
}
214+
215+
final JCRNodeDecorator resultNode = protoNodeDecorator.writeToJcr(session)
216+
217+
then:
218+
(resultNode as Node) == adminNode
219+
}
220+
221+
189222
def "Passes security check if all JVM permissions are present"() {
190223
when:
191224
final session = Mock(Session) {
@@ -291,7 +324,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
291324
1 * it.setProperty('cq:authorizableCategory', new StringValue('mcm'))
292325
it.getPath() >> 'newUserPath'
293326
}
294-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false) {
327+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'authorizableID') {
295328
it.getName() >> '/home/users/auth_folder/user'
296329
it.getSecurityManager() >> null
297330
it.setPasswordForUser(newUser, session) >> {
@@ -372,7 +405,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
372405
final session = Mock(Session) {
373406
it.getNode('/home/users/u/newuser') >> node
374407
}
375-
final protoNodeDecorator = theProtoNodeDecoratorForUser(exists, false) {
408+
final protoNodeDecorator = theProtoNodeDecoratorForUser(exists, false, 'authorizableID') {
376409
it.getSecurityManager() >> null
377410
it.getUserManager(session) >> Mock(UserManager) {
378411
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
@@ -411,7 +444,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
411444
final session = Mock(Session) {
412445
it.getNode('/home/users/u/newuser') >> node
413446
}
414-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, exists) {
447+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, exists, 'authorizableID') {
415448
it.getSecurityManager() >> null
416449
it.getUserManager(session) >> Mock(UserManager) {
417450
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
@@ -453,7 +486,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
453486
1 * it.removeMember(_)
454487
1 * it.addMember(_)
455488
}
456-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false) {
489+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'authorizableID') {
457490
it.getUserManager(session) >> Mock(UserManager) {
458491
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
459492
it.declaredMemberOf() >> [group].iterator()

0 commit comments

Comments
 (0)