Including Service Users in Your AEM Package | Perficient Digital

Including Service Users in Your AEM Package

While working on a project recently, I needed to include a service user within the Adobe Experience Manager package I was deploying. By doing this, administrators wouldn’t have to create the service users manually During this process, I ran into a few exceptions and wanted to share.

A few things to note:

  1. The banner photo is by chuttersnap on Unsplash
  2. You can do this easily with ACS Commons Ensure Authorizable feature, but I did not want to depend on ACS commons.
  3. All of this was done on AEM 6.4, though I assume the same issue would happen on 6.3.

Now onto the good stuff!

Adding my service user to the package

In my package, I created the following path:

/home/users/system/my-project/my-project-service-user

I then added the following properties:

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root
    xmlns:jcr="http://www.jcp.org/jcr/1.0"
    xmlns:rep="internal"
    jcr:primaryType="rep:SystemUser"
    jcr:uuid="bf2451f1-e091-3b27-90b1-52d7701bc60f"
    rep:authorizableId="my-project-service-user"
    rep:principalName="my-project-service-user"/>

 

Which is the same as the way ACS commons have their system users set up.

Deploying and errors:

When deploying, this error is printed in the console:

Request failed: org.apache.jackrabbit.vault.packaging.PackageException: javax.jcr.nodetype.ConstraintViolationException: OakConstraint0021: /home/users/system/my-project/my-project-service-user[[rep:SystemUser]]: Mandatory property rep:principalName not found in a new node (500)

But the rep:principalName was there!

Now, looking at the error logs:

5.01.2019 12:07:35.913 *ERROR* [qtp1214328009-1747] org.apache.jackrabbit.vault.fs.impl.io.GenericArtifactHandler Error while parsing jcr_root/home/users/system/my-project/my-project-service-user/.content.xml: {}
org.xml.sax.SAXException: Cannot handle protected PropInfo org.apache.jackrabbit.oak.spi.xml.PropInfo@715c673d. Invalid rep:authorizableId.
  at org.apache.jackrabbit.oak.jcr.xml.SysViewImportHandler.processNode(SysViewImportHandler.java:92) [org.apache.jackrabbit.oak-jcr:1.8.9]
  at org.apache.jackrabbit.oak.jcr.xml.SysViewImportHandler.endElement(SysViewImportHandler.java:221) [org.apache.jackrabbit.oak-jcr:1.8.9]
  at org.apache.jackrabbit.oak.jcr.xml.ImportHandler.endElement(ImportHandler.java:197) [org.apache.jackrabbit.oak-jcr:1.8.9]
  at org.apache.jackrabbit.vault.fs.impl.io.JcrSysViewTransformer.endNode(JcrSysViewTransformer.java:189) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.impl.io.DocViewSAXImporter.endElement(DocViewSAXImporter.java:1155) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(AbstractSAXParser.java:609)
  at com.sun.org.apache.xerces.internal.parsers.AbstractXMLDocumentParser.emptyElement(AbstractXMLDocumentParser.java:183)
  at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:351)
  at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
  at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3132)
  at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:852)
  at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:602)
  at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
  at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:505)
  at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:842)
  at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:771)
  at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
  at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213)
  at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:643)
  at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl.parse(SAXParserImpl.java:327)
  at org.apache.jackrabbit.vault.fs.impl.io.GenericArtifactHandler.accept(GenericArtifactHandler.java:99) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:929) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:798) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:838) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:838) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:838) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:838) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.commit(Importer.java:838) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.fs.io.Importer.run(Importer.java:436) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.packaging.impl.ZipVaultPackage.extract(ZipVaultPackage.java:233) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl.extract(JcrPackageImpl.java:400) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl.extract(JcrPackageImpl.java:359) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at org.apache.jackrabbit.vault.packaging.impl.JcrPackageImpl.install(JcrPackageImpl.java:353) [org.apache.jackrabbit.vault:3.2.5.R1844726]
  at com.day.crx.packmgr.impl.servlets.ServiceServlet.doInstall(ServiceServlet.java:437) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at com.day.crx.packmgr.impl.servlets.ServiceServlet.upload(ServiceServlet.java:512) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at com.day.crx.packmgr.impl.servlets.ServiceServlet.doService(ServiceServlet.java:180) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at com.day.crx.packmgr.impl.AbstractServlet.service(AbstractServlet.java:54) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at com.day.crx.packmgr.impl.MainServlet.doService(MainServlet.java:158) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at com.day.crx.packmgr.impl.MainServlet.service(MainServlet.java:135) [com.adobe.granite.crx-packagemgr:1.2.60.CQ640-B0002]
  at org.apache.felix.http.base.internal.handler.ServletHandler.handle(ServletHandler.java:120) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:86) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.sling.security.impl.ReferrerFilter.doFilter(ReferrerFilter.java:328) [org.apache.sling.security:1.1.12]
  at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:135) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:81) [org.apache.felix.http.jetty:4.0.6]
  at com.adobe.granite.license.impl.LicenseCheckFilter.doFilter(LicenseCheckFilter.java:308) [com.adobe.granite.license:1.2.6.CQ640-B0001]
  at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:135) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:81) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.sslfilter.internal.SslFilter.doFilter(SslFilter.java:96) [org.apache.felix.http.sslfilter:1.2.4]
  at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:135) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:81) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.sling.i18n.impl.I18NFilter.doFilter(I18NFilter.java:131) [org.apache.sling.i18n:2.5.14]
  at org.apache.felix.http.base.internal.handler.FilterHandler.handle(FilterHandler.java:135) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.InvocationChain.doFilter(InvocationChain.java:81) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.Dispatcher$1.doFilter(Dispatcher.java:146) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.whiteboard.WhiteboardManager.invokePreprocessors(WhiteboardManager.java:1000) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.Dispatcher.dispatch(Dispatcher.java:91) [org.apache.felix.http.jetty:4.0.6]
  at org.apache.felix.http.base.internal.dispatch.DispatcherServlet.service(DispatcherServlet.java:49) [org.apache.felix.http.jetty:4.0.6]
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:725) [org.apache.felix.http.servlet-api:1.1.2]
  at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:865) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:535) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1595) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:255) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1340) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:203) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:473) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1564) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:201) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1242) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:220) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.Server.handle(Server.java:503) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:364) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:305) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:103) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:765) [org.apache.felix.http.jetty:4.0.6]
  at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:683) [org.apache.felix.http.jetty:4.0.6]
  at java.lang.Thread.run(Thread.java:748)
Caused by: javax.jcr.nodetype.ConstraintViolationException: Cannot handle protected PropInfo org.apache.jackrabbit.oak.spi.xml.PropInfo@715c673d. Invalid rep:authorizableId.
  at org.apache.jackrabbit.oak.security.user.UserImporter.handlePropInfo(UserImporter.java:244) [org.apache.jackrabbit.oak-core:1.8.9]
  at org.apache.jackrabbit.oak.jcr.xml.ImporterImpl.importProperties(ImporterImpl.java:280) [org.apache.jackrabbit.oak-jcr:1.8.9]
  at org.apache.jackrabbit.oak.jcr.xml.ImporterImpl.startNode(ImporterImpl.java:463) [org.apache.jackrabbit.oak-jcr:1.8.9]
  at org.apache.jackrabbit.oak.jcr.xml.SysViewImportHandler.processNode(SysViewImportHandler.java:81) [org.apache.jackrabbit.oak-jcr:1.8.9]
  ... 80 common frames omitted

And that was even more puzzling…

A debugging session to the rescue!

I was perplexed, so I reached out to my coworker, Paul Bjorkstrand, and together we debugged the Jackrabbit source code looking for clues. We later discovered that the jcr:uuid property is actually derived from the rep:authorizableId value, and is NOT just a random UUID.

If you’d like to see for yourself, follow the source code for jackrabbit starting with:

https://github.com/apache/jackrabbit-oak/blob/1.8/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java#L240. specifically, the call to userManager.getAuthorizable(id); and following the code along till you arrive at: https://github.com/apache/jackrabbit-oak/blob/trunk/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/UUIDUtils.java#L35

The solution

So, since the UUID is derived from the rep:authorizableId (the user name), I just create that service user manually then copy the generated UUID for that user and add it to my source-code. And voila, problem solved!

Special thanks to Paul Bjorkstrand for the exceptional help with this.

Leave a Reply