Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManager.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManager.java	(revision )
@@ -24,6 +24,7 @@
 import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
 import org.apache.jackrabbit.api.security.user.Group;
 import org.apache.jackrabbit.api.security.user.Query;
 import org.apache.jackrabbit.api.security.user.User;
@@ -107,6 +108,15 @@
     public User createUser(String userID, String password, Principal principal, @Nullable String intermediatePath) throws RepositoryException {
         try {
             return wrap(dlg.createUser(userID, password, principal, intermediatePath));
+        } finally {
+            autosave();
+        }
+    }
+
+    @Override
+    public User createSystemUser(String userID, String intermediatePath) throws AuthorizableExistsException, RepositoryException {
+        try {
+            return wrap(dlg.createUser(userID, intermediatePath));
         } finally {
             autosave();
         }
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/SystemUserPrincipal.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/SystemUserPrincipal.java	(revision )
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/principal/SystemUserPrincipal.java	(revision )
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.spi.security.principal;
+
+import java.security.Principal;
+
+/**
+ * Principal used to mark a system user.
+ */
+public interface SystemUserPrincipal extends Principal {
+}
\ No newline at end of file
Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserManagerDelegator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserManagerDelegator.java	(revision 1616527)
+++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserManagerDelegator.java	(revision )
@@ -170,6 +170,18 @@
     }
 
     @Override
+    public User createSystemUser(final String userID, final String intermediatePath) throws AuthorizableExistsException, RepositoryException {
+        return sessionDelegate.perform(
+                new UserManagerOperation<User>(sessionDelegate, "createUser") {
+                    @Override
+                    public User perform() throws RepositoryException {
+                        User user = userManagerDelegate.createSystemUser(userID, intermediatePath);
+                        return UserDelegator.wrap(sessionDelegate, user);
+                    }
+                });
+    }
+
+    @Override
     public Group createGroup(final String groupID) throws AuthorizableExistsException, RepositoryException {
         return sessionDelegate.perform(
                 new UserManagerOperation<Group>(sessionDelegate, "createGroup") {
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java	(revision )
@@ -47,10 +47,10 @@
 
     private static final Logger log = LoggerFactory.getLogger(ImpersonationImpl.class);
 
-    private final UserImpl user;
+    private final AuthorizableImpl user;
     private final PrincipalManager principalManager;
 
-    ImpersonationImpl(UserImpl user) throws RepositoryException {
+    ImpersonationImpl(AuthorizableImpl user) throws RepositoryException {
         this.user = user;
         this.principalManager = user.getUserManager().getPrincipalManager();
     }
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/SystemUserImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/SystemUserImpl.java	(revision )
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/SystemUserImpl.java	(revision )
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.jackrabbit.oak.security.user;
+
+import java.security.Principal;
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.principal.SystemUserPrincipal;
+import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType;
+import org.apache.jackrabbit.oak.spi.security.user.util.UserUtil;
+
+/**
+ * Default implementation for system a system user.
+ */
+public class SystemUserImpl extends AuthorizableImpl implements User {
+
+    SystemUserImpl(@Nonnull String id, @Nonnull Tree tree, @Nonnull UserManagerImpl userManager) throws RepositoryException {
+        super(id, tree, userManager);
+    }
+
+    @Override
+    void checkValidTree(Tree tree) throws RepositoryException {
+        if (tree == null || !UserUtil.isType(tree, AuthorizableType.USER)) {
+            throw new IllegalArgumentException("Invalid user node: node type rep:SystemUser expected.");
+        }
+    }
+
+    @Override
+    public boolean isGroup() {
+        return false;
+    }
+
+    @Override
+    public Principal getPrincipal() throws RepositoryException {
+        return new SystemUserPrincipalImpl(getTree());
+    }
+
+    //---------------------------------------------------------------< User >---
+    @Override
+    public boolean isAdmin() {
+        return false;
+    }
+
+    @Override
+    public boolean isSystemUser() {
+        return true;
+    }
+
+    @Override
+    public Credentials getCredentials() throws RepositoryException {
+        return new CredentialsImpl(getID(), null);
+    }
+
+    @Override
+    public Impersonation getImpersonation() throws RepositoryException {
+        return new ImpersonationImpl(this);
+    }
+
+    @Override
+    public void changePassword(String password) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("system user");
+    }
+
+    @Override
+    public void changePassword(String password, String oldPassword) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("system user");
+    }
+
+    @Override
+    public void disable(String reason) throws RepositoryException {
+        throw new UnsupportedRepositoryOperationException("system user");
+    }
+
+    @Override
+    public boolean isDisabled() throws RepositoryException {
+        return false;
+    }
+
+    @Override
+    public String getDisabledReason() throws RepositoryException {
+        return null;
+    }
+
+    //--------------------------------------------------------------------------
+    private final class SystemUserPrincipalImpl extends TreeBasedPrincipal implements SystemUserPrincipal {
+
+        private SystemUserPrincipalImpl(Tree tree) throws RepositoryException {
+            super(getPrincipalName(), tree, getUserManager().getNamePathMapper());
+        }
+    }
+}
\ No newline at end of file
Index: oak-parent/pom.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-parent/pom.xml	(revision 1616527)
+++ oak-parent/pom.xml	(revision )
@@ -42,7 +42,7 @@
     <project.reporting.outputEncoding>
       ${project.build.sourceEncoding}
     </project.reporting.outputEncoding>
-    <jackrabbit.version>2.8.0</jackrabbit.version>
+    <jackrabbit.version>2.9-SNAPSHOT</jackrabbit.version>
     <mongo.host>127.0.0.1</mongo.host>
     <mongo.port>27017</mongo.port>
     <mongo.db>MongoMKDB</mongo.db>
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/UserImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/UserImpl.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/autosave/UserImpl.java	(revision )
@@ -41,6 +41,11 @@
     }
 
     @Override
+    public boolean isSystemUser() {
+        return getDelegate().isSystemUser();
+    }
+
+    @Override
     public Credentials getCredentials() throws RepositoryException {
         return getDelegate().getCredentials();
     }
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/CredentialsImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/CredentialsImpl.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/CredentialsImpl.java	(revision )
@@ -16,6 +16,9 @@
  */
 package org.apache.jackrabbit.oak.security.user;
 
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.jcr.Credentials;
 
 /**
@@ -27,15 +30,17 @@
     private final String userId;
     private final String pwHash;
 
-    CredentialsImpl(String userId, String pwHash) {
+    CredentialsImpl(@Nonnull String userId, @Nullable String pwHash) {
         this.userId = userId;
         this.pwHash = pwHash;
     }
 
+    @Nonnull
     public String getUserId() {
         return userId;
     }
 
+    @CheckForNull
     public String getPasswordHash() {
         return pwHash;
     }
\ No newline at end of file
Index: oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd	(revision 1616527)
+++ oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd	(revision )
@@ -716,6 +716,8 @@
   - rep:password (STRING) protected
   - rep:disabled (STRING) protected
 
+[rep:SystemUser] > rep:User
+
 [rep:Group] > rep:Authorizable, rep:MemberReferences
   + rep:members (rep:Members) = rep:Members multiple protected VERSION /* @deprecated since oak 1.0 (remove?) */
   + rep:membersList (rep:MemberReferencesList) = rep:MemberReferencesList protected COPY /* @since oak 1.0 */
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserManagerImpl.java	(revision )
@@ -26,6 +26,7 @@
 import javax.jcr.RepositoryException;
 import javax.jcr.UnsupportedRepositoryOperationException;
 
+import com.google.common.base.Strings;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
@@ -139,9 +140,9 @@
     }
 
     @Override
-    public User createUser(final String userId, String password) throws RepositoryException {
-        Principal principal = new PrincipalImpl(userId);
-        return createUser(userId, password, principal, null);
+    public User createUser(final String userID, String password) throws RepositoryException {
+        Principal principal = new PrincipalImpl(userID);
+        return createUser(userID, password, principal, null);
     }
 
     @Override
@@ -167,6 +168,21 @@
     }
 
     @Override
+    public User createSystemUser(String userID, String intermediatePath) throws AuthorizableExistsException, RepositoryException {
+        checkValidID(userID);
+        Principal principal = new PrincipalImpl(userID);
+        checkValidPrincipal(principal, false);
+
+        Tree userTree = userProvider.createSystemUser(userID, intermediatePath);
+        setPrincipal(userTree, principal);
+
+        User user = new SystemUserImpl(userID, userTree, this);
+
+        log.debug("System user created: " + userID);
+        return user;
+    }
+
+    @Override
     public Group createGroup(String groupId) throws RepositoryException {
         Principal principal = new PrincipalImpl(groupId);
         return createGroup(groupId, principal, null);
@@ -327,7 +343,11 @@
             return null;
         }
         if (UserUtil.isType(tree, AuthorizableType.USER)) {
+            if (UserUtil.isSystemUser(tree)) {
+                return new SystemUserImpl(UserUtil.getAuthorizableId(tree), tree, this);
+            } else {
-            return new UserImpl(UserUtil.getAuthorizableId(tree), tree, this);
+                return new UserImpl(UserUtil.getAuthorizableId(tree), tree, this);
+            }
         } else if (UserUtil.isType(tree, AuthorizableType.GROUP)) {
             return new GroupImpl(UserUtil.getAuthorizableId(tree), tree, this);
         } else {
@@ -344,7 +364,7 @@
     }
 
     void checkValidPrincipal(Principal principal, boolean isGroup) throws RepositoryException {
-        if (principal == null || principal.getName() == null || "".equals(principal.getName())) {
+        if (principal == null || Strings.isNullOrEmpty(principal.getName())) {
             throw new IllegalArgumentException("Principal may not be null and must have a valid name.");
         }
         if (!isGroup && EveryonePrincipal.NAME.equals(principal.getName())) {
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/UserConstants.java	(revision )
@@ -31,6 +31,7 @@
     String NT_REP_AUTHORIZABLE_FOLDER = "rep:AuthorizableFolder";
     String NT_REP_USER = "rep:User";
     String NT_REP_GROUP = "rep:Group";
+    String NT_REP_SYSTEM_USER = "rep:SystemUser";
     String NT_REP_PASSWORD = "rep:Password";
     @Deprecated
     String NT_REP_MEMBERS = "rep:Members";
@@ -126,6 +127,11 @@
      * Default value for {@link #PARAM_GROUP_PATH}
      */
     String DEFAULT_GROUP_PATH = "/rep:security/rep:authorizables/rep:groups";
+
+    /**
+     * Default intermediate path for system users.
+     */
+    String DEFAULT_SYSTEM_PATH = "system";
 
     /**
      * Parameter used to change the number of levels that are used by default to
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/UserUtil.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/UserUtil.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/user/util/UserUtil.java	(revision )
@@ -39,7 +39,6 @@
     private UserUtil() {
     }
 
-    @Nonnull
     public static boolean isAdmin(@Nonnull ConfigurationParameters parameters, @Nonnull String userId) {
         return getAdminId(parameters).equals(userId);
     }
@@ -61,9 +60,9 @@
                 case GROUP:
                     return NT_REP_GROUP.equals(ntName);
                 case USER:
-                    return NT_REP_USER.equals(ntName);
+                    return NT_REP_USER.equals(ntName) || NT_REP_SYSTEM_USER.equals(ntName);
                 default:
-                    return NT_REP_USER.equals(ntName) || NT_REP_GROUP.equals(ntName);
+                    return NT_REP_USER.equals(ntName) || NT_REP_GROUP.equals(ntName) || NT_REP_SYSTEM_USER.equals(ntName);
             }
         }
         return false;
@@ -73,13 +72,19 @@
     public static AuthorizableType getType(@Nonnull Tree authorizableNode) {
         String ntName = TreeUtil.getPrimaryTypeName(authorizableNode);
         if (ntName != null) {
-            if (UserConstants.NT_REP_GROUP.equals(ntName)) {
+            if (NT_REP_GROUP.equals(ntName)) {
                 return AuthorizableType.GROUP;
-            } else if (UserConstants.NT_REP_USER.equals(ntName)) {
+            } else if (NT_REP_USER.equals(ntName)) {
                 return AuthorizableType.USER;
+            } else if (NT_REP_SYSTEM_USER.equals(ntName)) {
+                return AuthorizableType.USER;
             }
         }
         return null;
+    }
+
+    public static boolean isSystemUser(@Nullable Tree authorizableTree) {
+        return authorizableTree != null && NT_REP_SYSTEM_USER.equals(TreeUtil.getPrimaryTypeName(authorizableTree));
     }
 
     @CheckForNull
\ No newline at end of file
Index: oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserDelegator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserDelegator.java	(revision 1616527)
+++ oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/UserDelegator.java	(revision )
@@ -72,6 +72,16 @@
     }
 
     @Override
+    public boolean isSystemUser() {
+        return sessionDelegate.safePerform(new SessionOperation<Boolean>("isSystemUser") {
+            @Override
+            public Boolean perform() {
+                return getDelegate().isSystemUser();
+            }
+        });
+    }
+
+    @Override
     public Credentials getCredentials() {
         return sessionDelegate.safePerform(new SessionOperation<Credentials>("getCredentials") {
             @Override
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProvider.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProvider.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserProvider.java	(revision )
@@ -23,6 +23,7 @@
 
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
 import javax.jcr.nodetype.ConstraintViolationException;
@@ -168,7 +169,7 @@
     private final String groupPath;
     private final String userPath;
 
-    UserProvider(Root root, ConfigurationParameters config) {
+    UserProvider(@Nonnull Root root, @Nonnull ConfigurationParameters config) {
         super(root, config);
 
         defaultDepth = config.getConfigValue(PARAM_DEFAULT_DEPTH, DEFAULT_DEPTH);
@@ -177,27 +178,41 @@
     }
 
     @Nonnull
-    Tree createUser(String userID, String intermediateJcrPath) throws RepositoryException {
-        return createAuthorizableNode(userID, false, intermediateJcrPath);
+    Tree createUser(@Nonnull String userID, @Nullable String intermediateJcrPath) throws RepositoryException {
+        return createAuthorizableNode(userID, NT_REP_USER, intermediateJcrPath);
     }
 
     @Nonnull
-    Tree createGroup(String groupID, String intermediateJcrPath) throws RepositoryException {
-        return createAuthorizableNode(groupID, true, intermediateJcrPath);
+    Tree createGroup(@Nonnull String groupID, @Nullable String intermediateJcrPath) throws RepositoryException {
+        return createAuthorizableNode(groupID, NT_REP_GROUP, intermediateJcrPath);
     }
 
+    @Nonnull
+    Tree createSystemUser(@Nonnull String userID, @Nullable String intermediateJcrPath) throws RepositoryException {
+        String relPath;
+        if (intermediateJcrPath == null) {
+            relPath = DEFAULT_SYSTEM_PATH;
+        } else {
+            if (intermediateJcrPath.startsWith(DEFAULT_SYSTEM_PATH)) {
+                throw new IllegalArgumentException("System users must be located in the 'system' subtree of the user root.");
+            }
+            relPath = intermediateJcrPath;
+        }
+        return createAuthorizableNode(userID, NT_REP_SYSTEM_USER, relPath);
+    }
+
     @CheckForNull
-    Tree getAuthorizable(String authorizableId) {
+    Tree getAuthorizable(@Nonnull String authorizableId) {
         return getByID(authorizableId, AuthorizableType.AUTHORIZABLE);
     }
 
     @CheckForNull
-    Tree getAuthorizableByPath(String authorizableOakPath) {
+    Tree getAuthorizableByPath(@Nonnull String authorizableOakPath) {
         return getByPath(authorizableOakPath);
     }
 
     @CheckForNull
-    Tree getAuthorizableByPrincipal(Principal principal) {
+    Tree getAuthorizableByPrincipal(@Nonnull Principal principal) {
         if (principal instanceof TreeBasedPrincipal) {
             return root.getTree(((TreeBasedPrincipal) principal).getOakPath());
         }
@@ -229,11 +244,12 @@
 
     //------------------------------------------------------------< private >---
 
-    private Tree createAuthorizableNode(String authorizableId, boolean isGroup, String intermediatePath) throws RepositoryException {
+    private Tree createAuthorizableNode(@Nonnull String authorizableId,
+                                        @Nonnull String ntName,
+                                        @Nullable String intermediatePath) throws RepositoryException {
         String nodeName = getNodeName(authorizableId);
-        NodeUtil folder = createFolderNodes(authorizableId, nodeName, isGroup, intermediatePath);
+        NodeUtil folder = createFolderNodes(authorizableId, nodeName, NT_REP_GROUP.equals(ntName), intermediatePath);
 
-        String ntName = (isGroup) ? NT_REP_GROUP : NT_REP_USER;
         NodeUtil authorizableNode = folder.addChild(nodeName, ntName);
 
         String nodeID = getContentID(authorizableId);
@@ -256,8 +272,10 @@
      * @return The folder node.
      * @throws RepositoryException If an error occurs
      */
-    private NodeUtil createFolderNodes(String authorizableId, String nodeName,
-                                       boolean isGroup, String intermediatePath) throws RepositoryException {
+    private NodeUtil createFolderNodes(@Nonnull String authorizableId,
+                                       @Nonnull String nodeName,
+                                       boolean isGroup,
+                                       @Nullable String intermediatePath) throws RepositoryException {
         String authRoot = (isGroup) ? groupPath : userPath;
         String folderPath = new StringBuilder()
                 .append(authRoot)
@@ -295,7 +313,9 @@
         return folder;
     }
 
-    private String getFolderPath(String authorizableId, String intermediatePath, String authRoot) throws ConstraintViolationException {
+    private String getFolderPath(@Nonnull String authorizableId,
+                                 @Nullable String intermediatePath,
+                                 @Nonnull String authRoot) throws ConstraintViolationException {
         if (intermediatePath != null && intermediatePath.charAt(0) == '/') {
             if (!intermediatePath.startsWith(authRoot)) {
                 throw new ConstraintViolationException("Attempt to create authorizable outside of configured tree");
@@ -323,7 +343,7 @@
         return sb.toString();
     }
 
-    private String getNodeName(String authorizableId) {
+    private String getNodeName(@Nonnull String authorizableId) {
         AuthorizableNodeName generator = checkNotNull(config.getConfigValue(PARAM_AUTHORIZABLE_NODE_NAME, AuthorizableNodeName.DEFAULT, AuthorizableNodeName.class));
         return generator.generateNodeName(authorizableId);
     }
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidator.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserValidator.java	(revision )
@@ -135,13 +135,29 @@
         Tree tree = checkNotNull(parentAfter.getChild(name));
 
         AuthorizableType type = UserUtil.getType(tree);
+        boolean isSystemUser = (type == AuthorizableType.USER) && UserUtil.isSystemUser(tree);
         String authRoot = UserUtil.getAuthorizableRootPath(provider.getConfig(), type);
+        if (isSystemUser) {
+            authRoot = authRoot + '/' + DEFAULT_SYSTEM_PATH;
+        }
         if (authRoot != null) {
             assertHierarchy(tree, authRoot);
             // assert rep:principalName is present (that should actually by covered
             // by node type validator)
             if (TreeUtil.getString(tree, REP_PRINCIPAL_NAME) == null) {
                 throw constraintViolation(26, "Mandatory property rep:principalName missing.");
+            }
+
+            if (isSystemUser) {
+                if (TreeUtil.getString(tree, REP_PASSWORD) != null) {
+                    throw constraintViolation(27, "Attempt to set password with system user.");
+                }
+                if (TreeUtil.getString(tree, REP_DISABLED) != null) {
+                    throw constraintViolation(28, "Attempt to to disable a system user.");
+                }
+                if (tree.hasChild(REP_PWD)) {
+                    throw constraintViolation(29, "Attempt to add rep:pwd node to a system user.");
+                }
             }
         }
         return new VisibleValidator(new UserValidator(null, tree, provider), true, true);
\ No newline at end of file
Index: oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java	(revision 1616527)
+++ oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImpl.java	(revision )
@@ -80,6 +80,11 @@
     }
 
     @Override
+    public boolean isSystemUser() {
+        return false;
+    }
+
+    @Override
     public Credentials getCredentials() {
         return new CredentialsImpl(getID(), getPasswordHash());
     }
\ No newline at end of file
