Skip to content

Commit 30dcd61

Browse files
author
Jeff Bornemann
committed
Automatically avoid modifying admin user
1 parent d17519c commit 30dcd61

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
@@ -42,7 +42,7 @@ import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE
4242
class AuthorizableProtoNodeDecoratorSpec extends Specification {
4343

4444

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

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

@@ -185,6 +185,39 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
185185
}
186186

187187

188+
def "Does not attempt to modify the administrator"() {
189+
when:
190+
final adminNode = Mock(Node) {
191+
getProperty(JCR_PRIMARYTYPE) >> Mock(Property) {
192+
it.getString() >> 'rep:User'
193+
}
194+
getProperties() >> Mock(PropertyIterator) {
195+
it.toList() >> []
196+
}
197+
}
198+
final session = Mock(Session) {
199+
it.getNode('/home/users/m/a') >> adminNode
200+
}
201+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'admin') {
202+
it.getSecurityManager() >> Mock(SecurityManager) {
203+
it.checkPermission(_) >> {
204+
return
205+
}
206+
}
207+
it.getUserManager(session) >> Mock(UserManager) {
208+
it.getAuthorizable('admin') >> Mock(Authorizable) {
209+
it.getPath() >> '/home/users/m/a'
210+
}
211+
}
212+
}
213+
214+
final JCRNodeDecorator resultNode = protoNodeDecorator.writeToJcr(session)
215+
216+
then:
217+
(resultNode as Node) == adminNode
218+
}
219+
220+
188221
def "Passes security check if all JVM permissions are present"() {
189222
when:
190223
final session = Mock(Session) {
@@ -281,7 +314,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
281314
1 * it.setProperty('cq:authorizableCategory', new StringValue('mcm'))
282315
it.getPath() >> 'newUserPath'
283316
}
284-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false) {
317+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'authorizableID') {
285318
it.getName() >> '/home/users/auth_folder/user'
286319
it.getSecurityManager() >> null
287320
it.setPasswordForUser(newUser, session) >> {
@@ -356,7 +389,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
356389
final session = Mock(Session) {
357390
it.getNode('/home/users/u/newuser') >> node
358391
}
359-
final protoNodeDecorator = theProtoNodeDecoratorForUser(exists, false) {
392+
final protoNodeDecorator = theProtoNodeDecoratorForUser(exists, false, 'authorizableID') {
360393
it.getSecurityManager() >> null
361394
it.getUserManager(session) >> Mock(UserManager) {
362395
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
@@ -392,7 +425,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
392425
final session = Mock(Session) {
393426
it.getNode('/home/users/u/newuser') >> node
394427
}
395-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, exists) {
428+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, exists, 'authorizableID') {
396429
it.getSecurityManager() >> null
397430
it.getUserManager(session) >> Mock(UserManager) {
398431
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
@@ -431,7 +464,7 @@ class AuthorizableProtoNodeDecoratorSpec extends Specification {
431464
1 * it.removeMember(_)
432465
1 * it.addMember(_)
433466
}
434-
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false) {
467+
final protoNodeDecorator = theProtoNodeDecoratorForUser(false, false, 'authorizableID') {
435468
it.getUserManager(session) >> Mock(UserManager) {
436469
it.getAuthorizable('authorizableID') >> Mock(Authorizable) {
437470
it.declaredMemberOf() >> [group].iterator()

0 commit comments

Comments
 (0)