Commit fcb0c1b3 authored by igoshin's avatar igoshin
Browse files

Final version of user story "Acl editor"

#10160
parent efebf219
...@@ -16,9 +16,6 @@ ...@@ -16,9 +16,6 @@
package org.genesys2.server.service; package org.genesys2.server.service;
import java.util.List;
import java.util.Map;
import org.genesys2.server.model.AclAwareModel; import org.genesys2.server.model.AclAwareModel;
import org.genesys2.server.model.acl.AclEntry; import org.genesys2.server.model.acl.AclEntry;
import org.genesys2.server.model.acl.AclObjectIdentity; import org.genesys2.server.model.acl.AclObjectIdentity;
...@@ -26,35 +23,41 @@ import org.genesys2.server.model.acl.AclSid; ...@@ -26,35 +23,41 @@ import org.genesys2.server.model.acl.AclSid;
import org.genesys2.server.security.AuthUserDetails; import org.genesys2.server.security.AuthUserDetails;
import org.springframework.security.acls.model.Permission; import org.springframework.security.acls.model.Permission;
import java.util.List;
import java.util.Map;
public interface AclService { public interface AclService {
void addCreatorPermissions(AclAwareModel target); void addCreatorPermissions(AclAwareModel target);
/**
* List ObjectIdentities of specified class for user with specified permission
*
* @param clazz
* @param authUser
* @return
*/
List<Long> listIdentitiesForSid(Class<? extends AclAwareModel> clazz, AuthUserDetails authUser, Permission permission);
/** AclObjectIdentity getObjectIdentity(long id);
* List ObjectIdentities of specified class for user with specified permission AclObjectIdentity getObjectIdentity(String clazz, long id);
* AclObjectIdentity ensureObjectIdentity(String clazz, long id);
* @param clazz AclObjectIdentity getObjectIdentity(AclAwareModel entity);
* @param authUser
* @return
*/
List<Long> listIdentitiesForSid(Class<? extends AclAwareModel> clazz, AuthUserDetails authUser, Permission permission);
AclObjectIdentity getObjectIdentity(long id); List<AclEntry> getAclEntries(AclObjectIdentity objectIdentity);
AclObjectIdentity getObjectIdentity(String clazz, long id); List<AclEntry> getAclEntries(AclAwareModel entity);
AclObjectIdentity ensureObjectIdentity(String clazz, long id);
AclObjectIdentity getObjectIdentity(AclAwareModel entity);
List<AclEntry> getAclEntries(AclObjectIdentity objectIdentity); Permission[] getAvailablePermissions(String className);
List<AclEntry> getAclEntries(AclAwareModel entity);
Permission[] getAvailablePermissions(String className); List<AclSid> getSids(AclAwareModel entity);
List<AclSid> getSids(long id, String className);
List<AclSid> getSids(AclAwareModel entity); Map<String, Map<Integer, Boolean>> getPermissions(AclAwareModel entity);
List<AclSid> getSids(long id, String className); Map<String, Map<Integer, Boolean>> getPermissions(long id, String className);
Map<AclSid, Map<Long, Boolean>> getPermissions(AclAwareModel entity); boolean addPermissions(long objectIdIdentity, String className, String uuid, boolean principal, Map<Integer, Boolean> permissions);
Map<AclSid, Map<Long, Boolean>> getPermissions(long id, String className);
boolean addPermissions(long objectIdIdentity, String className, String uuid, boolean principal, Permission ... permissions); void updatePermission(AclObjectIdentity entity, String sid, Map<Integer, Boolean> permissionMap);
List<AclSid> getAllSids();
} }
/** /**
* Copyright 2013 Global Crop Diversity Trust * Copyright 2013 Global Crop Diversity Trust
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
...@@ -16,10 +16,7 @@ ...@@ -16,10 +16,7 @@
package org.genesys2.server.service.impl; package org.genesys2.server.service.impl;
import java.util.HashMap; import net.sf.ehcache.CacheManager;
import java.util.List;
import java.util.Map;
import org.genesys2.server.aspect.AsAdminAspect; import org.genesys2.server.aspect.AsAdminAspect;
import org.genesys2.server.model.AclAwareModel; import org.genesys2.server.model.AclAwareModel;
import org.genesys2.server.model.acl.AclClass; import org.genesys2.server.model.acl.AclClass;
...@@ -43,6 +40,10 @@ import org.springframework.security.acls.model.Permission; ...@@ -43,6 +40,10 @@ import org.springframework.security.acls.model.Permission;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/** /**
* TODO Add support for cleaning up after objects are removed * TODO Add support for cleaning up after objects are removed
*/ */
...@@ -50,252 +51,277 @@ import org.springframework.transaction.annotation.Transactional; ...@@ -50,252 +51,277 @@ import org.springframework.transaction.annotation.Transactional;
@Transactional @Transactional
public class AclServiceImpl implements AclService { public class AclServiceImpl implements AclService {
private static final Logger LOG = LoggerFactory.getLogger(AclServiceImpl.class); private static final Logger LOG = LoggerFactory.getLogger(AclServiceImpl.class);
private static Permission[] basePermissions;
@Autowired
private UserService userService;
@Autowired
private AclClassPersistence aclClassPersistence;
@Autowired
private AclEntryPersistence aclEntryPersistence;
@Autowired
private AclObjectIdentityPersistence aclObjectIdentityPersistence;
@Autowired
private AclSidPersistence aclSidPersistence;
private static Permission[] basePermissions; @Autowired
private AsAdminAspect asAdminAspect;
@Autowired
private UserService userService;
@Autowired
private AclClassPersistence aclClassPersistence;
@Autowired @Autowired
private AclEntryPersistence aclEntryPersistence; private CacheManager cacheManager;
@Autowired static {
private AclObjectIdentityPersistence aclObjectIdentityPersistence; basePermissions = new Permission[] { BasePermission.CREATE, BasePermission.READ, BasePermission.WRITE, BasePermission.DELETE,
BasePermission.ADMINISTRATION };
@Autowired }
private AclSidPersistence aclSidPersistence;
@Autowired @Override
private AsAdminAspect asAdminAspect; @Transactional(readOnly = true)
public Permission[] getAvailablePermissions(String className) {
static { // Do not remove parameter. We may change available permissions based on
basePermissions = new Permission[] { BasePermission.CREATE, BasePermission.READ, BasePermission.WRITE, BasePermission.DELETE, // parameter type!
BasePermission.ADMINISTRATION }; return basePermissions;
} }
@Override @Override
@Transactional(readOnly = true) // @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public Permission[] getAvailablePermissions(String className) { public boolean addPermissions(long objectIdIdentity, String className, String uuid, boolean principal, Map<Integer, Boolean> permissions) {
// Do not remove parameter. We may change available permissions based on AclSid sid = ensureSid(uuid, principal);
// parameter type! AclObjectIdentity oid = ensureObjectIdentity(className, objectIdIdentity);
return basePermissions;
} addPermissions(sid, oid, permissions);
return true;
@Override }
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public boolean addPermissions(long objectIdIdentity, String className, String uuid, boolean principal, Permission... permissions) { @Override
AclSid sid = ensureSid(uuid, principal); public synchronized void addCreatorPermissions(AclAwareModel target) {
AclObjectIdentity oid = ensureObjectIdentity(className, objectIdIdentity); if (target == null) {
LOG.warn("No target specified for ACL permissions, bailing out!");
addPermissions(sid, oid, permissions); return;
return true; }
} // assume that auth user has already AclSid implemented
AuthUserDetails authUser = SecurityContextUtil.getAuthUser();
@Override if (authUser == null) {
public synchronized void addCreatorPermissions(AclAwareModel target) { LOG.warn("No user in security context, not doing ACL");
if (target == null) { return;
LOG.warn("No target specified for ACL permissions, bailing out!"); }
return;
} String uuid = authUser.getUsername();
// assume that auth user has already AclSid implemented
AuthUserDetails authUser = SecurityContextUtil.getAuthUser(); // it's ok if it is null
if (authUser == null) { // it can be pre-authorized Admin
LOG.warn("No user in security context, not doing ACL"); AclSid aclSid = ensureSid(uuid, true);
return;
} AclClass aclClass = ensureAclClass(target.getClass().getName());
String uuid = authUser.getUsername(); // create object identity
AclObjectIdentity objectIdentity = new AclObjectIdentity();
// it's ok if it is null objectIdentity.setObjectIdIdentity(target.getId());
// it can be pre-authorized Admin objectIdentity.setAclClass(aclClass);
AclSid aclSid = ensureSid(uuid, true); objectIdentity.setOwnerSid(aclSid);
objectIdentity.setParentObject(null);
AclClass aclClass = ensureAclClass(target.getClass().getName()); objectIdentity.setEntriesInheriting(false);
// create object identity // save object identity
AclObjectIdentity objectIdentity = new AclObjectIdentity(); aclObjectIdentityPersistence.save(objectIdentity);
objectIdentity.setObjectIdIdentity(target.getId());
objectIdentity.setAclClass(aclClass); Map<Integer,Boolean> permissionsMap=new HashMap<>();
objectIdentity.setOwnerSid(aclSid); for (Permission permission:basePermissions){
objectIdentity.setParentObject(null); permissionsMap.put(permission.getMask(),true);
objectIdentity.setEntriesInheriting(false); }
// save object identity addPermissions(aclSid, objectIdentity, permissionsMap);
aclObjectIdentityPersistence.save(objectIdentity); }
addPermissions(aclSid, objectIdentity, basePermissions); private AclClass ensureAclClass(String className) {
} AclClass aclClass = aclClassPersistence.findByAclClass(className);
private AclClass ensureAclClass(String className) { if (aclClass == null) {
AclClass aclClass = aclClassPersistence.findByAclClass(className); LOG.warn("Missing AclClass...");
aclClass = new AclClass();
if (aclClass == null) { aclClass.setAclClass(className);
LOG.warn("Missing AclClass..."); aclClassPersistence.save(aclClass);
aclClass = new AclClass(); }
aclClass.setAclClass(className);
aclClassPersistence.save(aclClass); return aclClass;
} }
return aclClass; private AclSid ensureSid(String uuid, boolean principal) {
} AclSid aclSid = aclSidPersistence.findBySidAndPrincipal(uuid, principal);
private AclSid ensureSid(String uuid, boolean principal) { if (aclSid == null) {
AclSid aclSid = aclSidPersistence.findBySidAndPrincipal(uuid, principal); // create Acl Sid
aclSid = new AclSid();
if (aclSid == null) { aclSid.setPrincipal(principal);
// create Acl Sid aclSid.setSid(uuid);
aclSid = new AclSid();
aclSid.setPrincipal(principal); // save it into db
aclSid.setSid(uuid); aclSidPersistence.save(aclSid);
LOG.warn("New SID " + aclSid);
// save it into db }
aclSidPersistence.save(aclSid);
LOG.warn("New SID " + aclSid); return aclSid;
} }
return aclSid; private void addPermissions(AclSid ownerSid, AclObjectIdentity objectIdentity, Map<Integer,Boolean>permissions) {
} // create Acl Entry
for (Integer mask : permissions.keySet()) {
private void addPermissions(AclSid ownerSid, AclObjectIdentity objectIdentity, Permission... permissions) { AclEntry aclEntry = new AclEntry();
// create Acl Entry aclEntry.setAclObjectIdentity(objectIdentity);
for (Permission permission : permissions) { aclEntry.setAclSid(ownerSid);
AclEntry aclEntry = new AclEntry(); aclEntry.setAceOrder(getAceOrder(objectIdentity.getId()));
aclEntry.setAclObjectIdentity(objectIdentity); aclEntry.setGranting(permissions.get(mask));
aclEntry.setAclSid(ownerSid); aclEntry.setAuditSuccess(true);
aclEntry.setAceOrder(getAceOrder(objectIdentity.getId())); aclEntry.setAuditFailure(true);
aclEntry.setGranting(true); // set full access for own organization
aclEntry.setAuditSuccess(true); aclEntry.setMask(mask);
aclEntry.setAuditFailure(true);
// set full access for own organization // save ACL
aclEntry.setMask(permission.getMask()); aclEntryPersistence.save(aclEntry);
}
// save ACL }
aclEntryPersistence.save(aclEntry);
} @Override
} @Transactional(readOnly = true)
public List<Long> listIdentitiesForSid(Class<? extends AclAwareModel> clazz, AuthUserDetails authUser, Permission permission) {
@Override return aclEntryPersistence.findObjectIdentitiesBySidAndAclClassAndMask(authUser.getUsername(), clazz.getName(), permission.getMask());
@Transactional(readOnly = true) }
public List<Long> listIdentitiesForSid(Class<? extends AclAwareModel> clazz, AuthUserDetails authUser, Permission permission) {
return aclEntryPersistence.findObjectIdentitiesBySidAndAclClassAndMask(authUser.getUsername(), clazz.getName(), permission.getMask()); /**
} * Generates next ace_order value (to avoid DuplicateIndex exception :
* acl_object_identity + ace_order is unique index)
/** *
* Generates next ace_order value (to avoid DuplicateIndex exception : * @param aclObjectEntityId
* acl_object_identity + ace_order is unique index) * - id of acl_object_identity table
* * @return - ace_order value
* @param aclObjectEntityId */
* - id of acl_object_identity table private Long getAceOrder(long aclObjectEntityId) {
* @return - ace_order value Long maxAceOrder = aclEntryPersistence.getMaxAceOrderForObjectEntity(aclObjectEntityId);
*/ return maxAceOrder != null ? maxAceOrder + 1 : 1;
private Long getAceOrder(long aclObjectEntityId) { }
Long maxAceOrder = aclEntryPersistence.getMaxAceOrderForObjectEntity(aclObjectEntityId);
return maxAceOrder != null ? maxAceOrder + 1 : 1; @Override
} @Transactional(readOnly = true)
public AclObjectIdentity getObjectIdentity(long id) {
@Override return aclObjectIdentityPersistence.findOne(id);
@Transactional(readOnly = true) }
public AclObjectIdentity getObjectIdentity(long id) {
return aclObjectIdentityPersistence.findOne(id); @Override
} @Transactional(readOnly = true)
public AclObjectIdentity ensureObjectIdentity(String className, long objectIdIdentity) {
@Override AclObjectIdentity aoi = aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(objectIdIdentity, className);
@Transactional(readOnly = true) if (aoi == null) {
public AclObjectIdentity ensureObjectIdentity(String className, long objectIdIdentity) { aoi = new AclObjectIdentity();
AclObjectIdentity aoi = aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(objectIdIdentity, className); aoi.setObjectIdIdentity(objectIdIdentity);
if (aoi == null) { aoi.setAclClass(ensureAclClass(className));
aoi = new AclObjectIdentity(); // System user UUID
aoi.setObjectIdIdentity(objectIdIdentity); String uuid = asAdminAspect.getSystemAdminAccount().getName();
aoi.setAclClass(ensureAclClass(className)); AclSid ownerSid = ensureSid(uuid, true);
// System user UUID aoi.setOwnerSid(ownerSid);
String uuid = asAdminAspect.getSystemAdminAccount().getName(); aclObjectIdentityPersistence.save(aoi);
AclSid ownerSid = ensureSid(uuid, true); }
aoi.setOwnerSid(ownerSid); return aoi;
aclObjectIdentityPersistence.save(aoi); }
}
return aoi; @Override
} @Transactional(readOnly = true)
public AclObjectIdentity getObjectIdentity(String className, long id) {
@Override return aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(id, className);
@Transactional(readOnly = true) }
public AclObjectIdentity getObjectIdentity(String className, long id) {
return aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(id, className); @Override
} @Transactional(readOnly = true)
public AclObjectIdentity getObjectIdentity(AclAwareModel entity) {
@Override return aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(entity.getId(), entity.getClass().getName());
@Transactional(readOnly = true) }
public AclObjectIdentity getObjectIdentity(AclAwareModel entity) {
return aclObjectIdentityPersistence.findByObjectIdIdentityAndClassName(entity.getId(), entity.getClass().getName()); @Override
} @Transactional(readOnly = true)
public List<AclEntry> getAclEntries(AclObjectIdentity objectIdentity) {
@Override return aclEntryPersistence.findByObjectIdentity(objectIdentity);
@Transactional(readOnly = true) }
public List<AclEntry> getAclEntries(AclObjectIdentity objectIdentity) {
return aclEntryPersistence.findByObjectIdentity(objectIdentity); @Override
} @Transactional(readOnly = true)
public List<AclEntry> getAclEntries(AclAwareModel entity) {
@Override return aclEntryPersistence.findByObjectIdentity(getObjectIdentity(entity));
@Transactional(readOnly = true) }
public List<AclEntry> getAclEntries(AclAwareModel entity) {
return aclEntryPersistence.findByObjectIdentity(getObjectIdentity(entity)); @Override
} @Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
@Override public List<AclSid> getSids(long id, String className) {
@Transactional(readOnly = true) return aclEntryPersistence.getSids(id, className);
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')") }
public List<AclSid> getSids(long id, String className) {
return aclEntryPersistence.getSids(id, className); @Override
} @Transactional(readOnly = true)
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
@Override public List<AclSid> getSids(AclAwareModel entity) {
@Transactional(readOnly = true) return aclEntryPersistence.getSids(entity.getId(), entity.getClass().getName());
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')") }
public List<AclSid> getSids(AclAwareModel entity) { @Override
return aclEntryPersistence.getSids(entity.getId(), entity.getClass().getName()); @Transactional(readOnly = true)
} public List<AclSid> getAllSids() {
return aclSidPersistence.findAll();
@Override }
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public Map<AclSid, Map<Long, Boolean>> getPermissions(long id, String className) { @Override
Map<AclSid, Map<Long, Boolean>> perm = new HashMap<AclSid, Map<Long, Boolean>>(); @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#id, #className, 'ADMINISTRATION')")
public Map<String, Map<Integer, Boolean>> getPermissions(long id, String className) {
List<AclEntry> aclEntries = getAclEntries(getObjectIdentity(className, id)); Map<String, Map<Integer, Boolean>> perm = new HashMap<>();
for (AclEntry aclEntry : aclEntries) {
Map<Long, Boolean> granted = perm.get(aclEntry.getAclSid()); List<AclEntry> aclEntries = getAclEntries(getObjectIdentity(className, id));
if (granted == null) { for (AclEntry aclEntry : aclEntries) {
perm.put(aclEntry.getAclSid(), granted = new HashMap<Long, Boolean>()); Map<Integer, Boolean> granted = perm.get(aclEntry.getAclSid().getSid());
} if (granted == null) {
granted.put(aclEntry.getMask(), Boolean.TRUE); perm.put(aclEntry.getAclSid().getSid(), granted = new HashMap<>());
} }
granted.put((int)aclEntry.getMask(), aclEntry.isGranting());
return perm; }
}
return perm;
@Override }
@PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
public Map<AclSid, Map<Long, Boolean>> getPermissions(AclAwareModel entity) { @Override
return getPermissions(entity.getId(), entity.getClass().getName()); @PreAuthorize("hasRole('ADMINISTRATOR') or hasPermission(#entity, 'ADMINISTRATION')")
} public Map<String, Map<Integer, Boolean>> getPermissions(AclAwareModel entity) {
return getPermissions(entity.getId(), entity.getClass().getName());