Commit c041cea8 authored by Matija Obreza's avatar Matija Obreza
Browse files

Merge commit 'fcb0c1b3'

* commit 'fcb0c1b3':
  Final version of user story "Acl editor"

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