Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java?rev=828791&r1=828790&r2=828791&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserAdministratorTest.java Thu Oct 22 17:26:37 2009 @@ -40,10 +40,10 @@ */ public class UserAdministratorTest extends AbstractUserTest { - // user 'above' + // a test user private String uID; - // user-admin 'below' + // a test user being member of the user-admin group private String otherUID; private Session otherSession; @@ -57,6 +57,8 @@ // created for that new user. Principal p = getTestPrincipal(); UserImpl u = (UserImpl) userMgr.createUser(p.getName(), buildPassword(p)); + save(superuser); + uID = u.getID(); // create a second user @@ -64,12 +66,14 @@ String pw = buildPassword(p); Credentials otherCreds = buildCredentials(p.getName(), pw); User other = userMgr.createUser(p.getName(), pw); + save(superuser); + otherUID = other.getID(); // make other user a user-administrator: Authorizable ua = userMgr.getAuthorizable(UserConstants.USER_ADMIN_GROUP_NAME); if (ua == null || !ua.isGroup()) { - throw new NotExecutableException("Cannot execute test. User-Admin name has been changed by config."); + throw new NotExecutableException("Cannot execute test. No user-administrator group found."); } uAdministrators = (Group) ua; uAdministrators.addMember(other); @@ -86,8 +90,8 @@ } finally { Authorizable a = userMgr.getAuthorizable(otherUID); if (a != null) { - for (Iterator it = a.memberOf(); it.hasNext();) { - Group gr = (Group) it.next(); + for (Iterator it = a.memberOf(); it.hasNext();) { + Group gr = it.next(); if (!gr.getPrincipal().equals(EveryonePrincipal.getInstance())) { gr.removeMember(a); } @@ -98,6 +102,7 @@ if (a != null) { a.remove(); } + save(superuser); } super.tearDown(); } @@ -110,13 +115,13 @@ return (Group) auth; } - public void testUserIsUserAdmin() throws RepositoryException, NotExecutableException { - Set principals = getPrincipalSetFromSession(otherSession); - boolean isAdmin = false; - for (Iterator it = principals.iterator(); it.hasNext() && !isAdmin;) { - isAdmin = UserConstants.USER_ADMIN_GROUP_NAME.equals(((Principal) it.next()).getName()); + public void testIsUserAdministrator() throws RepositoryException, NotExecutableException { + Set principals = getPrincipalSetFromSession(otherSession); + boolean isUserAdmin = false; + for (Iterator it = principals.iterator(); it.hasNext() && !isUserAdmin;) { + isUserAdmin = UserConstants.USER_ADMIN_GROUP_NAME.equals(it.next().getName()); } - assertTrue(isAdmin); + assertTrue(isUserAdmin); } public void testCreateUser() throws RepositoryException, NotExecutableException { @@ -126,9 +131,11 @@ try { Principal p = getTestPrincipal(); u = (UserImpl) umgr.createUser(p.getName(), buildPassword(p)); + save(otherSession); } finally { if (u != null) { u.remove(); + save(otherSession); } } } @@ -152,11 +159,14 @@ for (String intermediatePath : m.keySet()) { try { u = (UserImpl) umgr.createUser(p.getName(), buildPassword(p), p, intermediatePath); + save(otherSession); + String expPath = m.get(intermediatePath); assertEquals(expPath, u.getNode().getPath()); } finally { if (u != null) { u.remove(); + save(otherSession); } } } @@ -170,12 +180,15 @@ try { Principal p = getTestPrincipal(); u = (UserImpl) umgr.createUser(p.getName(), buildPassword(p), p, invalidIntermediatePath); + save(otherSession); + fail("An attempt to create a user below an existing user must fail."); } catch (RepositoryException e) { // success } finally { if (u != null) { u.remove(); + save(otherSession); } } } @@ -186,6 +199,8 @@ Authorizable himself = umgr.getAuthorizable(otherUID); try { himself.remove(); + save(otherSession); + fail("A UserAdministrator should not be allowed to remove himself."); } catch (AccessDeniedException e) { // success @@ -203,6 +218,7 @@ Authorizable user = umgr.getAuthorizable(uID); user.remove(); + save(otherSession); } public void testModifyImpersonationOfUser() throws RepositoryException, NotExecutableException { @@ -214,26 +230,36 @@ try { Principal p = getTestPrincipal(); u = umgr.createUser(p.getName(), buildPassword(p)); + save(otherSession); Impersonation impers = u.getImpersonation(); assertFalse(impers.allows(buildSubject(otherP))); + assertTrue(impers.grantImpersonation(otherP)); + save(otherSession); + assertTrue(impers.allows(buildSubject(otherP))); } finally { // impersonation get removed while removing the user u. if (u != null) { u.remove(); + save(otherSession); } } // modify impersonation of another user u = (User) umgr.getAuthorizable(uID); Impersonation uImpl = u.getImpersonation(); + if (!uImpl.allows(buildSubject(otherP))) { // ... trying to modify 'impersonators of another user must succeed assertTrue(uImpl.grantImpersonation(otherP)); + save(otherSession); + assertTrue(uImpl.allows(buildSubject(otherP))); + uImpl.revokeImpersonation(otherP); + save(otherSession); } else { throw new NotExecutableException("Cannot execute test. OtherP can already impersonate UID-user."); } @@ -246,8 +272,14 @@ Group gr = getGroupAdminGroup(umgr); try { assertFalse(gr.addMember(userHimSelf)); + // conditial save call omitted. } catch (RepositoryException e) { // success as well. + } finally { + // clean up using the superuser + if (getGroupAdminGroup(userMgr).removeMember(userMgr.getAuthorizable(otherUID))) { + save(superuser); + } } } @@ -270,9 +302,13 @@ User childU = null; try { childU = umgr.createUser(cp.getName(), buildPassword(cp)); + save(otherSession); + Group gr = getGroupAdminGroup(umgr); try { - assertFalse("A UserAdmin must not be allowed to modify group memberships", gr.addMember(childU)); + assertFalse("A UserAdmin must not be allowed to modify group " + + "memberships", gr.addMember(childU)); + // con-save call omitted. } catch (RepositoryException e) { // success } @@ -285,23 +321,49 @@ public void testCreateGroup() throws RepositoryException, NotExecutableException { UserManager umgr = getUserManager(otherSession); + String grId = null; try { Group testGroup = umgr.createGroup(getTestPrincipal()); + save(otherSession); + grId = testGroup.getID(); + fail("UserAdmin should not be allowed to create a new Group."); - testGroup.remove(); + } catch (RepositoryException e) { // success. + } finally { + // let superuser clean up + if (grId != null) { + Authorizable gr = userMgr.getAuthorizable(grId); + if (gr != null) { + gr.remove(); + save(superuser); + } + } } } public void testCreateGroupWithIntermediatePath() throws RepositoryException, NotExecutableException { UserManager umgr = getUserManager(otherSession); + String grId = null; try { Group testGroup = umgr.createGroup(getTestPrincipal(), "/any/intermediate/path"); - fail("UserAdmin should not be allowed to create a new Group."); - testGroup.remove(); + save(otherSession); + grId = testGroup.getID(); + + fail("UserAdmin should not be allowed to create a new Group with intermediate path."); + } catch (RepositoryException e) { // success. + } finally { + // let superuser clean up + if (grId != null) { + Authorizable gr = userMgr.getAuthorizable(grId); + if (gr != null) { + gr.remove(); + save(superuser); + } + } } } @@ -310,13 +372,18 @@ Group g = null; try { g = userMgr.createGroup(getTestPrincipal()); + save(superuser); + umgr.getAuthorizable(g.getID()).remove(); + save(otherSession); + fail("UserAdmin should not be allowed to remove a Group."); } catch (RepositoryException e) { // success. } finally { if (g != null) { g.remove(); + save(superuser); } } } @@ -328,6 +395,7 @@ Authorizable auth = umgr.getAuthorizable(uID); try { assertFalse(gr.addMember(auth)); + // omit cond-save call. } catch (AccessDeniedException e) { // success as well. } @@ -335,6 +403,7 @@ auth = umgr.getAuthorizable(otherUID); try { assertFalse(gr.addMember(auth)); + // omit cond-save call. } catch (AccessDeniedException e) { // success as well. } @@ -344,6 +413,7 @@ auth = umgr.getAuthorizable(otherUID); try { assertFalse(gr.addMember(auth)); + // omit cond-save call. } catch (AccessDeniedException e) { // success } @@ -356,6 +426,7 @@ try { Principal p = getTestPrincipal(); u = (UserImpl) umgr.createUser(p.getName(), buildPassword(p)); + save(otherSession); Authorizable az = userMgr.getAuthorizable(u.getID()); assertNotNull(az); @@ -363,6 +434,7 @@ } finally { if (u != null) { u.remove(); + save(otherSession); } } } Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java?rev=828791&r1=828790&r2=828791&view=diff ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java (original) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImplTest.java Thu Oct 22 17:26:37 2009 @@ -30,6 +30,7 @@ import javax.jcr.RepositoryException; import javax.jcr.Session; import javax.jcr.SimpleCredentials; +import javax.jcr.Value; import java.io.UnsupportedEncodingException; import java.security.NoSuchAlgorithmException; import java.security.Principal; @@ -52,7 +53,10 @@ Principal p = getTestPrincipal(); String pw = buildPassword(p); creds = new SimpleCredentials(p.getName(), pw.toCharArray()); + User u = userMgr.createUser(p.getName(), pw); + save(superuser); + uID = u.getID(); uSession = getHelper().getRepository().login(creds); uMgr = getUserManager(uSession); @@ -61,6 +65,7 @@ protected void tearDown() throws Exception { try { userMgr.getAuthorizable(uID).remove(); + save(superuser); } finally { uSession.logout(); } @@ -81,17 +86,38 @@ assertFalse(auth.isGroup()); } - public void testUserCanModifyItsOwnProperties() throws RepositoryException { + public void testUserCanModifyItsOwnProperties() throws RepositoryException, NotExecutableException { User u = (User) uMgr.getAuthorizable(uID); if (u == null) { fail("User " +uID+ "hast not been removed and must be visible to the Session created with its credentials."); } + if (!uSession.hasPermission(((UserImpl) u).getNode().getPath(), "set_property")) { + throw new NotExecutableException("Users should be able to modify their properties -> Check repository config."); + } + + // single valued properties u.setProperty("Email", new StringValue("tu@security.test")); + save(uSession); + + assertNotNull(u.getProperty("Email")); assertEquals("tu@security.test", u.getProperty("Email")[0].getString()); u.removeProperty("Email"); + save(uSession); + assertNull(u.getProperty("Email")); + + // multivalued properties + u.setProperty(propertyName1, new Value[] {uSession.getValueFactory().createValue("anyValue")}); + save(uSession); + + assertNotNull(u.getProperty(propertyName1)); + + u.removeProperty(propertyName1); + save(uSession); + + assertNull(u.getProperty(propertyName1)); } public void testChangePassword() throws RepositoryException, NotExecutableException, NoSuchAlgorithmException, UnsupportedEncodingException { @@ -104,11 +130,13 @@ User user = getTestUser(superuser); try { user.changePassword("pw"); + save(superuser); SimpleCredentials creds = new SimpleCredentials(user.getID(), "pw".toCharArray()); assertTrue(((CryptedSimpleCredentials) user.getCredentials()).matches(creds)); } finally { user.changePassword(oldPw); + save(superuser); } } } Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java?rev=828791&view=auto ============================================================================== --- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java (added) +++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/security/user/UserImporterTest.java Thu Oct 22 17:26:37 2009 @@ -0,0 +1,1261 @@ +/* + * 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.core.security.user; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.principal.PrincipalManager; +import org.apache.jackrabbit.api.security.principal.PrincipalIterator; +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.User; +import org.apache.jackrabbit.api.security.user.UserManager; +import org.apache.jackrabbit.api.security.user.Impersonation; +import org.apache.jackrabbit.core.SessionImpl; +import org.apache.jackrabbit.core.NodeImpl; +import org.apache.jackrabbit.core.config.ImportConfig; +import org.apache.jackrabbit.core.security.principal.PrincipalImpl; +import org.apache.jackrabbit.core.util.ReferenceChangeTracker; +import org.apache.jackrabbit.core.xml.ProtectedPropertyImporter; +import org.apache.jackrabbit.core.xml.SessionImporter; +import org.apache.jackrabbit.core.xml.ImportHandler; +import org.apache.jackrabbit.test.AbstractJCRTest; +import org.apache.jackrabbit.test.NotExecutableException; +import org.apache.jackrabbit.commons.xml.ParsingContentHandler; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + +import javax.jcr.AccessDeniedException; +import javax.jcr.Credentials; +import javax.jcr.ImportUUIDBehavior; +import javax.jcr.InvalidItemStateException; +import javax.jcr.InvalidSerializedDataException; +import javax.jcr.Item; +import javax.jcr.ItemExistsException; +import javax.jcr.ItemNotFoundException; +import javax.jcr.LoginException; +import javax.jcr.NamespaceException; +import javax.jcr.Node; +import javax.jcr.PathNotFoundException; +import javax.jcr.Property; +import javax.jcr.ReferentialIntegrityException; +import javax.jcr.Repository; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.UnsupportedRepositoryOperationException; +import javax.jcr.ValueFactory; +import javax.jcr.Workspace; +import javax.jcr.Value; +import javax.jcr.lock.LockException; +import javax.jcr.nodetype.ConstraintViolationException; +import javax.jcr.nodetype.NoSuchNodeTypeException; +import javax.jcr.retention.RetentionManager; +import javax.jcr.security.AccessControlManager; +import javax.jcr.version.VersionException; +import javax.security.auth.Subject; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.ByteArrayInputStream; +import java.security.AccessControlException; +import java.security.Principal; +import java.util.Iterator; +import java.util.List; +import java.util.ArrayList; +import java.util.UUID; +import java.util.Collections; + +/** + * UserImporterTest... + */ +public class UserImporterTest extends AbstractJCRTest { + + private SessionImpl sImpl; + private UserManagerImpl umgr; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + if (!(superuser instanceof SessionImpl)) { + throw new NotExecutableException("SessionImpl expected."); + } + + sImpl = (SessionImpl) superuser; + + UserManager umgr = sImpl.getUserManager(); + if (umgr.isAutoSave()) { + try { + umgr.autoSave(false); + } catch (RepositoryException e) { + // user manager cannot have the autosave behavior changed + // -> test not executable + throw new NotExecutableException("Expected user manager that can have its autosave behavior changed to false."); + } + } + this.umgr = (UserManagerImpl) umgr; + // avoid collision with testing a-folders that may have been created + // with another test (but not removed as user/groups got removed) + String path = this.umgr.getUsersPath() + "/t"; + if (sImpl.nodeExists(path)) { + sImpl.getNode(path).remove(); + } + path = this.umgr.getGroupsPath() + "/g"; + if (sImpl.nodeExists(path)) { + sImpl.getNode(path).remove(); + } + sImpl.save(); + } + + @Override + protected void tearDown() throws Exception { + sImpl.refresh(false); + + if (umgr != null) { + String path = umgr.getUsersPath() + "/t"; + if (sImpl.nodeExists(path)) { + sImpl.getNode(path).remove(); + } + path = umgr.getGroupsPath() + "/g"; + if (sImpl.nodeExists(path)) { + sImpl.getNode(path).remove(); + } + sImpl.save(); + } + super.tearDown(); + } + + private static ProtectedPropertyImporter createImporter() { + return new UserImporter(); + } + + public void testWorkspaceImport() { + assertFalse("WorkspaceImport is not supported -> init should return false.", + createImporter().init(sImpl, sImpl, true, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new ReferenceChangeTracker())); } + + public void testUUIDBehaviorCreateNew() { + assertFalse("ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW is not supported -> init should return false.", + createImporter().init(sImpl, sImpl, false, ImportUUIDBehavior.IMPORT_UUID_CREATE_NEW, new ReferenceChangeTracker())); + } + + public void testDifferentUserManagerImpl() { + assertFalse("Only UserManagerImpl supported", + createImporter().init(new DummySession(), sImpl, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new ReferenceChangeTracker())); + } + + public void testInitTwice() { + ProtectedPropertyImporter ppi = createImporter(); + assertTrue(ppi.init(sImpl, sImpl, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new ReferenceChangeTracker())); + try { + ppi.init(sImpl, sImpl, false, ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new ReferenceChangeTracker()); + fail("calling init twice must fail"); + } catch (IllegalStateException e) { + // success + } + } + + public void testImportUser() throws RepositoryException, IOException, SAXException, NotExecutableException { + String xml = "\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + " t" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + Authorizable newUser = umgr.getAuthorizable("t"); + assertNotNull(newUser); + assertFalse(newUser.isGroup()); + assertEquals("t", newUser.getPrincipal().getName()); + assertEquals("t", newUser.getID()); + + NodeImpl n = ((UserImpl) newUser).getNode(); + assertTrue(n.isNew()); + assertTrue(n.getParent().isSame(target)); + + assertEquals("t", n.getName()); + assertEquals("t", n.getProperty(UserConstants.P_PRINCIPAL_NAME).getString()); + assertEquals("{sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375", n.getProperty(UserConstants.P_PASSWORD).getString()); + + // saving changes of the import -> must succeed. add mandatory + // props should have been created. + sImpl.save(); + + } finally { + sImpl.refresh(false); + if (target.hasNode("t")) { + target.getNode("t").remove(); + sImpl.save(); + } + } + } + + public void testImportGroup() throws RepositoryException, IOException, SAXException, NotExecutableException { + String xml = "\n" + + "" + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " g" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + Authorizable newGroup = umgr.getAuthorizable("g"); + assertNotNull(newGroup); + assertTrue(newGroup.isGroup()); + assertEquals("g", newGroup.getPrincipal().getName()); + assertEquals("g", newGroup.getID()); + + NodeImpl n = ((GroupImpl) newGroup).getNode(); + assertTrue(n.isNew()); + assertTrue(n.getParent().isSame(target)); + + assertEquals("g", n.getName()); + assertEquals("g", n.getProperty(UserConstants.P_PRINCIPAL_NAME).getString()); + + // saving changes of the import -> must succeed. add mandatory + // props should have been created. + sImpl.save(); + + } finally { + sImpl.refresh(false); + if (target.hasNode("g")) { + target.getNode("g").remove(); + sImpl.save(); + } + } + } + + public void testImportGroupIntoUsersTree() throws RepositoryException, IOException, SAXException, NotExecutableException { + String xml = "\n" + + "" + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " g" + + ""; + + /* + importing a group below the users-path: + - nonProtected node rep:Group must be created. + - protected properties are ignored + - UserManager.getAuthorizable must return null. + - saving changes must fail with ConstraintViolationEx. + */ + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + Authorizable newGroup = umgr.getAuthorizable("g"); + assertNull(newGroup); + + assertTrue(target.hasNode("g")); + assertFalse(target.hasProperty("g/rep:principalName")); + + // saving changes of the import -> must fail as mandatory prop is missing + try { + sImpl.save(); + fail("Import must be incomplete. Saving changes must fail."); + } catch (ConstraintViolationException e) { + // success + } + + } finally { + sImpl.refresh(false); + if (target.hasNode("g")) { + target.getNode("g").remove(); + sImpl.save(); + } + } + } + + public void testImportAuthorizableId() throws IOException, RepositoryException, SAXException, NotExecutableException { + // importing an authorizable with an jcr:uuid that doesn't match the + // hash of the given ID -> getAuthorizable(String id) will not find the + // authorizable. + //String calculatedUUID = "e358efa4-89f5-3062-b10d-d7316b65649e"; + String mismatchUUID = "a358efa4-89f5-3062-b10d-d7316b65649e"; + + String xml = "" + + "" + + " rep:User" + + " " +mismatchUUID+ "" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + " t"; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + // node must be present: + assertTrue(target.hasNode("t")); + NodeImpl n = (NodeImpl) target.getNode("t"); + assertEquals(mismatchUUID, n.getUUID()); + + // but UserManager.getAuthorizable(String) will not find the + // authorizable + Authorizable newUser = umgr.getAuthorizable("t"); + assertNull(newUser); + + } finally { + sImpl.refresh(false); + } + + } + + public void testExistingPrincipal() throws RepositoryException, NotExecutableException, IOException, SAXException { + Principal existing = null; + for (Principal p : sImpl.getSubject().getPrincipals()) { + if (umgr.getAuthorizable(p) != null) { + existing = p; + break; + } + } + if (existing == null) { + throw new NotExecutableException(); + } + + String xml = "\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + " "+ existing.getName() +"" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + fail("Import must detect conflicting principals."); + } catch (SAXException e) { + // success + } finally { + sImpl.refresh(false); + } + } + + + public void testConflictingPrincipalsWithinImport() throws IOException, RepositoryException, NotExecutableException { + String xml = "\n" + + "" + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " g" + + "" + + "" + + " rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + fail("Import must detect conflicting principals."); + } catch (SAXException e) { + // success + } finally { + sImpl.refresh(false); + } + } + + public void testMultiValuedPrincipalName() throws RepositoryException, IOException, SAXException, NotExecutableException { + String xml = "\n" + + "" + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " gg2g"; + + /* + importing a group with a multi-valued rep:principalName property + - nonProtected node rep:Group must be created. + - protected property rep:principalName must be ignored + - saving changes must fail with ConstraintViolationEx. + */ + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + Authorizable newGroup = umgr.getAuthorizable("g"); + assertNotNull(newGroup); + + assertTrue(target.hasNode("g")); + assertTrue(target.hasProperty("g/rep:principalName")); + assertFalse(target.getProperty("g/rep:principalName").getDefinition().isProtected()); + + // saving changes of the import -> must fail as mandatory prop is missing + try { + sImpl.save(); + fail("Import must be incomplete. Saving changes must fail."); + } catch (ConstraintViolationException e) { + // success + } + + } finally { + sImpl.refresh(false); + if (target.hasNode("g")) { + target.getNode("g").remove(); + sImpl.save(); + } + } + } + + public void testIncompleteUser() throws RepositoryException, IOException, SAXException, NotExecutableException { + List incompleteXml = new ArrayList(); + incompleteXml.add("\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + ""); + incompleteXml.add("\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " t" + + ""); + + for (String xml : incompleteXml) { + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + // saving changes of the import -> must fail as mandatory prop is missing + try { + sImpl.save(); + fail("Import must be incomplete. Saving changes must fail."); + } catch (ConstraintViolationException e) { + // success + } + } finally { + sImpl.refresh(false); + if (target.hasNode("t")) { + target.getNode("t").remove(); + sImpl.save(); + } + } + } + } + + public void testIncompleteGroup() throws IOException, RepositoryException, SAXException, NotExecutableException { + String xml = "" + + "" + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + ""; + + /* + importing a group without rep:principalName property + - saving changes must fail with ConstraintViolationEx. + */ + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + // saving changes of the import -> must fail as mandatory prop is missing + try { + sImpl.save(); + fail("Import must be incomplete. Saving changes must fail."); + } catch (ConstraintViolationException e) { + // success + } + + } finally { + sImpl.refresh(false); + if (target.hasNode("g")) { + target.getNode("g").remove(); + sImpl.save(); + } + } + } + + public void testImportWithIntermediatePath() throws IOException, RepositoryException, SAXException, NotExecutableException { + String xml = "\n" + + "" + + " rep:AuthorizableFolder" + + " d5433be9-68d0-4fba-bf96-efc29f461993" + + "" + + " rep:AuthorizableFolder" + + " d87354a4-037e-4756-a8fb-deb2eb7c5149" + + "" + + " rep:AuthorizableFolder" + + " 24263272-b789-4568-957a-3bcaf99dbab3" + + "" + + " rep:User" + + " 0b8854ad-38f0-36c6-9807-928d28195609" + + " {sha1}4358694eeb098c6708ae914a10562ce722bbbc34" + + " t3" + + "" + + "" + + "" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + + assertTrue(target.isModified()); + assertTrue(sImpl.hasPendingChanges()); + + Authorizable newUser = umgr.getAuthorizable("t3"); + assertNotNull(newUser); + assertFalse(newUser.isGroup()); + assertEquals("t3", newUser.getPrincipal().getName()); + assertEquals("t3", newUser.getID()); + + NodeImpl n = ((UserImpl) newUser).getNode(); + assertTrue(n.isNew()); + + Node parent = n.getParent(); + assertFalse(n.isSame(target)); + assertTrue(((NodeImpl) parent).isNodeType(UserConstants.NT_REP_AUTHORIZABLE_FOLDER)); + assertFalse(parent.getDefinition().isProtected()); + + assertTrue(target.hasNode("some")); + assertTrue(target.hasNode("some/intermediate/path")); + + } finally { + sImpl.refresh(false); + } + } + + public void testImportNewMembers() throws IOException, RepositoryException, SAXException, NotExecutableException { + String xml = "" + + "rep:AuthorizableFolderrep:Groupb2f5ff47-4366-31b6-a533-d8dc3614845dgrep:Group0120a4f9-196a-3f9e-b9f5-23f31f914da7g1b2f5ff47-4366-31b6-a533-d8dc3614845d"; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + + Group g = (Group) umgr.getAuthorizable("g"); + assertNotNull(g); + Group g1 = (Group) umgr.getAuthorizable("g1"); + assertNotNull(g1); + + NodeImpl n = ((AuthorizableImpl) g1).getNode(); + assertTrue(n.hasProperty(UserConstants.P_MEMBERS)); + + // getWeakReferences only works upon save. + sImpl.save(); + + assertTrue(g1.isMember(g)); + + } finally { + sImpl.refresh(false); + target.getNode("gFolder").remove(); + sImpl.save(); + } + } + + public void testImportNewMembersReverseOrder() throws IOException, RepositoryException, SAXException, NotExecutableException { + // group is imported before the member + String xml = "" + + "" + + " rep:AuthorizableFolder" + + " " + + " rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g1" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " " + + " " + + " rep:Group" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " g" + + " " + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + + Group g = (Group) umgr.getAuthorizable("g"); + assertNotNull(g); + Group g1 = (Group) umgr.getAuthorizable("g1"); + assertNotNull(g1); + + NodeImpl n = ((AuthorizableImpl) g1).getNode(); + assertTrue(n.hasProperty(UserConstants.P_MEMBERS)); + + // getWeakReferences only works upon save. + sImpl.save(); + + assertTrue(g1.isMember(g)); + + } finally { + sImpl.refresh(false); + target.getNode("gFolder").remove(); + sImpl.save(); + } + } + + public void testImportMembers() throws RepositoryException, IOException, SAXException, NotExecutableException { + Authorizable admin = umgr.getAuthorizable("admin"); + if (admin == null) { + throw new NotExecutableException(); + } + + String uuid = ((AuthorizableImpl) admin).getNode().getUUID(); + String xml = "" + + "" + + " rep:AuthorizableFolder" + + " " + + " rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g1" + + " " +uuid+ "" + + " " + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml); + + Group g1 = (Group) umgr.getAuthorizable("g1"); + assertNotNull(g1); + + // getWeakReferences only works upon save. + sImpl.save(); + + assertTrue(g1.isMember(admin)); + + boolean found = false; + for (Iterator it = admin.declaredMemberOf(); it.hasNext() && !found;) { + found = "g1".equals(it.next().getID()); + } + assertTrue(found); + + } finally { + sImpl.refresh(false); + target.getNode("gFolder").remove(); + sImpl.save(); + } + } + + public void testImportNonExistingMemberIgnore() throws IOException, RepositoryException, SAXException, NotExecutableException { + Node n = testRootNode.addNode(nodeName1, ntUnstructured); + n.addMixin(mixReferenceable); + + List invalid = new ArrayList(); + invalid.add(UUID.randomUUID().toString()); // random uuid + invalid.add(n.getUUID()); // uuid of non-authorizable node + + for (String id : invalid) { + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g1" + + " " +id+ "" + + "" + + ""; + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + // there should be no exception during import, + // but invalid members must be ignored. + doImport(target, xml, UserImporter.ImportBehavior.IGNORE); + Authorizable a = umgr.getAuthorizable("g1"); + if (a.isGroup()) { + assertNotDeclaredMember((Group) a, id); + } else { + fail("'g1' was not imported as Group."); + } + } finally { + sImpl.refresh(false); + } + } + } + + public void testImportNonExistingMemberAbort() throws IOException, RepositoryException, SAXException, NotExecutableException { + Node n = testRootNode.addNode(nodeName1, ntUnstructured); + n.addMixin(mixReferenceable); + + List invalid = new ArrayList(); + invalid.add(UUID.randomUUID().toString()); // random uuid + invalid.add(n.getUUID()); // uuid of non-authorizable node + + for (String id : invalid) { + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g1" + + " " +id+ "" + + "" + + ""; + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml, UserImporter.ImportBehavior.ABORT); + // importbehavior ABORT -> should throw. + fail("importing invalid members -> must throw."); + } catch (SAXException e) { + // success as well + } finally { + sImpl.refresh(false); + } + } + } + + public void testImportNonExistingMemberBestEffort() throws IOException, RepositoryException, SAXException, NotExecutableException { + Node n = testRootNode.addNode(nodeName1, ntUnstructured); + n.addMixin(mixReferenceable); + + List invalid = new ArrayList(); + invalid.add(UUID.randomUUID().toString()); // random uuid + invalid.add(n.getUUID()); // uuid of non-authorizable node + + for (String id : invalid) { + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " 0120a4f9-196a-3f9e-b9f5-23f31f914da7" + + " g1" + + " " +id+ "" + + "" + + ""; + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + // BESTEFFORT behavior -> must import non-existing members. + doImport(target, xml, UserImporter.ImportBehavior.BESTEFFORT); + Authorizable a = umgr.getAuthorizable("g1"); + if (a.isGroup()) { + // the rep:members property must contain the invalid value + boolean found = false; + NodeImpl grNode = ((AuthorizableImpl) a).getNode(); + for (Value memberValue : grNode.getProperty(UserConstants.P_MEMBERS).getValues()) { + if (id.equals(memberValue.getString())) { + found = true; + break; + } + } + assertTrue("ImportBehavior.BESTEFFORT must import non-existing members.",found); + + // declared members must not list the invalid entry. + assertNotDeclaredMember((Group) a, id); + } else { + fail("'g1' was not imported as Group."); + } + } finally { + sImpl.refresh(false); + } + } + } + + public void testImportNonExistingMemberBestEffort2() throws IOException, RepositoryException, SAXException, NotExecutableException { + + String g1Id = "0120a4f9-196a-3f9e-b9f5-23f31f914da7"; + String nonExistingId = "b2f5ff47-4366-31b6-a533-d8dc3614845d"; // groupId of 'g' group. + if (umgr.getAuthorizable("g") != null) { + throw new NotExecutableException(); + } + + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " " + g1Id + "" + + " g1" + + " " +nonExistingId+ "" + + "" + + ""; + + String xml2 = "" + + " " + + " rep:Group" + + " " + nonExistingId + "" + + " g" + + " " + g1Id + "" + + " "; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + // BESTEFFORT behavior -> must import non-existing members. + doImport(target, xml, UserImporter.ImportBehavior.BESTEFFORT); + Authorizable g1 = umgr.getAuthorizable("g1"); + if (g1.isGroup()) { + // the rep:members property must contain the invalid value + boolean found = false; + NodeImpl grNode = ((AuthorizableImpl) g1).getNode(); + for (Value memberValue : grNode.getProperty(UserConstants.P_MEMBERS).getValues()) { + if (nonExistingId.equals(memberValue.getString())) { + found = true; + break; + } + } + assertTrue("ImportBehavior.BESTEFFORT must import non-existing members.",found); + } else { + fail("'g1' was not imported as Group."); + } + + /* + now try to import the 'g' group that has a circular group + membership references. + expected: + - group is imported + - circular membership is ignored + - g is member of g1 + - g1 isn't member of g + */ + target = (NodeImpl) target.getNode("gFolder"); + doImport(target, xml2, UserImporter.ImportBehavior.BESTEFFORT); + + Authorizable g = umgr.getAuthorizable("g"); + assertNotNull(g); + if (g.isGroup()) { + assertNotDeclaredMember((Group) g, g1Id); + } else { + fail("'g' was not imported as Group."); + } + + } finally { + sImpl.refresh(false); + } + } + + public void testImportSelfAsGroupIgnore() throws Exception { + + String invalidId = "0120a4f9-196a-3f9e-b9f5-23f31f914da7"; // uuid of the group itself + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " "+invalidId+"" + + " g1" + + " " +invalidId+ "" + + "" + + ""; + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml, UserImporter.ImportBehavior.IGNORE); + // no exception during import -> member must have been ignored though. + Authorizable a = umgr.getAuthorizable("g1"); + if (a.isGroup()) { + assertNotDeclaredMember((Group) a, invalidId); + } else { + fail("'g1' was not imported as Group."); + } + } finally { + sImpl.refresh(false); + } + } + + private static void assertNotDeclaredMember(Group gr, String potentialID) throws RepositoryException { + // declared members must not list the invalid entry. + Iterator it = gr.getDeclaredMembers(); + while (it.hasNext()) { + AuthorizableImpl member = (AuthorizableImpl) it.next(); + assertFalse(potentialID.equals(member.getNode().getIdentifier())); + } + } + + public void testImportSelfAsGroupAbort() throws Exception { + + String invalidId = "0120a4f9-196a-3f9e-b9f5-23f31f914da7"; // uuid of the group itself + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "rep:Group" + + " "+invalidId+"" + + " g1" + + " " +invalidId+ "" + + "" + + ""; + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getGroupsPath()); + try { + doImport(target, xml, UserImporter.ImportBehavior.ABORT); + fail("Importing self as group with ImportBehavior.ABORT must fail."); + } catch (SAXException e) { + // success. + }finally { + sImpl.refresh(false); + } + } + + public void testImportImpersonation() throws IOException, RepositoryException, SAXException, NotExecutableException { + String xml = "" + + "" + + " rep:AuthorizableFolder" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " t" + + " g" + + "" + + "" + + " rep:User" + + " b2f5ff47-4366-31b6-a533-d8dc3614845d" + + " g" + + "" + + ""; + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml); + + Authorizable newUser = umgr.getAuthorizable("t"); + assertNotNull(newUser); + + Authorizable u2 = umgr.getAuthorizable("g"); + assertNotNull(u2); + + Subject subj = new Subject(); + subj.getPrincipals().add(u2.getPrincipal()); + + Impersonation imp = ((User) newUser).getImpersonation(); + assertTrue(imp.allows(subj)); + + } finally { + sImpl.refresh(false); + } + } + + public void testImportInvalidImpersonationIgnore() throws IOException, RepositoryException, SAXException, NotExecutableException { + List invalid = new ArrayList(); + invalid.add("anybody"); // an non-existing princ-name + invalid.add("administrators"); // a group + invalid.add("t"); // principal of the user itself. + + for (String principalName : invalid) { + String xml = "\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + " t" +principalName+ "" + + ""; + Subject subj = new Subject(); + subj.getPrincipals().add(new PrincipalImpl(principalName)); + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml, UserImporter.ImportBehavior.IGNORE); + // no exception during import: no impersonation must be granted + // for the invalid principal name + Authorizable a = umgr.getAuthorizable("t"); + if (!a.isGroup()) { + Impersonation imp = ((User)a).getImpersonation(); + Subject s = new Subject(); + s.getPrincipals().add(new PrincipalImpl(principalName)); + assertFalse(imp.allows(s)); + for (PrincipalIterator it = imp.getImpersonators(); it.hasNext();) { + assertFalse(principalName.equals(it.nextPrincipal().getName())); + } + } else { + fail("Importing 't' didn't create a User."); + } + } finally { + sImpl.refresh(false); + } + } + } + + public void testImportInvalidImpersonationAbort() throws IOException, RepositoryException, SAXException, NotExecutableException { + List invalid = new ArrayList(); + invalid.add("anybody"); // an non-existing princ-name + invalid.add("administrators"); // a group + invalid.add("t"); // principal of the user itself. + + for (String principalName : invalid) { + String xml = "\n" + + "" + + " rep:User" + + " e358efa4-89f5-3062-b10d-d7316b65649e" + + " {sha1}8efd86fb78a56a5145ed7739dcb00c78581c5375" + + " t" +principalName+ "" + + ""; + Subject subj = new Subject(); + subj.getPrincipals().add(new PrincipalImpl(principalName)); + + NodeImpl target = (NodeImpl) sImpl.getNode(umgr.getUsersPath()); + try { + doImport(target, xml, UserImporter.ImportBehavior.ABORT); + fail("UserImporter.ImportBehavior.ABORT -> importing invalid impersonators must throw."); + } catch (SAXException e) { + // success + } finally { + sImpl.refresh(false); + } + } + } + + private void doImport(NodeImpl target, String xml) throws IOException, SAXException, RepositoryException { + InputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8")); + SessionImporter importer = new SessionImporter(target, sImpl, + ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new PseudoConfig()); + ImportHandler ih = new ImportHandler(importer, sImpl); + new ParsingContentHandler(ih).parse(in); + } + + private void doImport(NodeImpl target, String xml, int importBehavior) throws IOException, SAXException, RepositoryException { + InputStream in = new ByteArrayInputStream(xml.getBytes("UTF-8")); + SessionImporter importer = new SessionImporter(target, sImpl, + ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW, new PseudoConfig(importBehavior)); + ImportHandler ih = new ImportHandler(importer, sImpl); + new ParsingContentHandler(ih).parse(in); + } + + //-------------------------------------------------------------------------- + private final class PseudoConfig extends ImportConfig { + + private final ProtectedPropertyImporter ppi; + + private PseudoConfig() { + this.ppi = createImporter(); + } + + private PseudoConfig(int importBehavior) { + this.ppi = createImporter(); + ((UserImporter) ppi).setImportBehavior(importBehavior); + } + + @Override + public List getProtectedPropertyImporters() { + return Collections.singletonList(ppi); + } + } + + private final class DummySession implements JackrabbitSession { + + private DummySession() { + } + + public PrincipalManager getPrincipalManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + return null; + } + + public UserManager getUserManager() throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException { + return new UserManager() { + + public Authorizable getAuthorizable(String id) throws RepositoryException { + return null; + } + + public Authorizable getAuthorizable(Principal principal) throws RepositoryException { + return null; + } + + public Iterator findAuthorizables(String propertyName, String value) throws RepositoryException { + return null; + } + + public Iterator findAuthorizables(String propertyName, String value, int searchType) throws RepositoryException { + return null; + } + + public User createUser(String userID, String password) throws AuthorizableExistsException, RepositoryException { + return null; + } + + public User createUser(String userID, String password, Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + return null; + } + + public Group createGroup(Principal principal) throws AuthorizableExistsException, RepositoryException { + return null; + } + + public Group createGroup(Principal principal, String intermediatePath) throws AuthorizableExistsException, RepositoryException { + return null; + } + + public boolean isAutoSave() { + return true; + } + + public void autoSave(boolean enable) throws UnsupportedRepositoryOperationException, RepositoryException { + } + }; + } + + public Repository getRepository() { + return null; + } + + public String getUserID() { + return null; + } + + public String[] getAttributeNames() { + return new String[0]; + } + + public Object getAttribute(String name) { + return null; + } + + public Workspace getWorkspace() { + return null; + } + + public Node getRootNode() throws RepositoryException { + return null; + } + + public Session impersonate(Credentials credentials) throws LoginException, RepositoryException { + return null; + } + + public Node getNodeByUUID(String uuid) throws ItemNotFoundException, RepositoryException { + return null; + } + + public Node getNodeByIdentifier(String id) throws ItemNotFoundException, RepositoryException { + return null; + } + + public Item getItem(String absPath) throws PathNotFoundException, RepositoryException { + return null; + } + + public Node getNode(String absPath) throws PathNotFoundException, RepositoryException { + return null; + } + + public Property getProperty(String absPath) throws PathNotFoundException, RepositoryException { + return null; + } + + public boolean itemExists(String absPath) throws RepositoryException { + return false; + } + + public boolean nodeExists(String absPath) throws RepositoryException { + return false; + } + + public boolean propertyExists(String absPath) throws RepositoryException { + return false; + } + + public void move(String srcAbsPath, String destAbsPath) throws ItemExistsException, PathNotFoundException, VersionException, ConstraintViolationException, LockException, RepositoryException { + } + + public void removeItem(String absPath) throws VersionException, LockException, ConstraintViolationException, AccessDeniedException, RepositoryException { + } + + public void save() throws AccessDeniedException, ItemExistsException, ReferentialIntegrityException, ConstraintViolationException, InvalidItemStateException, VersionException, LockException, NoSuchNodeTypeException, RepositoryException { + } + + public void refresh(boolean keepChanges) throws RepositoryException { + } + + public boolean hasPendingChanges() throws RepositoryException { + return false; + } + + public ValueFactory getValueFactory() throws UnsupportedRepositoryOperationException, RepositoryException { + return null; + } + + public boolean hasPermission(String absPath, String actions) throws RepositoryException { + return false; + } + + public void checkPermission(String absPath, String actions) throws AccessControlException, RepositoryException { + } + + public boolean hasCapability(String methodName, Object target, Object[] arguments) throws RepositoryException { + return false; + } + + public ContentHandler getImportContentHandler(String parentAbsPath, int uuidBehavior) throws PathNotFoundException, ConstraintViolationException, VersionException, LockException, RepositoryException { + return null; + } + + public void importXML(String parentAbsPath, InputStream in, int uuidBehavior) throws IOException, PathNotFoundException, ItemExistsException, ConstraintViolationException, VersionException, InvalidSerializedDataException, LockException, RepositoryException { + } + + public void exportSystemView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse) throws PathNotFoundException, SAXException, RepositoryException { + } + + public void exportSystemView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse) throws IOException, PathNotFoundException, RepositoryException { + } + + public void exportDocumentView(String absPath, ContentHandler contentHandler, boolean skipBinary, boolean noRecurse) throws PathNotFoundException, SAXException, RepositoryException { + } + + public void exportDocumentView(String absPath, OutputStream out, boolean skipBinary, boolean noRecurse) throws IOException, PathNotFoundException, RepositoryException { + } + + public void setNamespacePrefix(String prefix, String uri) throws NamespaceException, RepositoryException { + } + + public String[] getNamespacePrefixes() throws RepositoryException { + return new String[0]; + } + + public String getNamespaceURI(String prefix) throws NamespaceException, RepositoryException { + return null; + } + + public String getNamespacePrefix(String uri) throws NamespaceException, RepositoryException { + return null; + } + + public void logout() { + + } + + public boolean isLive() { + return false; + } + + public void addLockToken(String lt) { + + } + + public String[] getLockTokens() { + return new String[0]; + } + + public void removeLockToken(String lt) { + + } + + public AccessControlManager getAccessControlManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return null; + } + + public RetentionManager getRetentionManager() throws UnsupportedRepositoryOperationException, RepositoryException { + return null; + } + } + + +} \ No newline at end of file