package de.skuzzle.polly.core.internal.roles; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.log4j.Logger; import de.skuzzle.polly.core.internal.users.UserImpl; import de.skuzzle.polly.sdk.PersistenceManagerV2; import de.skuzzle.polly.sdk.PersistenceManagerV2.Atomic; import de.skuzzle.polly.sdk.PersistenceManagerV2.Param; import de.skuzzle.polly.sdk.PersistenceManagerV2.Read; import de.skuzzle.polly.sdk.PersistenceManagerV2.Write; import de.skuzzle.polly.sdk.User; import de.skuzzle.polly.sdk.exceptions.DatabaseException; import de.skuzzle.polly.sdk.exceptions.InsufficientRightsException; import de.skuzzle.polly.sdk.exceptions.RoleException; import de.skuzzle.polly.sdk.roles.RoleManager; import de.skuzzle.polly.sdk.roles.SecurityContainer; import de.skuzzle.polly.sdk.roles.SecurityObject; public class RoleManagerImpl implements RoleManager { private final static Logger logger = Logger.getLogger(RoleManagerImpl.class .getName()); private final static Object SYNC = new Object(); private PersistenceManagerV2 persistence; private boolean rolesStale; private Set<String> allRoles; public RoleManagerImpl(PersistenceManagerV2 persistence) { this.persistence = persistence; } @Override public boolean roleExists(String roleName) { synchronized (SYNC) { return this.getRoles().contains(roleName); } } @Override public boolean permissionExists(String permissionName) { return this.persistence.atomic().findSingle(Permission.class, Permission.PERMISSION_BY_NAME, new Param(permissionName)) != null; } @Override public Set<String> getRoles() { synchronized(SYNC) { if (this.rolesStale || this.allRoles == null) { List<Role> roles = this.persistence.atomic().findList( Role.class, Role.ALL_ROLES); this.allRoles = new HashSet<String>(roles.size()); for (Role role : roles) { this.allRoles.add(role.getName()); } this.rolesStale = false; } } return Collections.unmodifiableSet(this.allRoles); } @Override public Set<String> getRoles(User user) { Set<String> result = new HashSet<String>(); for (Role role : ((de.skuzzle.polly.core.internal.users.UserImpl)user).getRoles()) { result.add(role.getName()); } return Collections.unmodifiableSet(result); } @Override public boolean hasRole(User user, String role) { return this.getRoles(user).contains(role); } @Override public Set<String> getPermissions(String roleName) { try (final Read r = this.persistence.read()) { Role role = r.findSingle( Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { return Collections.emptySet(); } return role.getPermissionNames(); } } @Override public void createRole(final String newRoleName) throws DatabaseException { synchronized(SYNC) { this.persistence.writeAtomic(new Atomic() { @Override public void perform(Write write) throws DatabaseException { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(newRoleName)); if (role != null) { return; } logger.info("Creating new Role: '" + newRoleName + "'"); write.single(new Role(newRoleName)); } }); this.rolesStale = true; } } @Override public void createRole(final String baseRoleName, final String newRoleName) throws RoleException, DatabaseException { synchronized (SYNC) { try (final Write write = this.persistence.write()) { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(newRoleName)); if (role != null) { return; } final Role baseRole = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(baseRoleName)); if (baseRole == null) { throw new RoleException("Unknown base role: '" + baseRoleName + "'"); } logger.info("Creating new Role: '" + newRoleName + "' from base role '" + baseRoleName + "'"); write.single(new Role(newRoleName, new HashSet<>(baseRole.getPermissions()))); } this.rolesStale = true; } } @Override public void deleteRole(final String roleName) throws RoleException, DatabaseException { if (roleName.equals(ADMIN_ROLE) || roleName.equals(DEFAULT_ROLE)) { throw new RoleException("Default roles cant be deleted"); } this.persistence.writeAtomic(new Atomic() { @Override public void perform(Write write) throws DatabaseException { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { return; } final List<User> allUsers = write.read().findList(User.class, UserImpl.ALL_USERS); logger.debug("Deleting role: '" + roleName + "'"); write.remove(role); for (User user : allUsers) { UserImpl puser = (UserImpl) user; puser.getRoles().remove(role); } } }); } @Override public void registerPermission(final String permission) throws DatabaseException { synchronized(SYNC) { if (!permissionExists(permission)) { logger.debug("Registering permission: '" + permission + "'"); this.persistence.writeAtomic(new Atomic() { @Override public void perform(Write write) throws DatabaseException { write.single(new Permission(permission)); } }); } } } @Override public void registerPermissions(final Set<String> permissions) throws DatabaseException { synchronized(SYNC) { this.persistence.writeAtomic(new Atomic() { @Override public void perform(Write write) { for (String perm : permissions) { if (!permissionExists(perm)) { logger.debug("Registering permission: '" + perm + "'"); write.single(new Permission(perm)); } } } }); } } @Override public void registerPermissions(SecurityContainer container) throws DatabaseException { this.registerPermissions(container.getContainedPermissions()); } @Override public void assignPermission(final String roleName, final String permission) throws DatabaseException, RoleException { synchronized(SYNC) { try (final Write write = this.persistence.write()) { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { throw new RoleException("Unknown role: " + roleName); } final Permission perm = write.read().findSingle(Permission.class, Permission.PERMISSION_BY_NAME, new Param(permission)); if (perm == null) { throw new RoleException("Unknown permission: " + permission); } // TODO: add permission to admin role logger.debug("Assigning permission '" + permission + "' to role '" + roleName + "'"); role.getPermissions().add(perm); role.setStale(true); // this updates the permission name string set } } } @Override public void assignPermissions(String roleName, final Set<String> permissions) throws RoleException, DatabaseException { synchronized(SYNC) { try (final Write write = this.persistence.write()) { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { throw new RoleException("Unknown role: " + roleName); } final List<Permission> perms = new ArrayList<Permission>(permissions.size()); for (String permission : permissions) { final Permission perm = write.read().findSingle(Permission.class, Permission.PERMISSION_BY_NAME, new Param(permission)); if (perm == null) { throw new RoleException( "Unknown permission: '" + permission + "'"); } perms.add(perm); } // TODO: add permission to admin role logger.debug("Assigning permission '" + permissions + "' to role '" + roleName + "'"); role.getPermissions().addAll(perms); role.setStale(true); // this updates the permission name string set } } } @Override public void assignPermissions(String roleName, SecurityContainer container) throws RoleException, DatabaseException { this.assignPermissions(roleName, container.getContainedPermissions()); } @Override public synchronized void removePermission(final String roleName, final String permission) throws RoleException, DatabaseException { synchronized(SYNC) { try (final Write write = this.persistence.write()) { final Role role = write.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { throw new RoleException("Unknown role: " + roleName); } final Permission perm = write.read().findSingle(Permission.class, Permission.PERMISSION_BY_NAME, new Param(permission)); if (perm == null) { return; } logger.debug("Removing permission '" + permission + "' from role '" + roleName + "'"); role.getPermissions().remove(perm); role.setStale(true); } } } @Override public synchronized void assignRole(final User user, final String roleName) throws RoleException, DatabaseException { synchronized (SYNC) { try (final Write w = this.persistence.write()) { final Role role = w.read().findSingle(Role.class, Role.ROLE_BY_NAME, new Param(roleName)); if (role == null) { throw new RoleException("Unknown role: " + roleName); } logger.debug("Assigning role '" + roleName + "' to user '" + user + "'"); ((UserImpl) user).getRoles().add(role); } } } @Override public synchronized void removeRole(final User user, final String roleName) throws RoleException, DatabaseException { synchronized (SYNC) { logger.debug("Removing role '" + roleName + "' from user '" + user + "'"); this.persistence.writeAtomic(new Atomic() { @Override public void perform(Write write) { ((UserImpl) user).getRoles().remove(new Role(roleName)); } }); } } @Override public boolean hasPermission(User user, String permission) { if (permission.equals(RoleManager.NONE_PERMISSION)) { return true; } else if (user == null) { return false; } de.skuzzle.polly.core.internal.users.UserImpl puser = (de.skuzzle.polly.core.internal.users.UserImpl) user; synchronized (SYNC) { for (Role role : puser.getRoles()) { if (role.getName().equals(RoleManager.ADMIN_ROLE) || role.getPermissionNames().contains(permission)) { return true; } } } return false; } @Override public boolean hasPermission(User user, Set<String> permissions) { for (String perm : permissions) { if (!this.hasPermission(user, perm)) { return false; } } return true; } @Override public boolean canAccess(User user, SecurityObject securityObject) { return this.hasPermission(user, securityObject.getRequiredPermission()); } @Override public void checkAccess(User user, SecurityObject securityObject) throws InsufficientRightsException { if (!this.canAccess(user, securityObject)) { this.denyAccess(securityObject); } } @Override public void denyAccess(SecurityObject securityObject) throws InsufficientRightsException { throw new InsufficientRightsException(securityObject); } }