Andrew Hind
2008-05-13 11:54:55 +00:00
parent 344b703a61
commit 1b807e3e77
42 changed files with 2243 additions and 233 deletions

View File

@@ -235,18 +235,18 @@
<value>org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent</value>
</property>
<property name="defaultBinding">
<ref bean="oldPermissionsDaoComponent"></ref>
<ref bean="dmPermissionsDaoComponent"></ref>
</property>
<property name="redirectedProtocolBindings">
<map>
<entry key="workspace"><ref bean="oldPermissionsDaoComponent"></ref></entry>
<entry key="versionStore"><ref bean="oldPermissionsDaoComponent"></ref></entry>
<entry key="avm"><ref bean="newPermissionsDaoComponent"/></entry>
<entry key="workspace"><ref bean="dmPermissionsDaoComponent"></ref></entry>
<entry key="versionStore"><ref bean="dmPermissionsDaoComponent"></ref></entry>
<entry key="avm"><ref bean="avmPermissionsDaoComponent"/></entry>
</map>
</property>
</bean>
<bean id="newPermissionsDaoComponent" class="org.alfresco.repo.domain.hibernate.PermissionsDaoComponentImpl">
<bean id="avmPermissionsDaoComponent" class="org.alfresco.repo.domain.hibernate.PermissionsDaoComponentImpl">
<property name="aclDaoComponent">
<ref bean="aclDaoComponent" />
</property>
@@ -261,7 +261,7 @@
</property>
</bean>
<bean id="oldPermissionsDaoComponent" class="org.alfresco.repo.domain.hibernate.OldADMPermissionsDaoComponentImpl">
<bean id="dmPermissionsDaoComponent" class="org.alfresco.repo.domain.hibernate.DMPermissionsDaoComponentImpl">
<property name="aclDaoComponent">
<ref bean="aclDaoComponent" />
</property>
@@ -288,9 +288,18 @@
</property>
</bean>
<bean id="nodeACLDAO" class="org.alfresco.repo.domain.hibernate.NodeAccessControlListDAO">
<bean id="nodeACLDAO" class="org.alfresco.repo.domain.hibernate.DMAccessControlListDAO">
<property name="nodeDaoService">
<ref bean="nodeDaoService" />
</property>
<property name="aclDaoComponent">
<ref bean="aclDaoComponent"/>
</property>
<property name="hibernateSessionHelper">
<ref bean="hibernateSessionHelper"/>
</property>
<property name="nodeService">
<ref bean="nodeService"/>
</property>
</bean>

View File

@@ -214,9 +214,9 @@ patch.wcmPermissionPatch.result=Updated ACLs: ACLS are moved to the staging area
patch.avmWebProjectInheritPermissions.description=Break inheritance of permissions on wca:webfolder object to hide access by default.
patch.avmWebProjectInheritPermissions.result=Removed inheritance of permissions on all wca:webfolder objects.
patch.wcmPostPermissionSnapshotPatch.description=Snapshot stores (after fixing ACLs so they are only set on the staging area store).
patch.wcmPostPermissionSnapshotPatch.result=Snapshot complete after WCM ACL changes.
patch.updateDmPermissions.description=Update ACLs on all DM node objects to the new 3.0 permission model
patch.updateDmPermissions.result=Updated ACLs. Created {0} defining ACLs.

View File

@@ -179,6 +179,9 @@
</property>
<property name="tenantService">
<ref bean="tenantService"/>
</property>
<property name="aclDaoComponent">
<ref bean="aclDaoComponent"/>
</property>
</bean>
<bean id="sessionSizeResourceInterceptor" class="org.alfresco.repo.transaction.TransactionResourceInterceptor" >

View File

@@ -1453,4 +1453,19 @@
</property>
</bean>
<bean id="patch.updateDmPermissions" class="org.alfresco.repo.admin.patch.impl.DmPermissionsPatch" parent="basePatch" >
<property name="id"><value>patch.updateDmPermissions</value></property>
<property name="description"><value>patch.updateDmPermissions.description</value></property>
<property name="fixesFromSchema"><value>0</value></property>
<property name="fixesToSchema"><value>124</value></property>
<property name="targetSchema"><value>125</value></property>
<!-- helper beans -->
<property name="accessControlListDao">
<ref bean="nodeACLDAO" />
</property>
<property name="aclDaoComponent">
<ref bean="aclDaoComponent" />
</property>
</bean>
</beans>

View File

@@ -41,7 +41,7 @@
<bean id="permissionServiceImpl" class="org.alfresco.repo.security.permissions.impl.PermissionServiceImpl">
<property name="nodeService">
<ref bean="nodeService" />
<ref bean="dbNodeService" />
</property>
<property name="tenantService">
<ref bean="tenantService"/>
@@ -136,6 +136,16 @@
<property name="nodeService">
<ref bean="nodeService" />
</property>
<property name="modelDAO">
<ref bean="permissionsModelDAO" />
</property>
<property name="requiredFor">
<list>
<value>Unlock</value>
<value>CheckIn</value>
<value>CancelCheckOut</value>
</list>
</property>
</bean>
<!-- ===================== -->

View File

@@ -19,4 +19,4 @@ version.build=@build-number@
# Schema number
version.schema=124
version.schema=125

View File

@@ -0,0 +1,143 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.admin.patch.impl;
import java.util.Map;
import org.alfresco.i18n.I18NUtil;
import org.alfresco.repo.admin.patch.AbstractPatch;
import org.alfresco.repo.domain.AccessControlListDAO;
import org.alfresco.repo.domain.hibernate.AclDaoComponentImpl;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.transaction.RetryingTransactionHelper;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
/**
* Migrate permissions from the OLD format to defining, shared and layered
*/
public class DmPermissionsPatch extends AbstractPatch
{
private static final String MSG_SUCCESS = "patch.updateDmPermissions.result";
private AccessControlListDAO accessControlListDao;
private AclDaoComponentImpl aclDaoComponent;
@Override
protected String applyInternal() throws Exception
{
Thread progressThread = null;
if (aclDaoComponent.supportsProgressTracking())
{
Long toDo = aclDaoComponent.getDmNodeCount();
Long maxId = aclDaoComponent.getMaxAclId();
progressThread = new Thread(new ProgressWatcher(toDo, maxId), "DMPatchProgressWatcher");
progressThread.start();
}
Map<ACLType, Integer> summary = accessControlListDao.patchAcls();
if (progressThread != null)
{
progressThread.interrupt();
progressThread.join();
}
// build the result message
String msg = I18NUtil.getMessage(MSG_SUCCESS, summary.get(ACLType.DEFINING));
// done
return msg;
}
/**
* Set the access control list dao
*
* @param accessControlListDao
*/
public void setAccessControlListDao(AccessControlListDAO accessControlListDao)
{
this.accessControlListDao = accessControlListDao;
}
/**
* Set the acl dao component
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponentImpl aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
private class ProgressWatcher implements Runnable
{
private boolean running = true;
Long toDo;
Long max;
ProgressWatcher(Long toDo, Long max)
{
this.toDo = toDo;
this.max = max;
}
public void run()
{
while (running)
{
try
{
Thread.sleep(60000);
}
catch (InterruptedException e)
{
running = false;
}
if (running)
{
RetryingTransactionHelper txHelper = transactionService.getRetryingTransactionHelper();
txHelper.setMaxRetries(1);
Long done = txHelper.doInTransaction(new RetryingTransactionCallback<Long>()
{
public Long execute() throws Throwable
{
return aclDaoComponent.getDmNodeCountWithNewACLS(max);
}
}, true, true);
reportProgress(toDo, done);
}
}
}
}
}

View File

@@ -83,26 +83,47 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
{
}
/**
* Set the AVM repository
*
* @param repository
*/
public void setAvmRepository(AVMRepository repository)
{
fAVMRepository = repository;
}
/**
* Set the AVM service
*
* @param avmService
*/
public void setAvmService(AVMService avmService)
{
fAVMService = avmService;
}
/**
* Set the ACL DAO component
*
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponent aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
/**
* @param avmSnapShotTriggeredIndexingMethodInterceptor
*/
public void setAvmSnapShotTriggeredIndexingMethodInterceptor(AVMSnapShotTriggeredIndexingMethodInterceptor avmSnapShotTriggeredIndexingMethodInterceptor)
{
this.avmSnapShotTriggeredIndexingMethodInterceptor = avmSnapShotTriggeredIndexingMethodInterceptor;
}
/**
* @param hibernateSessionHelper
*/
public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper)
{
this.hibernateSessionHelper = hibernateSessionHelper;
@@ -161,6 +182,7 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
// to the path stuffed in the NodeRef.
Pair<Integer, String> avmVersionPath = AVMNodeConverter.ToAVMVersionPath(nodeRef);
String path = avmVersionPath.getSecond();
@SuppressWarnings("unused")
List<ChildAssociationRef> result = new ArrayList<ChildAssociationRef>();
String[] splitPath = AVMNodeConverter.SplitBase(path);
if (splitPath[0] == null)
@@ -588,6 +610,16 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
}
}
/**
* Set and cascade ACls
*
* @param descriptor
* @param mergeFrom
* @param changes
* @param mode
* @param set
* @param indirections
*/
public void setFixedAcls(AVMNodeDescriptor descriptor, Long mergeFrom, List<AclChange> changes, SetMode mode, boolean set, Map<Long, Set<Long>> indirections)
{
if (descriptor == null)
@@ -691,9 +723,21 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
}
}
/**
* Mode to sue when setting ACLs
* @author andyh
*
*/
private enum SetMode
{
ALL, DIRECT_ONLY;
/**
* Set ALL
*/
ALL,
/**
* Set only direct children (not those present by layering)
*/
DIRECT_ONLY;
}
public Map<ACLType, Integer> patchAcls()
@@ -893,8 +937,19 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
return result;
}
private class CounterSet extends HashMap<ACLType, Counter>
/**
*
* Counter for each type of ACL change
* @author andyh
*
*/
public static class CounterSet extends HashMap<ACLType, Counter>
{
/**
*
*/
private static final long serialVersionUID = -3682278258679211481L;
CounterSet()
{
super();
@@ -929,7 +984,12 @@ public class AVMAccessControlListDAO implements AccessControlListDAO
}
}
private class Counter
/**
* Simple counter
* @author andyh
*
*/
public static class Counter
{
int counter;

View File

@@ -37,6 +37,7 @@ import org.alfresco.repo.security.permissions.ACEType;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.NodePermissionEntry;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.PermissionReference;
@@ -57,6 +58,16 @@ import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Common suppot for permisisons dao
*
* Sub classes deteremine how ACLs are cascaded to children and how changes may COW/version children as ACLs are pushed down.
*
* TODO: remove the protocol to dao mapping
*
* @author andyh
*
*/
public abstract class AbstractPermissionsDaoComponentImpl implements PermissionsDaoComponent, TransactionalDao
{
private static Log logger = LogFactory.getLog(AbstractPermissionsDaoComponentImpl.class);
@@ -77,11 +88,19 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
this.uuid = GUID.generate();
}
/**
* Get the ACL DAO component
* @return - the acl dao component
*/
public AclDaoComponent getAclDaoComponent()
{
return aclDaoComponent;
}
/**
* Set the ACL DAO component
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponent aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
@@ -138,11 +157,19 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
aclDaoComponent.beforeCommit();
}
/**
* Set the mapping of protocol to DAO
* @param map
*/
public void setProtocolToACLDAO(Map<String, AccessControlListDAO> map)
{
fProtocolToACLDAO = map;
}
/**
* Set the default DAO
* @param defaultACLDAO
*/
public void setDefaultACLDAO(AccessControlListDAO defaultACLDAO)
{
fDefaultACLDAO = defaultACLDAO;
@@ -435,6 +462,8 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
deletePermissions(nodeRef);
}
// create the access control list
existing = getAccessControlList(nodeRef);
CreationReport report = createAccessControlList(nodeRef, nodePermissionEntry.inheritPermissions(), existing);
// add all entries
@@ -594,8 +623,26 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
return npe;
}
public AccessControlListProperties getAccessControlListProperties(NodeRef nodeRef)
{
DbAccessControlList acl = getACLDAO(nodeRef).getAccessControlList(nodeRef);
if(acl == null)
{
return null;
}
return aclDaoComponent.getAccessControlListProperties(acl.getId());
}
protected abstract CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing);
/**
* Internal class used for reporting the collateral damage when creating an new ACL entry
* @author andyh
*
*/
static class CreationReport
{
DbAccessControlList created;
@@ -608,21 +655,38 @@ public abstract class AbstractPermissionsDaoComponentImpl implements Permissions
this.changes = changes;
}
/**
* Set the change list
*
* @param changes
*/
public void setChanges(List<AclChange> changes)
{
this.changes = changes;
}
/**
* Set the ACL that was created
* @param created
*/
public void setCreated(DbAccessControlList created)
{
this.created = created;
}
/**
* Get the change list
* @return - the change list
*/
public List<AclChange> getChanges()
{
return changes;
}
/**
* Get the created ACL
* @return - the acl
*/
public DbAccessControlList getCreated()
{
return created;

View File

@@ -41,6 +41,7 @@ import org.alfresco.repo.domain.DbAccessControlListChangeSet;
import org.alfresco.repo.domain.DbAccessControlListMember;
import org.alfresco.repo.domain.DbAuthority;
import org.alfresco.repo.domain.DbPermission;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.QNameDAO;
import org.alfresco.repo.domain.QNameEntity;
import org.alfresco.repo.node.db.hibernate.HibernateNodeDaoServiceImpl;
@@ -62,10 +63,10 @@ import org.alfresco.service.namespace.QName;
import org.alfresco.util.GUID;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.HibernateException;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.jgroups.tests.DeadlockTest.InRpc;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
@@ -112,23 +113,59 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
private enum WriteMode
{
TRUNCATE_INHERITED, ADD_INHERITED, CHANGE_INHERITED, REMOVE_INHERITED, INSERT_INHERITED, COPY_UPDATE_AND_INHERIT, COPY_ONLY;
/**
* Remove inherited ACEs after that set
*/
TRUNCATE_INHERITED,
/**
* Add inherited ACEs
*/
ADD_INHERITED,
/**
* The source of inherited ACEs is changing
*/
CHANGE_INHERITED,
/**
* Remove all inherited ACEs
*/
REMOVE_INHERITED,
/**
* Insert inherited ACEs
*/
INSERT_INHERITED,
/**
* Copy ACLs and update ACEs and inheritance
*/
COPY_UPDATE_AND_INHERIT,
/**
* Simlpe copy
*/
COPY_ONLY;
}
/**
*
*/
public AclDaoComponentImpl()
{
super();
// Wire up for annoying AVM hack to support copy and setting of ACLs as nodes are created
DbAccessControlListImpl.setAclDaoComponent(this);
}
/**
* Set the DAO for accessing QName entities
* @param qnameDAO
*/
public void setQnameDAO(QNameDAO qnameDAO)
{
this.qnameDAO = qnameDAO;
}
/**
* Set the ACL cache
* @param aclCache
*/
public void setAclCache(SimpleCache<Long, AccessControlList> aclCache)
{
this.aclCache = aclCache;
@@ -344,7 +381,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
* @param toAdd
* @param inheritsFrom
* @param depth
* @return
* @return - an AclChange
*/
@SuppressWarnings("unchecked")
private AclChange getWritable(final Long id, final Long parent, AccessControlEntry exclude, List<DbAccessControlEntry> toAdd, Long inheritsFrom,
@@ -814,9 +851,26 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
@SuppressWarnings("unchecked")
public List<AclChange> deleteAccessControlList(final Long id)
{
HibernateCallback check = new HibernateCallback()
{
public Object doInHibernate(Session session)
{
Criteria criteria = getSession().createCriteria(NodeImpl.class, "node");
criteria.createAlias("node.accessControlList", "acl");
criteria.add(Restrictions.eq("acl.id", id));
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return criteria.list();
}
};
List<Node> nodes = (List<Node>) getHibernateTemplate().execute(check);
for(Node node : nodes)
{
logger.error("Found "+node.getId() +" "+node.getUuid() + " "+node.getAccessControlList() );
}
List<AclChange> acls = new ArrayList<AclChange>();
DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id);
final DbAccessControlList acl = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id);
if (!acl.isLatest())
{
throw new UnsupportedOperationException("Old ALC versions can not be updated");
@@ -828,7 +882,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
if ((acl.getAclType() == ACLType.DEFINING) || (acl.getAclType() == ACLType.LAYERED))
{
if (acl.getInheritedAclId() != -1)
if ((acl.getInheritedAclId() != null) && (acl.getInheritedAclId() != -1))
{
final DbAccessControlList inherited = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, acl.getInheritedAclId());
// Will remove from the cache
@@ -929,6 +983,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
getHibernateTemplate().delete(acl);
getSession().flush();
}
// remove the deleted acl from the cache
@@ -965,6 +1020,11 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return changes;
}
/**
* Search for access control lists
* @param pattern
* @return the ids of the ACLs found
*/
public Long[] findAccessControlList(AccessControlEntry pattern)
{
throw new UnsupportedOperationException();
@@ -986,6 +1046,10 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return acl;
}
/**
* @param id
* @return the access control list
*/
@SuppressWarnings("unchecked")
public AccessControlList getAccessControlListImpl(final Long id)
{
@@ -1025,7 +1089,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
entry.setContext(context);
}
DbPermission perm = member.getAccessControlEntry().getPermission();
SimplePermissionReference permissionRefernce = new SimplePermissionReference(perm.getTypeQName().getQName(), perm.getName());
SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(perm.getTypeQName().getQName(), perm.getName());
entry.setPermission(permissionRefernce);
entry.setPosition(member.getPosition());
@@ -1054,6 +1118,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
properties.setInherits(acl.getInherits());
properties.setLatest(acl.isLatest());
properties.setVersioned(acl.isVersioned());
properties.setId(id);
return properties;
}
@@ -1199,7 +1264,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
@SuppressWarnings("unchecked")
public List<AclChange> setAccessControlEntry(Long id, final AccessControlEntry ace)
public List<AclChange> setAccessControlEntry(final Long id, final AccessControlEntry ace)
{
DbAccessControlList target = (DbAccessControlList) getHibernateTemplate().get(DbAccessControlListImpl.class, id);
if (target.getAclType() == ACLType.SHARED)
@@ -1595,7 +1660,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
entry.setContext(context);
}
DbPermission perm = member.getAccessControlEntry().getPermission();
SimplePermissionReference permissionRefernce = new SimplePermissionReference(perm.getTypeQName().getQName(), perm.getName());
SimplePermissionReference permissionRefernce = SimplePermissionReference.getPermissionReference(perm.getTypeQName().getQName(), perm.getName());
entry.setPermission(permissionRefernce);
entry.setPosition(Integer.valueOf(0));
@@ -1775,11 +1840,17 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return before;
}
/**
* @param after
*/
public void setAfter(Long after)
{
this.after = after;
}
/**
* @param before
*/
public void setBefore(Long before)
{
this.before = before;
@@ -1790,6 +1861,9 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return typeAfter;
}
/**
* @param typeAfter
*/
public void setTypeAfter(ACLType typeAfter)
{
this.typeAfter = typeAfter;
@@ -1800,6 +1874,9 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return typeBefore;
}
/**
* @param typeBefore
*/
public void setTypeBefore(ACLType typeBefore)
{
this.typeBefore = typeBefore;
@@ -1820,7 +1897,7 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
/**
* Get the total number of head nodes in the repository
*
* @return
* @return count
*/
public Long getAVMHeadNodeCount()
{
@@ -1847,6 +1924,10 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
/**
* Get the max acl id
* @return - max acl id
*/
public Long getMaxAclId()
{
try
@@ -1871,6 +1952,11 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
}
/**
* Does the underlyinf connection support isolation level 1 (dirty read)
*
* @return true if we can do a dirty db read and so track changes (Oracle can not)
*/
public boolean supportsProgressTracking()
{
try
@@ -1885,6 +1971,11 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
/**
* Get the acl count canges so far for progress tracking
* @param above
* @return - the count
*/
public Long getAVMNodeCountWithNewACLS(Long above)
{
try
@@ -1910,6 +2001,10 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
}
/**
* How many nodes are noew in store (approximate)
* @return - the number fo new nodes - approximate
*/
public Long getNewInStore()
{
HibernateCallback callback = new HibernateCallback()
@@ -1924,6 +2019,13 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return count;
}
/**
* Find layered directories
* Used to imporove performance during patching and cascading the effect fo permission changes between layers
*
* @return - layered directories
*/
@SuppressWarnings("unchecked")
public List<Indirection> getLayeredDirectories()
{
@@ -1947,6 +2049,13 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
return indirections;
}
/**
* Find layered files
*
* Used to imporove performance during patching and cascading the effect fo permission changes between layers
*
* @return - layerd files
*/
@SuppressWarnings("unchecked")
public List<Indirection> getLayeredFiles()
{
@@ -1985,6 +2094,11 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
getSession().flush();
}
/**
* Support to describe AVM indirections for permission performance improvements when permissions are set.
* @author andyh
*
*/
public static class Indirection
{
Long from;
@@ -2000,16 +2114,25 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
this.toVersion = toVersion;
}
/**
* @return - from id
*/
public Long getFrom()
{
return from;
}
/**
* @return - to id
*/
public String getTo()
{
return to;
}
/**
* @return - version
*/
public Integer getToVersion()
{
return toVersion;
@@ -2017,4 +2140,64 @@ public class AclDaoComponentImpl extends HibernateDaoSupport implements AclDaoCo
}
/**
* Ho many DM nodes are there?
*
* @return - the count
*/
public Long getDmNodeCount()
{
try
{
Session session = getSession();
int isolationLevel = session.connection().getTransactionIsolation();
try
{
session.connection().setTransactionIsolation(1);
Query query = getSession().getNamedQuery("permission.GetDmNodeCount");
Long answer = (Long) query.uniqueResult();
return answer;
}
finally
{
session.connection().setTransactionIsolation(isolationLevel);
}
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to set TX isolation level", e);
}
}
/**
* How many DM nodes are three with new ACls (to track patch progress)
* @param above
* @return - the count
*/
public Long getDmNodeCountWithNewACLS(Long above)
{
try
{
Session session = getSession();
int isolationLevel = session.connection().getTransactionIsolation();
try
{
session.connection().setTransactionIsolation(1);
Query query = getSession().getNamedQuery("permission.GetDmNodeCountWherePermissionsHaveChanged");
query.setParameter("above", above);
Long answer = (Long) query.uniqueResult();
return answer;
}
finally
{
session.connection().setTransactionIsolation(isolationLevel);
}
}
catch (SQLException e)
{
throw new AlfrescoRuntimeException("Failed to set TX isolation level", e);
}
}
}

View File

@@ -0,0 +1,405 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.domain.hibernate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.domain.AccessControlListDAO;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.hibernate.AVMAccessControlListDAO.CounterSet;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
import org.alfresco.repo.security.permissions.impl.AclChange;
import org.alfresco.repo.security.permissions.impl.AclDaoComponent;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.StoreRef;
/**
* DAO layer for the improved ACL implemtentation.
*
* This layer is responsible for setting ACLs and any cascade behaviour required.
* It also implements the migration from the old implementation to the new.
*
* @author andyh
*
*/
public class DMAccessControlListDAO implements AccessControlListDAO
{
/**
* The DAO for Nodes.
*/
private NodeDaoService nodeDaoService;
private NodeService nodeService;
private AclDaoComponent aclDaoComponent;
private HibernateSessionHelper hibernateSessionHelper;
/**
* Set the node dao service
*
* @param nodeDaoService
*/
public void setNodeDaoService(NodeDaoService nodeDaoService)
{
this.nodeDaoService = nodeDaoService;
}
/**
* Set the ACL DAO components
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponent aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
/**
* Set the hibernate session helper for session size management
*
* @param hibernateSessionHelper
*/
public void setHibernateSessionHelper(HibernateSessionHelper hibernateSessionHelper)
{
this.hibernateSessionHelper = hibernateSessionHelper;
}
/**
* Set the node service.
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
public void forceCopy(NodeRef nodeRef)
{
// Nothing to do
}
public DbAccessControlList getAccessControlList(NodeRef nodeRef)
{
Node node = nodeDaoService.getNode(nodeRef);
if (node == null)
{
throw new InvalidNodeRefException(nodeRef);
}
return node.getAccessControlList();
}
public DbAccessControlList getAccessControlList(StoreRef storeRef)
{
return null;
}
public Long getIndirectAcl(NodeRef nodeRef)
{
return getAccessControlList(nodeRef).getId();
}
public Long getInheritedAcl(NodeRef nodeRef)
{
Node node = nodeDaoService.getNode(nodeRef);
ChildAssoc ca = nodeDaoService.getPrimaryParentAssoc(node);
if ((ca != null) && (ca.getParent() != null))
{
DbAccessControlList acl = getAccessControlList(ca.getParent().getNodeRef());
if (acl != null)
{
return acl.getId();
}
else
{
return null;
}
}
else
{
return null;
}
}
public Map<ACLType, Integer> patchAcls()
{
CounterSet result = new CounterSet();
List<StoreRef> stores = nodeService.getStores();
for (StoreRef store : stores)
{
@SuppressWarnings("unused")
CounterSet update;
update = fixOldDmAcls(nodeService.getRootNode(store));
}
HashMap<ACLType, Integer> toReturn = new HashMap<ACLType, Integer>();
toReturn.put(ACLType.DEFINING, Integer.valueOf(result.get(ACLType.DEFINING).getCounter()));
toReturn.put(ACLType.FIXED, Integer.valueOf(result.get(ACLType.FIXED).getCounter()));
toReturn.put(ACLType.GLOBAL, Integer.valueOf(result.get(ACLType.GLOBAL).getCounter()));
toReturn.put(ACLType.LAYERED, Integer.valueOf(result.get(ACLType.LAYERED).getCounter()));
toReturn.put(ACLType.OLD, Integer.valueOf(result.get(ACLType.OLD).getCounter()));
toReturn.put(ACLType.SHARED, Integer.valueOf(result.get(ACLType.SHARED).getCounter()));
return toReturn;
}
private CounterSet fixOldDmAcls(NodeRef nodeRef)
{
hibernateSessionHelper.mark();
try
{
return fixOldDmAclsImpl(nodeRef);
}
finally
{
hibernateSessionHelper.resetAndRemoveMark();
}
}
private CounterSet fixOldDmAclsImpl(NodeRef nodeRef)
{
CounterSet result = new CounterSet();
// Do the children first
for (ChildAssociationRef child : nodeService.getChildAssocs(nodeRef))
{
CounterSet update = fixOldDmAcls(child.getChildRef());
result.add(update);
}
DbAccessControlList existingAcl = getAccessControlList(nodeRef);
if (existingAcl != null)
{
if (existingAcl.getAclType() == ACLType.OLD)
{
result.increment(ACLType.DEFINING);
//
SimpleAccessControlListProperties properties = DMPermissionsDaoComponentImpl.getDefaultProperties();
// Accept default versioning
Long id = aclDaoComponent.createAccessControlList(properties);
DbAccessControlList newAcl = aclDaoComponent.getDbAccessControlList(id);
AccessControlList existing = aclDaoComponent.getAccessControlList(existingAcl.getId());
for (AccessControlEntry entry : existing.getEntries())
{
if (entry.getPosition() == 0)
{
aclDaoComponent.setAccessControlEntry(id, entry);
}
}
setAccessControlList(nodeRef, newAcl);
// Cascade to children - changes should all be 1-1 so we do not have to post fix
List<AclChange> changes = new ArrayList<AclChange>();
setFixedAcls(nodeRef, aclDaoComponent.getInheritedAccessControlList(id), changes, false);
}
else
{
// Already fixed up :-)
}
}
return result;
}
public void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl)
{
Node node = nodeDaoService.getNode(nodeRef);
if (node == null)
{
throw new InvalidNodeRefException(nodeRef);
}
node.setAccessControlList(acl);
}
public void setAccessControlList(StoreRef storeRef, DbAccessControlList acl)
{
throw new UnsupportedOperationException();
}
public List<AclChange> setInheritanceForChildren(NodeRef parent, Long mergeFrom)
{
List<AclChange> changes = new ArrayList<AclChange>();
setFixedAcls(parent, mergeFrom, changes, false);
return changes;
}
public void updateChangedAcls(NodeRef startingPoint, List<AclChange> changes)
{
// Nothing to do: no nodes change as a result of ACL changes
}
/**
* Support to set ACLs and cascade fo required
*
* @param nodeRef
* @param mergeFrom
* @param changes
* @param set
*/
public void setFixedAcls(NodeRef nodeRef, Long mergeFrom, List<AclChange> changes, boolean set)
{
if (nodeRef == null)
{
return;
}
else
{
if (set)
{
setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(mergeFrom));
}
List<ChildAssociationRef> children = nodeService.getChildAssocs(nodeRef);
for (ChildAssociationRef child : children)
{
DbAccessControlList acl = getAccessControlList(child.getChildRef());
if (acl == null)
{
hibernateSessionHelper.mark();
try
{
setFixedAcls(child.getChildRef(), mergeFrom, changes, true);
}
finally
{
hibernateSessionHelper.resetAndRemoveMark();
}
}
else if (acl.getAclType() == ACLType.LAYERED)
{
throw new UnsupportedOperationException();
}
else if (acl.getAclType() == ACLType.DEFINING)
{
@SuppressWarnings("unused")
List<AclChange> newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFrom, acl.getId());
}
else
{
hibernateSessionHelper.mark();
try
{
setFixedAcls(child.getChildRef(), mergeFrom, changes, true);
}
finally
{
hibernateSessionHelper.resetAndRemoveMark();
}
}
}
}
}
/**
* Static support to set ACLs - required for use by the dbNodeService
*
* @param nodeRef
* @param mergeFrom
* @param set
* @param nodeService
* @param aclDaoComponent
* @param nodeDaoService
*/
public static void setFixedAcls(NodeRef nodeRef, Long mergeFrom, boolean set, NodeService nodeService, AclDaoComponent aclDaoComponent, NodeDaoService nodeDaoService)
{
if (nodeRef == null)
{
return;
}
else
{
if (set)
{
setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(mergeFrom), nodeDaoService);
}
List<ChildAssociationRef> children = nodeService.getChildAssocs(nodeRef);
for (ChildAssociationRef child : children)
{
DbAccessControlList acl = getAccessControlList(child.getChildRef(), nodeDaoService);
if (acl == null)
{
setFixedAcls(child.getChildRef(), mergeFrom, true, nodeService, aclDaoComponent, nodeDaoService);
}
else if (acl.getAclType() == ACLType.LAYERED)
{
throw new UnsupportedOperationException();
}
else if (acl.getAclType() == ACLType.DEFINING)
{
@SuppressWarnings("unused")
List<AclChange> newChanges = aclDaoComponent.mergeInheritedAccessControlList(mergeFrom, acl.getId());
}
else
{
setFixedAcls(child.getChildRef(), mergeFrom, true, nodeService, aclDaoComponent, nodeDaoService);
}
}
}
}
private static DbAccessControlList getAccessControlList(NodeRef nodeRef, NodeDaoService nodeDaoService)
{
Node node = nodeDaoService.getNode(nodeRef);
if (node == null)
{
throw new InvalidNodeRefException(nodeRef);
}
return node.getAccessControlList();
}
private static void setAccessControlList(NodeRef nodeRef, DbAccessControlList acl, NodeDaoService nodeDaoService)
{
Node node = nodeDaoService.getNode(nodeRef);
if (node == null)
{
throw new InvalidNodeRefException(nodeRef);
}
node.setAccessControlList(acl);
}
}

View File

@@ -0,0 +1,167 @@
/*
* Copyright (C) 2005-2007 Alfresco Software Limited.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* As a special exception to the terms and conditions of version 2.0 of
* the GPL, you may redistribute this Program in connection with Free/Libre
* and Open Source Software ("FLOSS") applications as described in Alfresco's
* FLOSS exception. You should have recieved a copy of the text describing
* the FLOSS exception, and it is also available here:
* http://www.alfresco.com/legal/licensing
*/
package org.alfresco.repo.domain.hibernate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
import org.alfresco.repo.security.permissions.impl.AclChange;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Manage creation and deletion of ACL entries for the new DM ACL implementation
*
* @author andyh
*
*/
public class DMPermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl
{
@SuppressWarnings("unused")
private static Log logger = LogFactory.getLog(DMPermissionsDaoComponentImpl.class);
@Override
protected CreationReport createAccessControlList(NodeRef nodeRef, boolean inherit, DbAccessControlList existing)
{
if (existing == null)
{
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
properties.setAclType(ACLType.DEFINING);
properties.setInherits(inherit);
properties.setVersioned(false);
// Accept default versioning
Long id = aclDaoComponent.createAccessControlList(properties);
List<AclChange> changes = new ArrayList<AclChange>();
DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id);
changes.add(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType()));
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, aclDaoComponent.getInheritedAccessControlList(id)));
getACLDAO(nodeRef).setAccessControlList(nodeRef, acl);
return new CreationReport(acl, changes);
}
SimpleAccessControlListProperties properties;
Long id;
List<AclChange> changes;
DbAccessControlList acl;
switch (existing.getAclType())
{
case OLD:
throw new IllegalStateException("Can not mix old and new style permissions");
case DEFINING:
return new CreationReport(existing, Collections.<AclChange> emptyList());
case FIXED:
case GLOBAL:
case SHARED:
// create new defining, wire up and report changes to acl required.
properties = new SimpleAccessControlListProperties();
properties.setAclType(ACLType.DEFINING);
properties.setInherits(existing.getInherits());
properties.setVersioned(false);
id = aclDaoComponent.createAccessControlList(properties);
changes = new ArrayList<AclChange>();
acl = aclDaoComponent.getDbAccessControlList(id);
changes.add(new AclDaoComponentImpl.AclChangeImpl(existing.getId(), id, existing.getAclType(), acl.getAclType()));
changes.addAll(aclDaoComponent.mergeInheritedAccessControlList(existing.getId(), id));
// set this to inherit to children
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, aclDaoComponent.getInheritedAccessControlList(id)));
getACLDAO(nodeRef).setAccessControlList(nodeRef, acl);
return new CreationReport(acl, changes);
case LAYERED:
throw new IllegalStateException("Layering is not supported for DM permissions");
default:
throw new IllegalStateException("Unknown type " + existing.getAclType());
}
}
public void deletePermissions(NodeRef nodeRef)
{
DbAccessControlList acl = null;
try
{
acl = getAccessControlList(nodeRef);
}
catch (InvalidNodeRefException e)
{
return;
}
System.out.println("Deleting "+acl+" on "+nodeRef);
if (acl != null)
{
if (acl.getInheritsFrom() != null)
{
@SuppressWarnings("unused")
Long deleted = acl.getId();
Long inheritsFrom = acl.getInheritsFrom();
getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(inheritsFrom));
List<AclChange> changes = new ArrayList<AclChange>();
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom));
getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes);
aclDaoComponent.deleteAccessControlList(acl.getId());
}
else
{
// TODO: could just cear out existing
@SuppressWarnings("unused")
Long deleted = acl.getId();
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
properties = new SimpleAccessControlListProperties();
properties.setAclType(ACLType.DEFINING);
properties.setInherits(Boolean.FALSE);
properties.setVersioned(false);
Long id = aclDaoComponent.createAccessControlList(properties);
getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(id));
List<AclChange> changes = new ArrayList<AclChange>();
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, aclDaoComponent.getInheritedAccessControlList(id)));
getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes);
aclDaoComponent.deleteAccessControlList(acl.getId());
}
}
}
/**
* Get the default ACL properties
*
* @return the default properties
*/
public static SimpleAccessControlListProperties getDefaultProperties()
{
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
properties.setAclType(ACLType.DEFINING);
properties.setInherits(true);
properties.setVersioned(false);
return properties;
}
}

View File

@@ -62,7 +62,7 @@
fetch="select"
unique="false"
not-null="false"
cascade="delete" />
cascade="none" />
<!-- forward assoc to properties -->
<map
name="properties"

View File

@@ -73,7 +73,8 @@ public class OldADMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCom
logger.debug("Created Access Control List: \n" + " node: " + nodeRef + "\n" + " list: " + acl);
}
AbstractPermissionsDaoComponentImpl.CreationReport report = new AbstractPermissionsDaoComponentImpl.CreationReport(acl, Collections.<AclChange>singletonList(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType())));
AbstractPermissionsDaoComponentImpl.CreationReport report = new AbstractPermissionsDaoComponentImpl.CreationReport(acl, Collections
.<AclChange> singletonList(new AclDaoComponentImpl.AclChangeImpl(null, id, null, acl.getAclType())));
return report;
}
@@ -96,7 +97,4 @@ public class OldADMPermissionsDaoComponentImpl extends AbstractPermissionsDaoCom
aclDaoComponent.deleteAccessControlList(acl.getId());
}
}
}

View File

@@ -433,6 +433,21 @@
</query>
<query name="permission.GetDmNodeCount">
<![CDATA[
select count(*)
from org.alfresco.repo.domain.hibernate.NodeImpl
]]>
</query>
<query name="permission.GetDmNodeCountWherePermissionsHaveChanged">
<![CDATA[
select count(*)
from org.alfresco.repo.domain.hibernate.NodeImpl node
where node.accessControlList.id > :above
]]>
</query>
<!--
<query name="permission.GetAccessControlEntriesForAuthority">

View File

@@ -29,7 +29,6 @@ import java.util.Collections;
import java.util.List;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.hibernate.AbstractPermissionsDaoComponentImpl.CreationReport;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
@@ -38,6 +37,11 @@ import org.alfresco.repo.security.permissions.impl.AclChange;
import org.alfresco.service.cmr.repository.InvalidNodeRefException;
import org.alfresco.service.cmr.repository.NodeRef;
/**
* Old permissions dao component impl
* @author andyh
*
*/
public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponentImpl
{
@@ -142,17 +146,19 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent
{
if (acl.getInheritsFrom() != null)
{
@SuppressWarnings("unused")
Long deleted = acl.getId();
Long inheritsFrom = acl.getInheritsFrom();
getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(inheritsFrom));
aclDaoComponent.deleteAccessControlList(acl.getId());
List<AclChange> changes = new ArrayList<AclChange>();
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, inheritsFrom));
getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes);
aclDaoComponent.deleteAccessControlList(acl.getId());
}
else
{
// TODO: could just cear out existing
@SuppressWarnings("unused")
Long deleted = acl.getId();
SimpleAccessControlListProperties properties = new SimpleAccessControlListProperties();
properties.setAclType(ACLType.DEFINING);
@@ -160,12 +166,11 @@ public class PermissionsDaoComponentImpl extends AbstractPermissionsDaoComponent
// Accept default versioning
Long id = aclDaoComponent.createAccessControlList(properties);
getACLDAO(nodeRef).setAccessControlList(nodeRef, aclDaoComponent.getDbAccessControlList(id));
aclDaoComponent.deleteAccessControlList(acl.getId());
List<AclChange> changes = new ArrayList<AclChange>();
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, id));
changes.addAll(getACLDAO(nodeRef).setInheritanceForChildren(nodeRef, aclDaoComponent.getInheritedAccessControlList(id)));
getACLDAO(nodeRef).updateChangedAcls(nodeRef, changes);
aclDaoComponent.deleteAccessControlList(acl.getId());
}
}
}
}

View File

@@ -40,6 +40,7 @@ import java.util.Stack;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.domain.ChildAssoc;
import org.alfresco.repo.domain.DbAccessControlList;
import org.alfresco.repo.domain.Node;
import org.alfresco.repo.domain.NodeAssoc;
import org.alfresco.repo.domain.NodeStatus;
@@ -47,9 +48,16 @@ import org.alfresco.repo.domain.PropertyValue;
import org.alfresco.repo.domain.QNameDAO;
import org.alfresco.repo.domain.QNameEntity;
import org.alfresco.repo.domain.Store;
import org.alfresco.repo.domain.hibernate.DMAccessControlListDAO;
import org.alfresco.repo.domain.hibernate.DMPermissionsDaoComponentImpl;
import org.alfresco.repo.node.AbstractNodeServiceImpl;
import org.alfresco.repo.node.StoreArchiveMap;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.SimpleAccessControlListProperties;
import org.alfresco.repo.security.permissions.impl.AclDaoComponent;
import org.alfresco.repo.security.permissions.impl.PermissionsDaoComponent;
import org.alfresco.repo.tenant.TenantService;
import org.alfresco.service.cmr.dictionary.AspectDefinition;
import org.alfresco.service.cmr.dictionary.AssociationDefinition;
@@ -98,6 +106,7 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
private StoreArchiveMap storeArchiveMap;
private NodeService avmNodeService;
private TenantService tenantService;
private AclDaoComponent aclDaoComponent;
public DbNodeServiceImpl()
{
@@ -132,6 +141,11 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
this.tenantService = tenantService;
}
public void setAclDaoComponent(AclDaoComponent aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
}
/**
* Performs a null-safe get of the node
*
@@ -265,6 +279,16 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
ContentModel.ASPECT_ROOT,
Collections.<QName, Serializable>emptyMap());
// Bind root permission
if(aclDaoComponent != null)
{
SimpleAccessControlListProperties properties = DMPermissionsDaoComponentImpl.getDefaultProperties();
Long id = aclDaoComponent.createAccessControlList(properties);
DbAccessControlList acl = aclDaoComponent.getDbAccessControlList(id);
rootNode.setAccessControlList(acl);
}
// invoke policies
invokeOnCreateStore(rootNodeRef);
@@ -412,6 +436,20 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
setChildUniqueName(childNode); // ensure uniqueness
ChildAssociationRef childAssocRef = tenantService.getBaseName(childAssoc.getChildAssocRef());
// permissions behaviour
if(aclDaoComponent != null)
{
DbAccessControlList inherited = parentNode.getAccessControlList();
if (inherited == null)
{
// not fixde up yet or unset
}
else
{
childNode.setAccessControlList(aclDaoComponent.getDbAccessControlList(aclDaoComponent.getInheritedAccessControlList(inherited.getId())));
}
}
// Invoke policy behaviour
invokeOnCreateNode(childAssocRef);
invokeOnCreateChildAssociation(childAssocRef, true);
@@ -519,6 +557,29 @@ public class DbNodeServiceImpl extends AbstractNodeServiceImpl
// check that no cyclic relationships have been created
getPaths(nodeToMoveRef, false);
// Fix inherited permissions
if(aclDaoComponent != null)
{
Long targetAcl = newAssoc.getChild().getAccessControlList().getId();
AccessControlListProperties aclProperties = aclDaoComponent.getAccessControlListProperties(targetAcl);
Boolean inherits = aclProperties.getInherits();
if((inherits != null) && (inherits.booleanValue()))
{
Long parentAcl = newAssoc.getParent().getAccessControlList().getId();
Long inheritedAcl = aclDaoComponent.getInheritedAccessControlList(parentAcl);
if(aclProperties.getAclType() == ACLType.DEFINING)
{
aclDaoComponent.enableInheritance(targetAcl, parentAcl);
}
else if(aclProperties.getAclType() == ACLType.SHARED)
{
DMAccessControlListDAO.setFixedAcls(newAssoc.getChildAssocRef().getChildRef(), inheritedAcl, true, this, aclDaoComponent, nodeDaoService);
}
}
}
// invoke policy behaviour
if (movingStore)
{

View File

@@ -26,25 +26,30 @@ package org.alfresco.repo.security.permissions;
import java.io.Serializable;
/**
* Properties for an access control list
*
* @author andyh
*
*/
public interface AccessControlListProperties extends Serializable
{
/**
* Get the ACL ID
* @return
* @return the acl id
*/
public String getAclId();
/**
* Get the ACL version
* @return
* @return the acl version
*/
public Long getAclVersion();
/**
* Is this the latest version of the acl identified by the acl id string?
* @return
* @return - true if the acl is the latest version
*/
public Boolean isLatest();
@@ -57,7 +62,7 @@ public interface AccessControlListProperties extends Serializable
/**
* Get the type for this ACL
*
* @return
* @return the acl type
*/
public ACLType getAclType();
@@ -67,7 +72,14 @@ public interface AccessControlListProperties extends Serializable
*
* If an acl is versioned it can not be updated - a new copy has to be created,
*
* @return
* @return if the acl is verioned
*/
public Boolean isVersioned();
/**
* The ACL DB id
*
* @return the id
*/
public Long getId();
}

View File

@@ -24,6 +24,8 @@
*/
package org.alfresco.repo.security.permissions;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
/**
@@ -40,7 +42,7 @@ public interface DynamicAuthority
*
* @param nodeRef
* @param userName
* @return
* @return true if the current user has the authority
*/
public boolean hasAuthority(NodeRef nodeRef, String userName);
@@ -48,7 +50,15 @@ public interface DynamicAuthority
* If this authority is granted this method provides the string
* representation of the granted authority.
*
* @return
* @return the authority taht may be assigned
*/
public String getAuthority();
/**
* For what permission checks is this dynamic authority required?
* If null, it is required for all checks.
*
* @return the set of permissions for which this dynamic authority should be evaluated
*/
public Set<PermissionReference> requiredFor();
}

View File

@@ -41,14 +41,16 @@ public interface PermissionReference extends Serializable
* Get the QName of the type or aspect against which the permission is
* defined.
*
* @return
* @return the qname
*/
public QName getQName();
/**
* Get the name of the permission
*
* @return
* @return the name
*/
public String getName();
}

View File

@@ -27,6 +27,7 @@ package org.alfresco.repo.security.permissions;
import java.util.Set;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.StoreRef;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
@@ -50,8 +51,8 @@ public interface PermissionServiceSPI extends PermissionService
/**
* Get the permissions that can be set for a given type
*
* @param nodeRef
* @return
* @param type
* @return the set of permissions
*/
public Set<PermissionReference> getSettablePermissionReferences(QName type);
@@ -59,7 +60,7 @@ public interface PermissionServiceSPI extends PermissionService
* Get the permissions that can be set for a given type
*
* @param nodeRef
* @return
* @return the set of permissions
*/
public Set<PermissionReference> getSettablePermissionReferences(NodeRef nodeRef);
@@ -68,7 +69,7 @@ public interface PermissionServiceSPI extends PermissionService
* nothing of the parent permissions)
*
* @param nodeRef
* @return
* @return the node permission entry
*/
public NodePermissionEntry getSetPermissions(NodeRef nodeRef);
@@ -78,7 +79,7 @@ public interface PermissionServiceSPI extends PermissionService
*
* @param nodeRef
* @param perm
* @return
* @return the access status
*/
public AccessStatus hasPermission(NodeRef nodeRef, PermissionReference perm);
@@ -87,9 +88,8 @@ public interface PermissionServiceSPI extends PermissionService
* permission for the given authentication to access the specified name.
*
* @param nodeRef
* @param auth
* @param perm
* @return
* @return the node permission entry
*/
public NodePermissionEntry explainPermission(NodeRef nodeRef, PermissionReference perm);
@@ -124,7 +124,7 @@ public interface PermissionServiceSPI extends PermissionService
*
* @param qname - may be null if the permission name is unique
* @param permissionName
* @return
* @return the permission reference
*/
public PermissionReference getPermissionReference(QName qname, String permissionName);
@@ -132,7 +132,7 @@ public interface PermissionServiceSPI extends PermissionService
* Get the permission reference by permission name.
*
* @param permissionName
* @return
* @return the permission reference
*/
public PermissionReference getPermissionReference(String permissionName);
@@ -141,9 +141,20 @@ public interface PermissionServiceSPI extends PermissionService
* Get the string that can be used to identify the given permission reference.
*
* @param permissionReference
* @return
* @return the permission short name
*/
public String getPermission(PermissionReference permissionReference);
/**
* Delete permissions for the given recipient.
* @param recipient
*/
public void deletePermissions(String recipient);
/**
* Get the permissions set for the store
* @param storeRef
* @return - the node permission entry
*/
public NodePermissionEntry getSetPermissions(StoreRef storeRef);
}

View File

@@ -27,6 +27,12 @@ package org.alfresco.repo.security.permissions;
import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthorityType;
/**
* A basic access control entry
*
* @author andyh
*
*/
public class SimpleAccessControlEntry implements AccessControlEntry
{
/**
@@ -76,31 +82,56 @@ public class SimpleAccessControlEntry implements AccessControlEntry
return position;
}
/**
* Set the status
* @param accessStatus
*/
public void setAccessStatus(AccessStatus accessStatus)
{
this.accessStatus = accessStatus;
}
/**
* Set the type
* @param aceType
*/
public void setAceType(ACEType aceType)
{
this.aceType = aceType;
}
/**
* Set the authority
* @param authority
*/
public void setAuthority(String authority)
{
this.authority = authority;
}
/**
* Set the context
* @param context
*/
public void setContext(AccessControlEntryContext context)
{
this.context = context;
}
/**
* Set the permission
* @param permission
*/
public void setPermission(PermissionReference permission)
{
this.permission = permission;
}
/**
* Set the position
* @param position
*/
public void setPosition(Integer position)
{
this.position = position;
@@ -127,5 +158,20 @@ public class SimpleAccessControlEntry implements AccessControlEntry
}
}
@Override
public String toString()
{
StringBuilder builder = new StringBuilder();
builder.append("[");
builder.append(getPermission()).append(", ");
builder.append(getAuthority()).append(", ");
builder.append(getAccessStatus()).append(", ");
builder.append(getAceType()).append(", ");
builder.append(getPosition()).append(", ");
builder.append(getContext());
builder.append("]");
return builder.toString();
}
}

View File

@@ -24,6 +24,12 @@
*/
package org.alfresco.repo.security.permissions;
/**
* Basic implementation of access control list properties
*
* @author andyh
*
*/
public class SimpleAccessControlListProperties implements AccessControlListProperties
{
/**
@@ -43,6 +49,8 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope
private Boolean versioned;
private Long id;
public String getAclId()
{
return aclId;
@@ -73,36 +81,74 @@ public class SimpleAccessControlListProperties implements AccessControlListPrope
return versioned;
}
/**
* Set the acl id
* @param aclId
*/
public void setAclId(String aclId)
{
this.aclId = aclId;
}
/**
* Set the acl type
* @param aclType
*/
public void setAclType(ACLType aclType)
{
this.aclType = aclType;
}
/**
* Set the acl version
* @param aclVersion
*/
public void setAclVersion(Long aclVersion)
{
this.aclVersion = aclVersion;
}
/**
* Set inheritance
* @param inherits
*/
public void setInherits(boolean inherits)
{
this.inherits = inherits;
}
/**
* Set latest
* @param latest
*/
public void setLatest(boolean latest)
{
this.latest = latest;
}
/**
* Set versioned
* @param versioned
*/
public void setVersioned(boolean versioned)
{
this.versioned = versioned;
}
public Long getId()
{
return id;
}
/**
* Set the id
* @param id
*/
public void setId(Long id)
{
this.id = id;
}
}

View File

@@ -25,18 +25,22 @@
package org.alfresco.repo.security.permissions.dynamic;
import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.repo.security.permissions.impl.ModelDAO;
import org.alfresco.service.cmr.lock.LockService;
import org.alfresco.service.cmr.lock.LockStatus;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeService;
import org.alfresco.service.cmr.repository.datatype.DefaultTypeConverter;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.EqualsHelper;
import org.springframework.beans.factory.InitializingBean;
/**
@@ -48,6 +52,11 @@ public class LockOwnerDynamicAuthority implements DynamicAuthority, Initializing
private NodeService nodeService;
private ModelDAO modelDAO;
private List<String> requiredFor;
private Set<PermissionReference> whenRequired;
public boolean hasAuthority(final NodeRef nodeRef, final String userName)
{
@@ -101,16 +110,64 @@ public class LockOwnerDynamicAuthority implements DynamicAuthority, Initializing
{
throw new IllegalStateException("The NodeService service must be set");
}
if(modelDAO == null)
{
throw new IllegalStateException("The ModelDAO service must be set");
}
// buld the permission set
if(requiredFor != null)
{
whenRequired = new HashSet<PermissionReference>();
for(String permission : requiredFor)
{
PermissionReference permissionReference = modelDAO.getPermissionReference(null, permission);
whenRequired.addAll(modelDAO.getGranteePermissions(permissionReference));
whenRequired.addAll(modelDAO.getGrantingPermissions(permissionReference));
}
}
}
/**
* Set the lock service
* @param lockService
*/
public void setLockService(LockService lockService)
{
this.lockService = lockService;
}
/**
* Set the node service
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Set the permissions model dao
* @param modelDAO
*/
public void setModelDAO(ModelDAO modelDAO)
{
this.modelDAO = modelDAO;
}
/**
* Set the permissions for which this dynamic authority is required
* @param requiredFor
*/
public void setRequiredFor(List<String> requiredFor)
{
this.requiredFor = requiredFor;
}
public Set<PermissionReference> requiredFor()
{
return whenRequired;
}
}

View File

@@ -24,6 +24,9 @@
*/
package org.alfresco.repo.security.permissions.dynamic;
import java.io.Serializable;
import java.util.Map;
import javax.transaction.UserTransaction;
import junit.framework.TestCase;
@@ -43,10 +46,17 @@ import org.alfresco.service.cmr.security.AccessStatus;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.service.namespace.QName;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper;
import org.springframework.context.ApplicationContext;
/**
* Test the lock owner dynaic authority
*
* @author andyh
*
*/
public class LockOwnerDynamicAuthorityTest extends TestCase
{
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
@@ -73,11 +83,17 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
private OwnableService ownableService;
/**
*
*/
public LockOwnerDynamicAuthorityTest()
{
super();
}
/**
* @param arg0
*/
public LockOwnerDynamicAuthorityTest(String arg0)
{
super(arg0);
@@ -137,6 +153,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
super.tearDown();
}
/**
*
*/
public void testSetup()
{
assertNotNull(nodeService);
@@ -144,6 +163,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
assertNotNull(lockService);
}
/**
*
*/
public void testUnSet()
{
permissionService.setPermission(rootNodeRef, "andy", PermissionService.ALL_PERMISSIONS, true);
@@ -152,6 +174,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
authenticationService.clearCurrentSecurityContext();
}
/**
*
*/
public void testPermissionWithNoLockAspect()
{
authenticationService.authenticate("andy", "andy".toCharArray());
@@ -169,6 +194,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(rootNodeRef, PermissionService.CANCEL_CHECK_OUT));
}
/**
*
*/
public void testPermissionWithLockAspect()
{
permissionService.setPermission(rootNodeRef, "andy", PermissionService.ALL_PERMISSIONS, true);
@@ -228,6 +256,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
}
/**
*
*/
public void testCheckOutCheckInAuthorities()
{
permissionService.setPermission(rootNodeRef, "andy", PermissionService.ALL_PERMISSIONS, true);
@@ -356,11 +387,13 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode,
PermissionService.LOCK));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(testNode,
@SuppressWarnings("unused")
Map<QName, Serializable> properties = nodeService.getProperties(testNode);
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode,
PermissionService.UNLOCK));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.CHECK_OUT));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(testNode, PermissionService.CHECK_IN));
assertEquals(AccessStatus.DENIED, permissionService.hasPermission(testNode, PermissionService.CANCEL_CHECK_OUT));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.CHECK_IN));
assertEquals(AccessStatus.ALLOWED, permissionService.hasPermission(testNode, PermissionService.CANCEL_CHECK_OUT));
authenticationService.authenticate("lemur", "lemur".toCharArray());
@@ -390,6 +423,9 @@ public class LockOwnerDynamicAuthorityTest extends TestCase
}
/**
*
*/
public void testCeckInCheckOut()
{

View File

@@ -24,24 +24,39 @@
*/
package org.alfresco.repo.security.permissions.dynamic;
import java.util.Set;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.OwnableService;
import org.alfresco.service.cmr.security.PermissionService;
import org.alfresco.util.EqualsHelper;
import org.springframework.beans.factory.InitializingBean;
/**
* The owner dynamic authority
* @author andyh
*
*/
public class OwnerDynamicAuthority implements DynamicAuthority, InitializingBean
{
private OwnableService ownableService;
/**
* Standard construction
*/
public OwnerDynamicAuthority()
{
super();
}
/**
* Set the ownable service
* @param ownableService
*/
public void setOwnableService(OwnableService ownableService)
{
this.ownableService = ownableService;
@@ -72,4 +87,9 @@ public class OwnerDynamicAuthority implements DynamicAuthority, InitializingBean
return PermissionService.OWNER_AUTHORITY;
}
public Set<PermissionReference> requiredFor()
{
return null;
}
}

View File

@@ -37,7 +37,7 @@ public abstract class AbstractPermissionReference implements PermissionReference
private int hashcode = 0;
private String str = null;
public AbstractPermissionReference()
protected AbstractPermissionReference()
{
super();
}
@@ -54,6 +54,10 @@ public abstract class AbstractPermissionReference implements PermissionReference
return false;
}
AbstractPermissionReference other = (AbstractPermissionReference)o;
if(other.hashCode() != this.hashCode())
{
return false;
}
return this.getName().equals(other.getName()) && this.getQName().equals(other.getQName());
}

View File

@@ -29,6 +29,7 @@ import java.util.HashMap;
import java.util.Map;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.node.db.NodeDaoService;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.MutableAuthenticationDao;
import org.alfresco.repo.security.permissions.PermissionReference;
@@ -80,6 +81,10 @@ public class AbstractPermissionTest extends BaseSpringTest
protected AuthorityService authorityService;
protected NodeDaoService nodeDaoService;
protected AclDaoComponent aclDaoComponent;
public AbstractPermissionTest()
{
super();
@@ -103,6 +108,8 @@ public class AbstractPermissionTest extends BaseSpringTest
authenticationComponent.setCurrentUser(authenticationComponent.getSystemUserName());
authenticationDAO = (MutableAuthenticationDao) applicationContext.getBean("authenticationDao");
nodeDaoService = (NodeDaoService) applicationContext.getBean("nodeDaoService");
aclDaoComponent = (AclDaoComponent) applicationContext.getBean("aclDaoComponent");
StoreRef storeRef = nodeService.createStore(StoreRef.PROTOCOL_WORKSPACE, "Test_" + System.nanoTime());

View File

@@ -24,17 +24,24 @@
*/
package org.alfresco.repo.security.permissions.impl;
import java.util.HashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.service.namespace.QName;
/**
* A simple permission reference (not persisted).
*
* A permission is identified by name for a given type, which is identified by its qualified name.
* A simple permission reference (not persisted). A permission is identified by name for a given type, which is
* identified by its qualified name.
*
* @author andyh
*/
public class PermissionReferenceImpl extends AbstractPermissionReference
{
private static ReadWriteLock lock = new ReentrantReadWriteLock();
private static HashMap<QName, HashMap<String, PermissionReferenceImpl>> instances = new HashMap<QName, HashMap<String, PermissionReferenceImpl>>();
/**
*
*/
@@ -44,7 +51,56 @@ public class PermissionReferenceImpl extends AbstractPermissionReference
private String name;
public PermissionReferenceImpl(QName qName, String name)
/**
* Factory method to create permission references
* @param qName
* @param name
* @return the permissions reference
*/
public static PermissionReferenceImpl getPermissionReference(QName qName, String name)
{
lock.readLock().lock();
try
{
HashMap<String, PermissionReferenceImpl> typed = instances.get(qName);
if(typed != null)
{
PermissionReferenceImpl instance = typed.get(name);
if(instance != null)
{
return instance;
}
}
}
finally
{
lock.readLock().unlock();
}
lock.writeLock().lock();
try
{
HashMap<String, PermissionReferenceImpl> typed = instances.get(qName);
if(typed == null)
{
typed = new HashMap<String, PermissionReferenceImpl>();
instances.put(qName, typed);
}
PermissionReferenceImpl instance = typed.get(name);
if(instance == null)
{
instance = new PermissionReferenceImpl(qName, name);
typed.put(name, instance);
}
return instance;
}
finally
{
lock.writeLock().unlock();
}
}
protected PermissionReferenceImpl(QName qName, String name)
{
this.qName = qName;
this.name = name;

View File

@@ -44,8 +44,10 @@ import org.alfresco.repo.policy.PolicyComponent;
import org.alfresco.repo.security.authentication.AuthenticationComponent;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.repo.security.permissions.ACLType;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessControlList;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.DynamicAuthority;
import org.alfresco.repo.security.permissions.NodePermissionEntry;
import org.alfresco.repo.security.permissions.PermissionEntry;
@@ -130,7 +132,9 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
private AclDaoComponent aclDaoComponent;
/*
private PermissionReference allPermissionReference;
/**
* Standard spring construction.
*/
public PermissionServiceImpl()
@@ -142,46 +146,89 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
// Inversion of control
//
/**
* Set the dictionary service
* @param dictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Set the permissions model dao
*
* @param modelDAO
*/
public void setModelDAO(ModelDAO modelDAO)
{
this.modelDAO = modelDAO;
}
/**
* Set the node service.
*
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Set the tenant service.
* @param tenantService
*/
public void setTenantService(TenantService tenantService)
{
this.tenantService = tenantService;
}
/**
* Set the permissions dao component
*
* @param permissionsDaoComponent
*/
public void setPermissionsDaoComponent(PermissionsDaoComponent permissionsDaoComponent)
{
this.permissionsDaoComponent = permissionsDaoComponent;
}
/**
* Set the authentication component.
*
* @param authenticationComponent
*/
public void setAuthenticationComponent(AuthenticationComponent authenticationComponent)
{
this.authenticationComponent = authenticationComponent;
}
/**
* Set the authority service.
*
* @param authorityService
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
}
/**
* Set the dynamic authorities
*
* @param dynamicAuthorities
*/
public void setDynamicAuthorities(List<DynamicAuthority> dynamicAuthorities)
{
this.dynamicAuthorities = dynamicAuthorities;
}
/**
* Set the ACL DAO component.
*
* @param aclDaoComponent
*/
public void setAclDaoComponent(AclDaoComponent aclDaoComponent)
{
this.aclDaoComponent = aclDaoComponent;
@@ -198,11 +245,22 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
this.accessCache = accessCache;
}
/**
* Set the policy component
*
* @param policyComponent
*/
public void setPolicyComponent(PolicyComponent policyComponent)
{
this.policyComponent = policyComponent;
}
/**
* Cache clear on move node
*
* @param oldChildAssocRef
* @param newChildAssocRef
*/
public void onMoveNode(ChildAssociationRef oldChildAssocRef, ChildAssociationRef newChildAssocRef)
{
accessCache.clear();
@@ -249,6 +307,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
policyComponent.bindClassBehaviour(QName.createQName(NamespaceService.ALFRESCO_URI, "onMoveNode"), ContentModel.TYPE_BASE, new JavaBehaviour(this, "onMoveNode"));
allPermissionReference = getPermissionReference(ALL_PERMISSIONS);
}
//
@@ -374,14 +434,6 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
return doAvmCan(nodeRef, permIn);
}
// Allow permissions for nodes that do not exist
if (!nodeService.exists(nodeRef))
{
return AccessStatus.ALLOWED;
}
final PermissionReference perm;
if (permIn.equals(OLD_ALL_PERMISSIONS_REFERENCE))
{
@@ -392,6 +444,31 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
perm = permIn;
}
// Allow permissions for nodes that do not exist
if (!nodeService.exists(nodeRef))
{
return AccessStatus.ALLOWED;
}
// New ACLs
AccessControlListProperties properties = permissionsDaoComponent.getAccessControlListProperties(nodeRef);
if ((properties != null) && (properties.getAclType() != null) && (properties.getAclType() != ACLType.OLD))
{
QName typeQname = nodeService.getType(nodeRef);
Set<QName> aspectQNames = nodeService.getAspects(nodeRef);
PermissionContext context = new PermissionContext(typeQname);
context.getAspects().addAll(aspectQNames);
Authentication auth = AuthenticationUtil.getCurrentEffectiveAuthentication();
String user = AuthenticationUtil.getCurrentEffectiveUserName();
for (String dynamicAuthority : getDynamicAuthorities(auth, nodeRef, perm))
{
context.addDynamicAuthorityAssignment(user, dynamicAuthority);
}
return hasPermission(properties.getId(), context, perm);
}
if (AuthenticationUtil.getCurrentEffectiveUserName() == null)
{
return AccessStatus.DENIED;
@@ -405,7 +482,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
// Get the current authentications
// Use the smart authentication cache to improve permissions performance
Authentication auth = AuthenticationUtil.getCurrentEffectiveAuthentication();
final Set<String> authorisations = getAuthorisations(auth, nodeRef);
final Set<String> authorisations = getAuthorisations(auth, nodeRef, perm);
// If the node does not support the given permission there is no point
// doing the test
@@ -494,7 +571,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
return hasPermission(aclID, context, getPermissionReference(permission));
}
public AccessStatus hasPermission(Long aclId, PermissionContext context, PermissionReference permission)
private AccessStatus hasPermission(Long aclId, PermissionContext context, PermissionReference permission)
{
if (aclId == null)
{
@@ -529,10 +607,17 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
// If the node does not support the given permission there is no point
// doing the test
QName typeQname = context.getType();
Set<QName> aspectQNames = context.getAspects();
final QName typeQname = context.getType();
final Set<QName> aspectQNames = context.getAspects();
Set<PermissionReference> available = modelDAO.getAllPermissions(typeQname, aspectQNames);
Set<PermissionReference> available = AuthenticationUtil.runAs(new RunAsWork<Set<PermissionReference>>()
{
public Set<PermissionReference> doWork() throws Exception
{
return modelDAO.getAllPermissions(typeQname, aspectQNames);
}
}, AuthenticationUtil.getSystemUserName());
available.add(getAllPermissionReference());
available.add(OLD_ALL_PERMISSIONS_REFERENCE);
@@ -555,22 +640,40 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
if (context.getStoreAcl() == null)
{
AclTest aclTest = new AclTest(permission, typeQname, aspectQNames);
result = aclTest.evaluate(authorisations, aclId);
result = aclTest.evaluate(authorisations, aclId, context);
}
else
{
Set<String> storeAuthorisations = getAuthorisations(auth, (PermissionContext) null);
AclTest aclTest = new AclTest(permission, typeQname, aspectQNames);
result = aclTest.evaluate(authorisations, aclId) && aclTest.evaluate(storeAuthorisations, context.getStoreAcl());
result = aclTest.evaluate(authorisations, aclId, context) && aclTest.evaluate(storeAuthorisations, context.getStoreAcl(), context);
}
AccessStatus status = result ? AccessStatus.ALLOWED : AccessStatus.DENIED;
return status;
}
/**
* Control permissions cache - only used when we do old style permission evaluations
* - which should only be in DM stores where no permissions have been set
*
* @author andyh
*
*/
enum CacheType
{
HAS_PERMISSION, SINGLE_PERMISSION, SINGLE_PERMISSION_GLOBAL;
/**
* cache full check
*/
HAS_PERMISSION,
/**
* Cache single permission check
*/
SINGLE_PERMISSION,
/**
* Cache single permission check for global permission checks
*/
SINGLE_PERMISSION_GLOBAL;
}
/**
@@ -591,11 +694,10 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* Get the authorisations for the currently authenticated user
*
* @param auth
* @return
* @return the set of authorisations
*/
private Set<String> getAuthorisations(Authentication auth, NodeRef nodeRef)
private Set<String> getAuthorisations(Authentication auth, NodeRef nodeRef, PermissionReference required)
{
nodeRef = tenantService.getName(nodeRef);
HashSet<String> auths = new HashSet<String>();
// No authenticated user then no permissions
@@ -618,11 +720,31 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
{
auths.add(authority.getAuthority());
}
auths.addAll(getDynamicAuthorities(auth, nodeRef, required));
auths.addAll(authorityService.getAuthorities());
return auths;
}
private Set<String> getDynamicAuthorities(Authentication auth, NodeRef nodeRef, PermissionReference required)
{
HashSet<String> auths = new HashSet<String>();
if (auth == null)
{
return auths;
}
User user = (User) auth.getPrincipal();
String username = user.getUsername();
nodeRef = tenantService.getName(nodeRef);
if (nodeRef != null)
{
if (dynamicAuthorities != null)
{
for (DynamicAuthority da : dynamicAuthorities)
{
Set<PermissionReference> requiredFor = da.requiredFor();
if ((requiredFor == null) || (requiredFor.contains(required)))
{
if (da.hasAuthority(nodeRef, username))
{
@@ -631,7 +753,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
}
}
}
auths.addAll(authorityService.getAuthorities());
}
return auths;
}
@@ -688,7 +810,8 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
deletePermission(storeRef, authority, getPermissionReference(perm));
}
public void deletePermission(StoreRef storeRef, String authority, PermissionReference perm)
private void deletePermission(StoreRef storeRef, String authority, PermissionReference perm)
{
permissionsDaoComponent.deletePermission(storeRef, authority, perm);
accessCache.clear();
@@ -706,7 +829,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
setPermission(storeRef, authority, getPermissionReference(perm), allow);
}
public void setPermission(StoreRef storeRef, String authority, PermissionReference permission, boolean allow)
private void setPermission(StoreRef storeRef, String authority, PermissionReference permission, boolean allow)
{
permissionsDaoComponent.setPermission(storeRef, authority, permission, allow);
accessCache.clear();
@@ -736,7 +859,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
deletePermission(nodeRef, authority, permission);
}
public void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm)
private void deletePermission(NodeRef nodeRef, String authority, PermissionReference perm)
{
permissionsDaoComponent.deletePermission(tenantService.getName(nodeRef), authority, perm);
accessCache.clear();
@@ -748,7 +871,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
accessCache.clear();
}
public void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow)
private void setPermission(NodeRef nodeRef, String authority, PermissionReference perm, boolean allow)
{
permissionsDaoComponent.setPermission(tenantService.getName(nodeRef), authority, perm, allow);
accessCache.clear();
@@ -789,7 +912,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
public PermissionReference getAllPermissionReference()
{
return getPermissionReference(ALL_PERMISSIONS);
return allPermissionReference;
}
public String getPermission(PermissionReference permissionReference)
@@ -922,7 +1045,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
*
* @param authorisations
* @param nodeRef
* @return
* @return true if allowed
*/
boolean evaluate(Set<String> authorisations, NodeRef nodeRef)
{
@@ -937,7 +1060,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* @param nodeRef
* @param denied
* @param recursiveIn
* @return
* @return true if allowed
*/
boolean evaluate(Set<String> authorisations, NodeRef nodeRef, Set<Pair<String, PermissionReference>> denied, MutableBoolean recursiveIn)
{
@@ -1063,7 +1186,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
return success;
}
public boolean hasSinglePermission(Set<String> authorisations, NodeRef nodeRef)
boolean hasSinglePermission(Set<String> authorisations, NodeRef nodeRef)
{
nodeRef = tenantService.getName(nodeRef);
@@ -1089,7 +1212,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
}
public boolean hasSinglePermission(Set<String> authorisations, NodeRef nodeRef, Set<Pair<String, PermissionReference>> denied)
boolean hasSinglePermission(Set<String> authorisations, NodeRef nodeRef, Set<Pair<String, PermissionReference>> denied)
{
nodeRef = tenantService.getName(nodeRef);
@@ -1179,7 +1302,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* Check if we have a global permission
*
* @param authorisations
* @return
* @return true if allowed
*/
private boolean checkGlobalPermissions(Set<String> authorisations)
{
@@ -1197,7 +1320,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* Get the list of permissions denied for this node.
*
* @param nodeRef
* @return
* @return the list of denied permissions
*/
Set<Pair<String, PermissionReference>> getDenied(NodeRef nodeRef)
{
@@ -1249,7 +1372,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* @param authorisations
* @param nodeRef
* @param denied
* @return
* @return true if the check is required
*/
boolean checkRequired(Set<String> authorisations, NodeRef nodeRef, Set<Pair<String, PermissionReference>> denied)
{
@@ -1284,7 +1407,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* the set of authorities
* @param denied -
* the set of denied permissions/authority pais
* @return
* @return true if granted
*/
private boolean isGranted(PermissionEntry pe, Set<String> authorisations, Set<Pair<String, PermissionReference>> denied)
{
@@ -1426,13 +1549,10 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* @param nodeRef
* @param denied
* @param recursiveIn
* @return
* @return true if granted
*/
boolean evaluate(Set<String> authorisations, Long aclId)
boolean evaluate(Set<String> authorisations, Long aclId, PermissionContext context)
{
// Do we defer our required test to a parent (yes if not null)
MutableBoolean recursiveOut = null;
// Start out true and "and" all other results
boolean success = true;
@@ -1442,7 +1562,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
{
// We have to do the test as no parent will help us out
success &= hasSinglePermission(authorisations, aclId);
success &= hasSinglePermission(authorisations, aclId, context);
if (!success)
{
@@ -1455,7 +1575,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
{
// Build a new test
AclTest nt = new AclTest(pr, typeQName, aspectQNames);
success &= nt.evaluate(authorisations, aclId);
success &= nt.evaluate(authorisations, aclId, context);
if (!success)
{
return false;
@@ -1465,7 +1585,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
return success;
}
public boolean hasSinglePermission(Set<String> authorisations, Long aclId)
boolean hasSinglePermission(Set<String> authorisations, Long aclId, PermissionContext context)
{
// Check global permission
@@ -1474,7 +1594,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
return true;
}
return checkRequired(authorisations, aclId);
return checkRequired(authorisations, aclId, context);
}
@@ -1482,7 +1602,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* Check if we have a global permission
*
* @param authorisations
* @return
* @return true if granted
*/
private boolean checkGlobalPermissions(Set<String> authorisations)
{
@@ -1502,9 +1622,9 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* @param authorisations
* @param nodeRef
* @param denied
* @return
* @return true if a check is required
*/
boolean checkRequired(Set<String> authorisations, Long aclId)
boolean checkRequired(Set<String> authorisations, Long aclId, PermissionContext context)
{
AccessControlList acl = aclDaoComponent.getAccessControlList(aclId);
@@ -1519,7 +1639,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
// We could have other voting style mechanisms here
for (AccessControlEntry ace : acl.getEntries())
{
if (isGranted(ace, authorisations, denied))
if (isGranted(ace, authorisations, denied, context))
{
return true;
}
@@ -1538,14 +1658,39 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
* the set of authorities
* @param denied -
* the set of denied permissions/authority pais
* @return
* @return true if granted
*/
private boolean isGranted(AccessControlEntry ace, Set<String> authorisations, Set<Pair<String, PermissionReference>> denied)
private boolean isGranted(AccessControlEntry ace, Set<String> authorisations, Set<Pair<String, PermissionReference>> denied, PermissionContext context)
{
// If the permission entry denies then we just deny
if (ace.getAccessStatus() == AccessStatus.DENIED)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), ace.getPermission()));
Set<PermissionReference> granters = modelDAO.getGrantingPermissions(ace.getPermission());
for (PermissionReference granter : granters)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), granter));
}
// All the things granted by this permission must be
// denied
Set<PermissionReference> grantees = modelDAO.getGranteePermissions(ace.getPermission());
for (PermissionReference grantee : grantees)
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), grantee));
}
// All permission excludes all permissions available for
// the node.
if (ace.getPermission().equals(getAllPermissionReference()) || ace.getPermission().equals(OLD_ALL_PERMISSIONS_REFERENCE))
{
for (PermissionReference deny : modelDAO.getAllPermissions(context.getType(), context.getAspects()))
{
denied.add(new Pair<String, PermissionReference>(ace.getAuthority(), deny));
}
}
return false;
}
@@ -1611,7 +1756,7 @@ public class PermissionServiceImpl implements PermissionServiceSPI, Initializing
// If the permission has a match in both the authorities and
// granters list it is allowed
// It applies to the current user and it is granted
if (authorisations.contains(pe.getAuthority()) && granters.contains(pe.getPermissionReference()))
if (granters.contains(pe.getPermissionReference()) && authorisations.contains(pe.getAuthority()))
{
{
return true;

View File

@@ -35,8 +35,10 @@ import net.sf.acegisecurity.GrantedAuthority;
import org.alfresco.model.ContentModel;
import org.alfresco.repo.model.filefolder.FileFolderServiceImpl;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.permissions.AccessControlEntry;
import org.alfresco.repo.security.permissions.AccessDeniedException;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.service.cmr.repository.ChildAssociationRef;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AccessPermission;
import org.alfresco.service.cmr.security.AccessStatus;
@@ -135,6 +137,9 @@ public class PermissionServiceTest extends AbstractPermissionTest
public Object doWork() throws Exception
{
assertEquals("andy", AuthenticationUtil.getCurrentRealUserName());
assertEquals("admin", AuthenticationUtil.getCurrentEffectiveUserName());
assertTrue(permissionService.hasPermission(n1, getPermission(PermissionService.CONTRIBUTOR)) == AccessStatus.ALLOWED);
assertEquals("andy", AuthenticationUtil.getCurrentRealUserName());
@@ -318,6 +323,24 @@ public class PermissionServiceTest extends AbstractPermissionTest
// testUnset();
}
private void printPermissions(NodeRef nodeRef, String path)
{
Long id = nodeDaoService.getNode(nodeRef).getAccessControlList().getId();
System.out.println(path + " has "+id);
for(AccessControlEntry entry : aclDaoComponent.getAccessControlList(id).getEntries())
{
System.out.println("\t\t "+id+" "+entry);
}
List<ChildAssociationRef> children = nodeService.getChildAssocs(nodeRef);
for(ChildAssociationRef child: children)
{
String newPath = path+"/"+child.getQName();
printPermissions(child.getChildRef(), newPath);
}
}
public void testSetNodePermissionEntry()
{
runAs("andy");
@@ -1740,10 +1763,14 @@ public class PermissionServiceTest extends AbstractPermissionTest
assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CHILDREN)) == AccessStatus.ALLOWED);
assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_CONTENT)) == AccessStatus.ALLOWED);
//printPermissions(rootNodeRef, "/");
permissionService.deletePermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CHILDREN), "andy", AccessStatus.ALLOWED));
permissionService.deletePermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_PROPERTIES), "andy", AccessStatus.ALLOWED));
permissionService.deletePermission(new SimplePermissionEntry(n2, getPermission(PermissionService.READ_CONTENT), "andy", AccessStatus.ALLOWED));
printPermissions(rootNodeRef, "/");
runAs("andy");
assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ)) == AccessStatus.ALLOWED);
assertFalse(permissionService.hasPermission(n2, getPermission(PermissionService.READ_PROPERTIES)) == AccessStatus.ALLOWED);

View File

@@ -27,6 +27,7 @@ package org.alfresco.repo.security.permissions.impl;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.security.permissions.AccessControlListProperties;
import org.alfresco.repo.security.permissions.NodePermissionEntry;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.PermissionReference;
@@ -45,19 +46,21 @@ public interface PermissionsDaoComponent
* Get the permissions that have been set on a given node.
*
* @param nodeRef
* @return
* @return the node permission entry
*/
public NodePermissionEntry getPermissions(NodeRef nodeRef);
/**
* Delete the access control list and all access control entries for the node.
*
* @param nodeRef the node for which to delete permission
* @param nodeRef
* the node for which to delete permission
*/
public void deletePermissions(NodeRef nodeRef);
/**
* Remove all permissions for the specified authority
*
* @param authority
*/
public void deletePermissions(String authority);
@@ -65,25 +68,29 @@ public interface PermissionsDaoComponent
/**
* Delete permission entries for the given node and authority
*
* @param nodeRef the node to query against
* @param authority the specific authority to query against
* @param nodeRef
* the node to query against
* @param authority
* the specific authority to query against
*/
public void deletePermissions(NodeRef nodeRef, String authority);
/**
* Delete as single permission entry, if a match is found.
* This deleted one permission on the node. It does not affect the persistence of any other permissions.
* Delete as single permission entry, if a match is found. This deleted one permission on the node. It does not
* affect the persistence of any other permissions.
*
* @param nodeRef the node with the access control list
* @param authority the specific authority to look for
* @param permission the permission to look for
* @param nodeRef
* the node with the access control list
* @param authority
* the specific authority to look for
* @param permission
* the permission to look for
*/
public void deletePermission(NodeRef nodeRef, String authority, PermissionReference permission);
/**
* Set a permission on a node.
* If the node has no permissions set then a default node permission (allowing inheritance) will be created to
* contain the permission entry.
* Set a permission on a node. If the node has no permissions set then a default node permission (allowing
* inheritance) will be created to contain the permission entry.
*
* @param nodeRef
* @param authority
@@ -132,9 +139,13 @@ public interface PermissionsDaoComponent
/**
* Find nodes which have the given permisson for the given authority
* @param authority - the authority to match
* @param permission - the permission to match
* @param allow - true to match allow, false to match deny
*
* @param authority -
* the authority to match
* @param permission -
* the permission to match
* @param allow -
* true to match allow, false to match deny
* @return - the set of matching nodes
*/
public Set<NodeRef> findNodeByPermission(String authority, PermissionReference permission, boolean allow);
@@ -175,8 +186,18 @@ public interface PermissionsDaoComponent
/**
* Get permission masks set on a store
*
* @param storeRef
* @return
* @return the node permission entry
*/
public NodePermissionEntry getPermissions(StoreRef storeRef);
/**
* Get the properties for the access control list
*
* @param nodeRef
* @return the properties for the access control list
*/
public AccessControlListProperties getAccessControlListProperties(NodeRef nodeRef);
}

View File

@@ -46,6 +46,13 @@ public final class SimplePermissionReference extends AbstractPermissionReference
private static HashMap<QName, HashMap<String, SimplePermissionReference>> instances = new HashMap<QName, HashMap<String, SimplePermissionReference>>();
/**
* Factory method to create simple permission refrences
*
* @param qName
* @param name
* @return a simple permission reference
*/
public static SimplePermissionReference getPermissionReference(QName qName, String name)
{
lock.readLock().lock();
@@ -101,8 +108,7 @@ public final class SimplePermissionReference extends AbstractPermissionReference
private String name;
// TODO: make protected
public SimplePermissionReference(QName qName, String name)
protected SimplePermissionReference(QName qName, String name)
{
super();
this.qName = qName;

View File

@@ -59,6 +59,12 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.InitializingBean;
/**
* Enforce permission after the method calll
*
* @author andyh
*
*/
public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider, InitializingBean
{
private static Log log = LogFactory.getLog(ACLEntryAfterInvocationProvider.class);
@@ -74,6 +80,9 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
private int maxPermissionChecks;
private long maxPermissionCheckTimeMillis;
/**
* Default constructor
*/
public ACLEntryAfterInvocationProvider()
{
super();
@@ -81,51 +90,92 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
maxPermissionCheckTimeMillis = Long.MAX_VALUE;
}
/**
* Set the permission service.
*
* @param permissionService
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Get the permission service.
* @return - the permission service
*/
public PermissionService getPermissionService()
{
return permissionService;
}
/**
* Get the namespace prefix resolver
* @return the namespace prefix resolver
*/
public NamespacePrefixResolver getNamespacePrefixResolver()
{
return nspr;
}
/**
* Set the namespace prefix resolver
* @param nspr
*/
public void setNamespacePrefixResolver(NamespacePrefixResolver nspr)
{
this.nspr = nspr;
}
/**
* Get the node service
* @return the node service
*/
public NodeService getNodeService()
{
return nodeService;
}
/**
* Set the node service
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Get the authentication service
* @return the authentication service
*/
public AuthenticationService getAuthenticationService()
{
return authenticationService;
}
/**
* Set the authentication service
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* Set the max number of permission checks
* @param maxPermissionChecks
*/
public void setMaxPermissionChecks(int maxPermissionChecks)
{
this.maxPermissionChecks = maxPermissionChecks;
}
/**
* Set the max time for permission checks
* @param maxPermissionCheckTimeMillis
*/
public void setMaxPermissionCheckTimeMillis(long maxPermissionCheckTimeMillis)
{
this.maxPermissionCheckTimeMillis = maxPermissionCheckTimeMillis;
@@ -261,7 +311,8 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
}
public NodeRef decide(
private NodeRef decide(
Authentication authentication,
Object object,
ConfigAttributeDefinition config,
@@ -304,7 +355,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
return returnedObject;
}
public FileInfo decide(
private FileInfo decide(
Authentication authentication,
Object object,
ConfigAttributeDefinition config,
@@ -336,7 +387,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
return definitions;
}
public ChildAssociationRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
private ChildAssociationRef decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
ChildAssociationRef returnedObject) throws AccessDeniedException
{
@@ -376,7 +427,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
return returnedObject;
}
public ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
private ResultSet decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
ResultSet returnedObject) throws AccessDeniedException
{
@@ -473,7 +524,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
return filteringResultSet;
}
public Collection decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
private Collection decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Collection returnedObject) throws AccessDeniedException
{
@@ -594,7 +645,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
return returnedObject;
}
public Object[] decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
private Object[] decide(Authentication authentication, Object object, ConfigAttributeDefinition config,
Object[] returnedObject) throws AccessDeniedException
{
@@ -742,7 +793,7 @@ public class ACLEntryAfterInvocationProvider implements AfterInvocationProvider,
QName qName = QName.createQName(qNameString, nspr);
required = new SimplePermissionReference(qName, permissionString);
required = SimplePermissionReference.getPermissionReference(qName, permissionString);
}
}
}

View File

@@ -77,6 +77,10 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
private AuthorityService authorityService;
/**
* Default constructor
*
*/
public ACLEntryVoter()
{
super();
@@ -85,46 +89,82 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
// ~ Methods
// ================================================================
/**
* Set the permission service
* @param permissionService
*/
public void setPermissionService(PermissionService permissionService)
{
this.permissionService = permissionService;
}
/**
* Get the permission service
* @return the permission service
*/
public PermissionService getPermissionService()
{
return permissionService;
}
/**
* Get the name space prefix resolver
* @return the name space prefix resolver
*/
public NamespacePrefixResolver getNamespacePrefixResolver()
{
return nspr;
}
/**
* Set the name space prefix resolver
* @param nspr
*/
public void setNamespacePrefixResolver(NamespacePrefixResolver nspr)
{
this.nspr = nspr;
}
/**
* Get the node service
* @return the node service
*/
public NodeService getNodeService()
{
return nodeService;
}
/**
* Set the node service
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
}
/**
* Get the authentication service
* @return the authentication service
*/
public AuthenticationService getAuthenticationService()
{
return authenticationService;
}
/**
* Set the authentication service
* @param authenticationService
*/
public void setAuthenticationService(AuthenticationService authenticationService)
{
this.authenticationService = authenticationService;
}
/**
* Set the authority service
* @param authorityService
*/
public void setAuthorityService(AuthorityService authorityService)
{
this.authorityService = authorityService;
@@ -434,7 +474,7 @@ public class ACLEntryVoter implements AccessDecisionVoter, InitializingBean
QName qName = QName.createQName(qNameString, nspr);
required = new SimplePermissionReference(qName, permissionString);
required = SimplePermissionReference.getPermissionReference(qName, permissionString);
}
else if (typeString.equals(ACL_METHOD))
{

View File

@@ -71,7 +71,7 @@ public abstract class AbstractPermission extends AbstractPermissionReference imp
private Set<RequiredPermission> requiredPermissions = new HashSet<RequiredPermission>();
public AbstractPermission(QName typeQName)
protected AbstractPermission(QName typeQName)
{
super();
this.typeQName = typeQName;
@@ -134,11 +134,19 @@ public abstract class AbstractPermission extends AbstractPermissionReference imp
return name;
}
/**
* Get the required permissions
* @return the required permissions
*/
public final Set<RequiredPermission> getRequiredPermissions()
{
return Collections.unmodifiableSet(requiredPermissions);
}
/**
* Get the type for this permission
* @return the type
*/
public final QName getTypeQName()
{
return typeQName;

View File

@@ -67,6 +67,10 @@ public class ModelPermissionEntry implements PermissionEntry, XMLModelInitialisa
private NodeRef nodeRef;
/**
* Create a permission model entry with the given node context
* @param nodeRef (may be null)
*/
public ModelPermissionEntry(NodeRef nodeRef)
{
super();
@@ -83,6 +87,10 @@ public class ModelPermissionEntry implements PermissionEntry, XMLModelInitialisa
return getRecipient();
}
/**
* Synonym for authority
* @return recipient/authority
*/
public String getRecipient()
{
return recipient;
@@ -145,6 +153,6 @@ public class ModelPermissionEntry implements PermissionEntry, XMLModelInitialisa
Element permissionReferenceElement = element.element(PERMISSION_REFERENCE);
QName typeQName = QName.createQName(permissionReferenceElement.attributeValue(TYPE), nspr);
String name = permissionReferenceElement.attributeValue(NAME);
permissionReference = new PermissionReferenceImpl(typeQName, name);
permissionReference = PermissionReferenceImpl.getPermissionReference(typeQName, name);
}
}

View File

@@ -75,6 +75,11 @@ public class Permission extends AbstractPermission implements XMLModelInitialisa
private boolean requiresType;
/**
* A permission for the given type
*
* @param typeQName
*/
public Permission(QName typeQName)
{
super(typeQName);
@@ -141,25 +146,41 @@ public class Permission extends AbstractPermission implements XMLModelInitialisa
String grantedName = grantedToGroupsElement.attributeValue(GTG_NAME);
grantedToGroups.add(new PermissionReferenceImpl(qName, grantedName));
grantedToGroups.add(PermissionReferenceImpl.getPermissionReference(qName, grantedName));
}
}
/**
* Default deny/allow for this permission
* @return the access status
*/
public AccessStatus getDefaultPermission()
{
return defaultPermission;
}
/**
* Get the groups for which this permission is granted (by definition - filled in by the model API)
* @return the specifed groups
*/
public Set<PermissionReference> getGrantedToGroups()
{
return Collections.unmodifiableSet(grantedToGroups);
}
/**
* Should this permission be shown to the UI?
* @return return true if the permission be shown in the UI.
*/
public boolean isExposed()
{
return isExposed;
}
/**
* Does a node have to have the type/aspect for the permission to apply?
* @return true if a node must have the type/aspect for the permission to apply.
*/
public boolean isTypeRequired()
{
return requiresType;

View File

@@ -83,6 +83,10 @@ public final class PermissionGroup extends AbstractPermissionReference implement
private boolean requiresType;
/**
* Permission group for the given type or aspect.
* @param container
*/
public PermissionGroup(QName container)
{
super();
@@ -160,11 +164,15 @@ public final class PermissionGroup extends AbstractPermissionReference implement
qName = container;
}
String refName = includePermissionGroupElement.attributeValue(PERMISSION_GROUP);
PermissionReference permissionReference = new PermissionReferenceImpl(qName, refName);
PermissionReference permissionReference = PermissionReferenceImpl.getPermissionReference(qName, refName);
includedPermissionGroups.add(permissionReference);
}
}
/**
* What permission groups are included in this one (for ease of definition)
* @return - the set of included permission from teh definitio
*/
public Set<PermissionReference> getIncludedPermissionGroups()
{
return Collections.unmodifiableSet(includedPermissionGroups);
@@ -175,6 +183,10 @@ public final class PermissionGroup extends AbstractPermissionReference implement
return name;
}
/**
* Does this permission group allow full control?
* @return true if this definition allows full control
*/
public boolean isAllowFullControl()
{
return allowFullControl;
@@ -185,22 +197,37 @@ public final class PermissionGroup extends AbstractPermissionReference implement
return container;
}
/**
* Does this definition extend another (from a base type as defined in the DD)
* @return true if the permission is extended from another type
*/
public boolean isExtends()
{
return extendz;
}
/**
* Get the class
* @return - the class
*/
public QName getTypeQName()
{
return type;
}
/**
* Expose in the UI?
* @return exposed -> true
*/
public boolean isExposed()
{
return isExposed;
}
/**
* Does a node have to have a the type for the permission to apply?
* @return true if a node has to have the type for the permission to apply.
*/
public boolean isTypeRequired()
{
return requiresType;

View File

@@ -26,15 +26,17 @@ package org.alfresco.repo.security.permissions.impl.model;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.alfresco.repo.security.permissions.PermissionEntry;
import org.alfresco.repo.security.permissions.PermissionReference;
@@ -128,6 +130,10 @@ public class PermissionModel implements ModelDAO, InitializingBean
private Collection<QName> allAspects;
/**
* Default constructor
*
*/
public PermissionModel()
{
super();
@@ -135,16 +141,28 @@ public class PermissionModel implements ModelDAO, InitializingBean
// IOC
/**
* Set the model
* @param model
*/
public void setModel(String model)
{
this.model = model;
}
/**
* Set the dictionary service
* @param dictionaryService
*/
public void setDictionaryService(DictionaryService dictionaryService)
{
this.dictionaryService = dictionaryService;
}
/**
* Set the node service
* @param nodeService
*/
public void setNodeService(NodeService nodeService)
{
this.nodeService = nodeService;
@@ -164,7 +182,8 @@ public class PermissionModel implements ModelDAO, InitializingBean
/**
* Adds a permission model
*
* @param model path to the permission model to add
* @param model
* path to the permission model to add
*/
public void addPermissionModel(String model)
{
@@ -263,11 +282,20 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
/**
* Set the default access status
* @return the default access status
*/
public AccessStatus getDefaultPermission()
{
return defaultPermission;
}
/**
* Get the default acces status for the givne permission
* @param pr
* @return the access status
*/
public AccessStatus getDefaultPermission(PermissionReference pr)
{
Permission p = permissionMap.get(pr);
@@ -286,6 +314,10 @@ public class PermissionModel implements ModelDAO, InitializingBean
return Collections.unmodifiableSet(globalPermissions);
}
/**
* Get the permission sets by type
* @return the permission sets by type
*/
public Map<QName, PermissionSet> getPermissionSets()
{
return Collections.unmodifiableMap(permissionSets);
@@ -408,14 +440,15 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
if (pg.isTypeRequired() == typeRequired)
{
target.add(pg);
target.add(SimplePermissionReference.getPermissionReference(pg.getQName(), pg.getName()));
}
}
else if (exposedOnly)
{
if (pg.isTypeRequired() == typeRequired)
{
target.add(getBasePermissionGroup(pg));
PermissionReference base = getBasePermissionGroup(pg);
target.add(SimplePermissionReference.getPermissionReference(base.getQName(), base.getName()));
}
}
}
@@ -426,7 +459,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
if (p.isTypeRequired() == typeRequired)
{
target.add(p);
target.add(SimplePermissionReference.getPermissionReference(p.getQName(), p.getName()));
}
}
}
@@ -463,7 +496,6 @@ public class PermissionModel implements ModelDAO, InitializingBean
ClassDefinition cd = dictionaryService.getClass(typeName);
permissions.addAll(getAllPermissionsImpl(typeName, exposedOnly));
if (cd != null)
{
Set<QName> defaultAspects = new HashSet<QName>();
@@ -491,7 +523,12 @@ public class PermissionModel implements ModelDAO, InitializingBean
Set<PermissionReference> granters = grantingPermissions.get(permissionReference);
if (granters == null)
{
granters = getGrantingPermissionsImpl(permissionReference);
Set<PermissionReference> internal = getGrantingPermissionsImpl(permissionReference);
granters = new HashSet<PermissionReference>();
for (PermissionReference grantee : internal)
{
granters.add(SimplePermissionReference.getPermissionReference(grantee.getQName(), grantee.getName()));
}
granters = Collections.unmodifiableSet(granters);
grantingPermissions.put(permissionReference, granters);
}
@@ -564,7 +601,12 @@ public class PermissionModel implements ModelDAO, InitializingBean
Set<PermissionReference> grantees = granteePermissions.get(permissionReference);
if (grantees == null)
{
grantees = getGranteePermissionsImpl(permissionReference);
Set<PermissionReference> internal = getGranteePermissionsImpl(permissionReference);
grantees = new HashSet<PermissionReference>();
for (PermissionReference grantee : internal)
{
grantees.add(SimplePermissionReference.getPermissionReference(grantee.getQName(), grantee.getName()));
}
grantees = Collections.unmodifiableSet(grantees);
granteePermissions.put(permissionReference, grantees);
}
@@ -591,7 +633,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
if (pg.getTypeQName() != null)
{
permissions.addAll(getGranteePermissions(new SimplePermissionReference(pg.getTypeQName(), pg.getName())));
permissions.addAll(getGranteePermissions(SimplePermissionReference.getPermissionReference(pg.getTypeQName(), pg.getName())));
}
else
{
@@ -600,7 +642,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
if (parent != null)
{
classDefinition = dictionaryService.getClass(parent);
PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName()));
PermissionGroup attempt = getPermissionGroupOrNull(SimplePermissionReference.getPermissionReference(parent, pg.getName()));
if (attempt != null)
{
permissions.addAll(getGranteePermissions(attempt));
@@ -642,11 +684,11 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
for (PermissionGroup pg : ps.getPermissionGroups())
{
permissions.add(pg);
permissions.add(SimplePermissionReference.getPermissionReference(pg.getQName(), pg.getName()));
}
for (Permission p : ps.getPermissions())
{
permissions.add(p);
permissions.add(SimplePermissionReference.getPermissionReference(p.getQName(), p.getName()));
}
}
return permissions;
@@ -656,7 +698,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* Support to find permission groups
*
* @param target
* @return
* @return the permission group
*/
private PermissionGroup getPermissionGroupOrNull(PermissionReference target)
{
@@ -668,7 +710,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* Support to get a permission group
*
* @param target
* @return
* @return the permission group
*/
private PermissionGroup getPermissionGroup(PermissionReference target)
{
@@ -684,7 +726,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* Get the base permission group for a given permission group.
*
* @param pg
* @return
* @return the permission group
*/
private synchronized PermissionGroup getBasePermissionGroupOrNull(PermissionGroup pg)
{
@@ -701,7 +743,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* Query the model for a base permission group Uses the Data Dictionary to reolve inheritance
*
* @param pg
* @return
* @return the permission group
*/
private PermissionGroup getBasePermissionGroupOrNullImpl(PermissionGroup pg)
{
@@ -713,7 +755,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
if (pg.getTypeQName() != null)
{
return getPermissionGroup(new SimplePermissionReference(pg.getTypeQName(), pg.getName()));
return getPermissionGroup(SimplePermissionReference.getPermissionReference(pg.getTypeQName(), pg.getName()));
}
else
{
@@ -722,7 +764,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
while ((parent = classDefinition.getParentName()) != null)
{
classDefinition = dictionaryService.getClass(parent);
PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName()));
PermissionGroup attempt = getPermissionGroupOrNull(SimplePermissionReference.getPermissionReference(parent, pg.getName()));
if ((attempt != null) && (!attempt.isExtends()))
{
return attempt;
@@ -747,23 +789,184 @@ public class PermissionModel implements ModelDAO, InitializingBean
return pg;
}
static Serializable generateKey(PermissionReference required, QName qName, Set<QName> aspectQNames, RequiredPermission.On on)
static RequiredKey generateKey(PermissionReference required, QName qName, Set<QName> aspectQNames, RequiredPermission.On on)
{
LinkedHashSet<Serializable> key = new LinkedHashSet<Serializable>();
key.add(required.toString());
key.add(qName);
key.addAll(aspectQNames);
key.add(on.toString());
return key;
return RequiredKey.getRequiredKey(required, qName, aspectQNames, on);
}
private HashMap<Serializable, Set<PermissionReference>> requiredPermissionsCache = new HashMap<Serializable, Set<PermissionReference>>(1024);
/**
* Cache key
* @author andyh
*
*/
public static class RequiredKey
{
PermissionReference required;
QName qName;
Set<QName> aspectQNames;
RequiredPermission.On on;
int hashCode = 0;
private static ReadWriteLock lock = new ReentrantReadWriteLock();
private static HashMap<PermissionReference, HashMap<QName, HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>>> instances = new HashMap<PermissionReference, HashMap<QName, HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>>>();
/**
* factory for the key
*
* @param required
* @param qName
* @param aspectQNames
* @param on
* @return the key
*/
public static RequiredKey getRequiredKey(PermissionReference required, QName qName, Set<QName> aspectQNames, RequiredPermission.On on)
{
lock.readLock().lock();
try
{
HashMap<QName, HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>> byPermRef = instances.get(required);
if (byPermRef != null)
{
HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>> byType = byPermRef.get(qName);
if(byType != null)
{
EnumMap<RequiredPermission.On, RequiredKey> byAspects = byType.get(aspectQNames);
if(byAspects != null)
{
RequiredKey instance = byAspects.get(on);
if(instance != null)
{
return instance;
}
}
}
}
}
finally
{
lock.readLock().unlock();
}
lock.writeLock().lock();
try
{
HashMap<QName, HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>> byPermRef = instances.get(required);
if (byPermRef == null)
{
byPermRef = new HashMap<QName, HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>>();
instances.put(required, byPermRef);
}
HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>> byType = byPermRef.get(qName);
if(byType == null)
{
byType = new HashMap<Set<QName>, EnumMap<RequiredPermission.On, RequiredKey>>();
byPermRef.put(qName, byType);
}
EnumMap<RequiredPermission.On, RequiredKey> byAspects = byType.get(aspectQNames);
if(byAspects == null)
{
byAspects = new EnumMap<RequiredPermission.On, RequiredKey>(RequiredPermission.On.class);
byType.put(aspectQNames, byAspects);
}
RequiredKey instance = byAspects.get(on);
if(instance == null)
{
instance = new RequiredKey(required, qName, aspectQNames, on);
byAspects.put(on, instance);
}
return instance;
}
finally
{
lock.writeLock().unlock();
}
}
RequiredKey(PermissionReference required, QName qName, Set<QName> aspectQNames, RequiredPermission.On on)
{
this.required = required;
this.qName = qName;
this.aspectQNames = aspectQNames;
this.on = on;
}
@Override
public int hashCode()
{
if (hashCode == 0)
{
final int PRIME = 1000003;
int result = 1;
result = PRIME * result + ((aspectQNames == null) ? 0 : aspectQNames.hashCode());
result = PRIME * result + ((on == null) ? 0 : on.ordinal());
result = PRIME * result + ((qName == null) ? 0 : qName.hashCode());
result = PRIME * result + ((required == null) ? 0 : required.hashCode());
hashCode = result;
}
return hashCode;
}
@Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final RequiredKey other = (RequiredKey) obj;
if (required == null)
{
if (other.required != null)
return false;
}
else if (!required.equals(other.required))
return false;
if (qName == null)
{
if (other.qName != null)
return false;
}
else if (!qName.equals(other.qName))
return false;
if (on == null)
{
if (other.on != null)
return false;
}
else if (!on.equals(other.on))
return false;
if (aspectQNames == null)
{
if (other.aspectQNames != null)
return false;
}
else if (!aspectQNames.equals(other.aspectQNames))
return false;
return true;
}
}
private HashMap<RequiredKey, Set<PermissionReference>> requiredPermissionsCache = new HashMap<RequiredKey, Set<PermissionReference>>(1024);
public Set<PermissionReference> getRequiredPermissions(PermissionReference required, QName qName, Set<QName> aspectQNames, RequiredPermission.On on)
{
// Cache lookup as this is static
Serializable key = generateKey(required, qName, aspectQNames, on);
RequiredKey key = generateKey(required, qName, aspectQNames, on);
Set<PermissionReference> answer = requiredPermissionsCache.get(key);
if (answer == null)
@@ -788,7 +991,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
*
* @param required
* @param on
* @return
* @return the set of permission references
*/
private Set<PermissionReference> getRequirementsForPermission(PermissionReference required, RequiredPermission.On on)
{
@@ -814,7 +1017,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* @param on
* @param qName
* @param aspectQNames
* @return
* @return the set of permission references
*/
private Set<PermissionReference> getRequirementsForPermissionGroup(PermissionGroup target, RequiredPermission.On on, QName qName, Set<QName> aspectQNames)
{
@@ -861,7 +1064,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* @param pr
* @param typeQname
* @param aspects
* @return
* @return true if dynamic
*/
private boolean isPartOfDynamicPermissionGroup(PermissionReference pr, QName typeQname, Set<QName> aspects)
{
@@ -883,7 +1086,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
* Utility method to find a permission
*
* @param perm
* @return
* @return the permission
*/
private Permission getPermissionOrNull(PermissionReference perm)
{
@@ -905,7 +1108,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
if (pg.getTypeQName() != null)
{
return checkPermission(new SimplePermissionReference(pg.getTypeQName(), pg.getName()));
return checkPermission(SimplePermissionReference.getPermissionReference(pg.getTypeQName(), pg.getName()));
}
else
{
@@ -914,7 +1117,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
while ((parent = classDefinition.getParentName()) != null)
{
classDefinition = dictionaryService.getClass(parent);
PermissionGroup attempt = getPermissionGroupOrNull(new SimplePermissionReference(parent, pg.getName()));
PermissionGroup attempt = getPermissionGroupOrNull(SimplePermissionReference.getPermissionReference(parent, pg.getName()));
if ((attempt != null) && attempt.isAllowFullControl())
{
return true;
@@ -970,13 +1173,13 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
for (PermissionGroup pg : ps.getPermissionGroups())
{
permissionGroupMap.put(pg, pg);
permissionReferenceMap.put(pg.toString(), pg);
permissionGroupMap.put(SimplePermissionReference.getPermissionReference(pg.getQName(), pg.getName()), pg);
permissionReferenceMap.put(pg.toString(), SimplePermissionReference.getPermissionReference(pg.getQName(), pg.getName()));
}
for (Permission p : ps.getPermissions())
{
permissionReferenceMap.put(p.toString(), p);
permissionMap.put(p, p);
permissionReferenceMap.put(p.toString(), SimplePermissionReference.getPermissionReference(p.getQName(), p.getName()));
permissionMap.put(SimplePermissionReference.getPermissionReference(p.getQName(), p.getName()), p);
}
}
@@ -995,7 +1198,8 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
else
{
uniqueMap.put(pg.getName(), getBasePermissionGroup(pg));
PermissionReference base = getBasePermissionGroup(pg);
uniqueMap.put(pg.getName(), SimplePermissionReference.getPermissionReference(base.getQName(), base.getName()));
}
}
for (Permission p : ps.getPermissions())
@@ -1011,7 +1215,7 @@ public class PermissionModel implements ModelDAO, InitializingBean
}
else
{
uniqueMap.put(p.getName(), p);
uniqueMap.put(p.getName(), SimplePermissionReference.getPermissionReference(p.getQName(), p.getName()));
}
}
}
@@ -1020,8 +1224,8 @@ public class PermissionModel implements ModelDAO, InitializingBean
{
throw new IllegalStateException("There must not be a permission with the same name as the ALL_PERMISSION constant: " + PermissionService.ALL_PERMISSIONS);
}
uniqueMap.put(PermissionService.ALL_PERMISSIONS, new SimplePermissionReference(QName
.createQName(NamespaceService.SECURITY_MODEL_1_0_URI, PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS));
uniqueMap.put(PermissionService.ALL_PERMISSIONS, SimplePermissionReference.getPermissionReference(QName.createQName(NamespaceService.SECURITY_MODEL_1_0_URI,
PermissionService.ALL_PERMISSIONS), PermissionService.ALL_PERMISSIONS));
}

View File

@@ -193,12 +193,12 @@ public class PermissionServiceNOOPImpl
public PermissionReference getPermissionReference(QName qname, String permissionName)
{
return new PermissionReferenceImpl(qname, permissionName);
return PermissionReferenceImpl.getPermissionReference(qname, permissionName);
}
public PermissionReference getPermissionReference(String permissionName)
{
return new PermissionReferenceImpl(QName.createQName("uri", "local"), permissionName);
return PermissionReferenceImpl.getPermissionReference(QName.createQName("uri", "local"), permissionName);
}
public NodePermissionEntry getSetPermissions(NodeRef nodeRef)
@@ -285,5 +285,10 @@ public class PermissionServiceNOOPImpl
return Collections.<AccessPermission>emptySet();
}
public NodePermissionEntry getSetPermissions(StoreRef storeRef)
{
return new SimpleNodePermissionEntry(null, true, Collections.<PermissionEntry>emptySet());
}
}

View File

@@ -27,6 +27,7 @@ package org.alfresco.service.cmr.security;
import java.util.Map;
import java.util.Set;
import org.alfresco.repo.security.permissions.PermissionReference;
import org.alfresco.service.Auditable;
import org.alfresco.service.PublicService;
import org.alfresco.service.cmr.repository.NodeRef;
@@ -230,9 +231,9 @@ public interface PermissionService
/**
* Check if a permission is allowed on an acl.
* @param aclID
* @param owner
* @param context
* @param permission
* @return
* @return the access status
*/
@Auditable(parameters = { "aclID", "context", "permission" })
public AccessStatus hasPermission(Long aclID, PermissionContext context, String permission);
@@ -377,7 +378,7 @@ public interface PermissionService
* @param authority
* @param permission
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef", "authority", "permission" })
@Auditable(key = Auditable.Key.ARG_0, parameters = { "storeRef", "authority", "permission" })
public void deletePermission(StoreRef storeRef, String authority, String permission);
/**
@@ -386,7 +387,7 @@ public interface PermissionService
* @param storeRef
* @param authority
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef", "authority" })
@Auditable(key = Auditable.Key.ARG_0, parameters = { "storeRef", "authority" })
public void clearPermission(StoreRef storeRef, String authority);
/**
@@ -394,16 +395,17 @@ public interface PermissionService
*
* @param storeRef
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef" })
@Auditable(key = Auditable.Key.ARG_0, parameters = { "storeRef" })
public void deletePermissions(StoreRef storeRef);
/**
* Get all the AccessPermissions that are set for anyone for the given node
*
* @param nodeRef -
* the reference to the node
* @param storeRef -
* the reference to the store
* @return the set of allowed permissions
*/
@Auditable(key = Auditable.Key.ARG_0, parameters = { "StoreRef" })
@Auditable(key = Auditable.Key.ARG_0, parameters = { "storeRef" })
public Set<AccessPermission> getAllSetPermissions(StoreRef storeRef);
}