Mercurial > hg > LGDataverses
diff src/main/java/edu/harvard/iq/dataverse/PermissionServiceBean.java @ 10:a50cf11e5178
Rewrite LGDataverse completely upgrading to dataverse4.0
| author | Zoe Hong <zhong@mpiwg-berlin.mpg.de> |
|---|---|
| date | Tue, 08 Sep 2015 17:00:21 +0200 |
| parents | |
| children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/main/java/edu/harvard/iq/dataverse/PermissionServiceBean.java Tue Sep 08 17:00:21 2015 +0200 @@ -0,0 +1,293 @@ +package edu.harvard.iq.dataverse; + +import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; +import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean; +import edu.harvard.iq.dataverse.authorization.users.GuestUser; +import edu.harvard.iq.dataverse.authorization.Permission; +import edu.harvard.iq.dataverse.authorization.RoleAssignee; +import edu.harvard.iq.dataverse.authorization.groups.Group; +import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean; +import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AuthenticatedUsers; +import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; +import edu.harvard.iq.dataverse.authorization.users.User; +import edu.harvard.iq.dataverse.engine.command.Command; +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; +import javax.ejb.EJB; +import javax.ejb.Stateless; +import javax.inject.Inject; +import javax.inject.Named; +import java.util.HashSet; +import java.util.List; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import static edu.harvard.iq.dataverse.engine.command.CommandHelper.CH; +import java.util.LinkedList; +import javax.persistence.Query; + +/** + * Your one-stop-shop for deciding which user can do what action on which + * objects (TM). Note that this bean accesses the permissions/user assignment on + * a read-only basis. Changing the permissions a user has is done via roles and + * groups, over at {@link DataverseRoleServiceBean}. + * + * @author michael + */ +@Stateless +@Named +public class PermissionServiceBean { + + private static final Logger logger = Logger.getLogger(PermissionServiceBean.class.getName()); + + @EJB + BuiltinUserServiceBean userService; + + @EJB + AuthenticationServiceBean authenticationService; + + @EJB + DataverseRoleServiceBean roleService; + + @EJB + RoleAssigneeServiceBean roleAssigneeService; + + @EJB + DataverseServiceBean dataverseService; + + @PersistenceContext + EntityManager em; + + @EJB + GroupServiceBean groupService; + + @Inject + DataverseSession session; + + public class PermissionQuery { + + final RoleAssignee user; + final DvObject subject; + + public PermissionQuery(RoleAssignee user, DvObject subject) { + this.user = user; + this.subject = subject; + } + + public PermissionQuery user(User anotherUser) { + return new PermissionQuery(anotherUser, subject); + } + + public boolean canIssue(Class<? extends Command> cmd) { + return isUserAllowedOn(user, cmd, subject); + } + + /** + * "Fast and loose" query mechanism, allowing to pass the command class + * name. Command is assumed to live in + * {@code edu.harvard.iq.dataverse.engine.command.impl.} + * + * @deprecated + * @param commandName + * @return {@code true} iff the user has the permissions required by the + * command on the object. + * @throws ClassNotFoundException + */ + @Deprecated + public boolean canIssueCommand(String commandName) throws ClassNotFoundException { + return isUserAllowedOn(user, + (Class<? extends Command>) Class.forName("edu.harvard.iq.dataverse.engine.command.impl." + commandName), subject); + } + + public Set<Permission> get() { + return permissionsFor(user, subject); + } + + public boolean has(Permission p) { + return get().contains(p); + } + + public boolean has(String pName) { + return get().contains(Permission.valueOf(pName)); + } + + } + + public List<RoleAssignment> assignmentsOn(DvObject d) { + return em.createNamedQuery("RoleAssignment.listByDefinitionPointId", RoleAssignment.class) + .setParameter("definitionPointId", d.getId()).getResultList(); + } + + /** + * Returns the set of permission a user has over a dataverse object. + * This method takes into consideration group memberships as well. + * @param ra The role assignee. + * @param d The {@link DvObject} on which the user wants to operate + * @return the set of permissions {@code u} has over {@code d}. + */ + public Set<Permission> permissionsFor(RoleAssignee ra, DvObject d) { + + Set<Permission> permissions = EnumSet.noneOf(Permission.class); + + // Add permissions specifically given to the user + permissions.addAll( permissionsForSingleRoleAssignee(ra,d) ); + Set<Group> groupsRaBelongsTo = groupService.groupsFor(ra,d); + // Add permissions gained from groups + for ( Group g : groupsRaBelongsTo ) { + permissions.addAll( permissionsForSingleRoleAssignee(g,d) ); + } + + return permissions; + } + + public Set<Permission> permissionsForSingleRoleAssignee(RoleAssignee ra, DvObject d) { + // super user check + // @todo for 4.0, we are allowing superusers all permissions + // for secure data, we may need to restrict some of the permissions + if (ra instanceof AuthenticatedUser && ((AuthenticatedUser) ra).isSuperuser()) { + return EnumSet.allOf(Permission.class); + } + + Set<Permission> retVal = EnumSet.noneOf(Permission.class); + + if (d instanceof DataFile) { + // unrestricted files that are part of a release dataset + // automatically get download permission for everybody: + // -- L.A. 4.0 beta12 + + DataFile df = (DataFile)d; + + if (!df.isRestricted()) { + //logger.info("restricted? - nope."); + if (df.getOwner().getReleasedVersion() != null) { + //logger.info("file belongs to a dataset with a released version."); + if (df.getOwner().getReleasedVersion().getFileMetadatas() != null) { + //logger.info("going through the list of filemetadatas that belong to the released version."); + for (FileMetadata fm : df.getOwner().getReleasedVersion().getFileMetadatas()) { + if (df.equals(fm.getDataFile())) { + //logger.info("yep, found a match!"); + retVal.add(Permission.DownloadFile); + } + } + } + } + } + } + + for (RoleAssignment asmnt : assignmentsFor(ra, d)) { + retVal.addAll(asmnt.getRole().permissions()); + } + + return retVal; + } + + /** + * Returns all the role assignments that are effective for {@code ra} over + * {@code d}. Traverses the containment hierarchy of the {@code d}. + * @param ra The role assignee whose role assignemnts we look for. + * @param d The dataverse object over which the roles are assigned + * @return A set of all the role assignments for {@code ra} over {@code d}. + */ + public Set<RoleAssignment> assignmentsFor(RoleAssignee ra, DvObject d) { + Set<RoleAssignment> assignments = new HashSet<>(); + while (d != null) { + assignments.addAll(roleService.directRoleAssignments(ra, d)); + if (d instanceof Dataverse && ((Dataverse) d).isEffectivelyPermissionRoot()) { + return assignments; + } else { + d = d.getOwner(); + } + } + + return assignments; + } + + /** + * For commands with no named dvObjects, this allows a quick check whether + * a user can issue the command on the dataverse or not. + * + * @param u + * @param commandClass + * @param dvo + * @return + * @deprecated As commands have dynamic permissions now, it is not enough to look at the static permissions anymore. + * @see #isUserAllowedOn(edu.harvard.iq.dataverse.authorization.RoleAssignee, edu.harvard.iq.dataverse.engine.command.Command, edu.harvard.iq.dataverse.DvObject) + */ + public boolean isUserAllowedOn(RoleAssignee u, Class<? extends Command> commandClass, DvObject dvo) { + Map<String, Set<Permission>> required = CH.permissionsRequired(commandClass); + return isUserAllowedOn(u, required, dvo); + } + + public boolean isUserAllowedOn(RoleAssignee u, Command<?> command, DvObject dvo) { + Map<String, Set<Permission>> required = command.getRequiredPermissions(); + return isUserAllowedOn(u, required, dvo); + } + + private boolean isUserAllowedOn(RoleAssignee u, Map<String, Set<Permission>> required, DvObject dvo) { + if (required.isEmpty() || required.get("") == null) { + logger.fine("IsUserAllowedOn: empty-true"); + return true; + } else { + Set<Permission> grantedUserPermissions = permissionsFor(u, dvo); + Set<Permission> requiredPermissionSet = required.get(""); + return grantedUserPermissions.containsAll(requiredPermissionSet); + } + } + + public PermissionQuery userOn(RoleAssignee u, DvObject d) { + if (u == null) { + // get guest user for dataverse d + u = new GuestUser(); + } + return new PermissionQuery(u, d); + } + + public PermissionQuery on(DvObject d) { + if (d == null) { + throw new IllegalArgumentException("Cannot query permissions on a null DvObject"); + } + if (d.getId() == null) { + throw new IllegalArgumentException("Cannot query permissions on a DvObject with a null id."); + } + return userOn(session.getUser(), d); + } + + /** + * Go from (User, Permission) to a list of Dataverse objects that the user + * has the permission on. + * + * @param user + * @param permission + * @return The list of dataverses {@code user} has permission {@code permission} on. + */ + public List<Dataverse> getDataversesUserHasPermissionOn(User user, Permission permission) { + /** + * @todo What about groups? And how can we make this more performant? + */ + Query nativeQuery = em.createNativeQuery("SELECT id FROM dvobject WHERE dtype = 'Dataverse' and id in (select definitionpoint_id from roleassignment where assigneeidentifier in ('" + user.getIdentifier() + "'));"); + List<Integer> dataverseIdsToCheck = nativeQuery.getResultList(); + List<Dataverse> dataversesUserHasPermissionOn = new LinkedList<>(); + for (int dvIdAsInt : dataverseIdsToCheck) { + Dataverse dataverse = dataverseService.find(Long.valueOf(dvIdAsInt)); + if (userOn(user, dataverse).has(permission)) { + dataversesUserHasPermissionOn.add(dataverse); + } + } + return dataversesUserHasPermissionOn; + } + + public List<AuthenticatedUser> getUsersWithPermissionOn(Permission permission, DvObject dvo) { + List<AuthenticatedUser> usersHasPermissionOn = new LinkedList<>(); + Set<RoleAssignment> ras = roleService.rolesAssignments(dvo); + for (RoleAssignment ra : ras) { + if (ra.getRole().permissions().contains(permission)) { + RoleAssignee raee = roleAssigneeService.getRoleAssignee(ra.getAssigneeIdentifier()); + usersHasPermissionOn.addAll(roleAssigneeService.getExplicitUsers(raee)); + } + } + + return usersHasPermissionOn; + } + +}
