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:
- The banner photo is by chuttersnap on Unsplash
- You can do this easily with ACS Commons Ensure Authorizable feature, but I did not want to depend on ACS commons.
- 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 touserManager.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.