Mercurial > hg > LGDataverses
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 9:5926d6419569 | 10:a50cf11e5178 |
|---|---|
| 1 package edu.harvard.iq.dataverse; | |
| 2 | |
| 3 import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean; | |
| 4 import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean; | |
| 5 import edu.harvard.iq.dataverse.authorization.users.GuestUser; | |
| 6 import edu.harvard.iq.dataverse.authorization.Permission; | |
| 7 import edu.harvard.iq.dataverse.authorization.RoleAssignee; | |
| 8 import edu.harvard.iq.dataverse.authorization.groups.Group; | |
| 9 import edu.harvard.iq.dataverse.authorization.groups.GroupServiceBean; | |
| 10 import edu.harvard.iq.dataverse.authorization.groups.impl.builtin.AuthenticatedUsers; | |
| 11 import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser; | |
| 12 import edu.harvard.iq.dataverse.authorization.users.User; | |
| 13 import edu.harvard.iq.dataverse.engine.command.Command; | |
| 14 import java.util.EnumSet; | |
| 15 import java.util.Map; | |
| 16 import java.util.Set; | |
| 17 import java.util.logging.Logger; | |
| 18 import javax.ejb.EJB; | |
| 19 import javax.ejb.Stateless; | |
| 20 import javax.inject.Inject; | |
| 21 import javax.inject.Named; | |
| 22 import java.util.HashSet; | |
| 23 import java.util.List; | |
| 24 import javax.persistence.EntityManager; | |
| 25 import javax.persistence.PersistenceContext; | |
| 26 import static edu.harvard.iq.dataverse.engine.command.CommandHelper.CH; | |
| 27 import java.util.LinkedList; | |
| 28 import javax.persistence.Query; | |
| 29 | |
| 30 /** | |
| 31 * Your one-stop-shop for deciding which user can do what action on which | |
| 32 * objects (TM). Note that this bean accesses the permissions/user assignment on | |
| 33 * a read-only basis. Changing the permissions a user has is done via roles and | |
| 34 * groups, over at {@link DataverseRoleServiceBean}. | |
| 35 * | |
| 36 * @author michael | |
| 37 */ | |
| 38 @Stateless | |
| 39 @Named | |
| 40 public class PermissionServiceBean { | |
| 41 | |
| 42 private static final Logger logger = Logger.getLogger(PermissionServiceBean.class.getName()); | |
| 43 | |
| 44 @EJB | |
| 45 BuiltinUserServiceBean userService; | |
| 46 | |
| 47 @EJB | |
| 48 AuthenticationServiceBean authenticationService; | |
| 49 | |
| 50 @EJB | |
| 51 DataverseRoleServiceBean roleService; | |
| 52 | |
| 53 @EJB | |
| 54 RoleAssigneeServiceBean roleAssigneeService; | |
| 55 | |
| 56 @EJB | |
| 57 DataverseServiceBean dataverseService; | |
| 58 | |
| 59 @PersistenceContext | |
| 60 EntityManager em; | |
| 61 | |
| 62 @EJB | |
| 63 GroupServiceBean groupService; | |
| 64 | |
| 65 @Inject | |
| 66 DataverseSession session; | |
| 67 | |
| 68 public class PermissionQuery { | |
| 69 | |
| 70 final RoleAssignee user; | |
| 71 final DvObject subject; | |
| 72 | |
| 73 public PermissionQuery(RoleAssignee user, DvObject subject) { | |
| 74 this.user = user; | |
| 75 this.subject = subject; | |
| 76 } | |
| 77 | |
| 78 public PermissionQuery user(User anotherUser) { | |
| 79 return new PermissionQuery(anotherUser, subject); | |
| 80 } | |
| 81 | |
| 82 public boolean canIssue(Class<? extends Command> cmd) { | |
| 83 return isUserAllowedOn(user, cmd, subject); | |
| 84 } | |
| 85 | |
| 86 /** | |
| 87 * "Fast and loose" query mechanism, allowing to pass the command class | |
| 88 * name. Command is assumed to live in | |
| 89 * {@code edu.harvard.iq.dataverse.engine.command.impl.} | |
| 90 * | |
| 91 * @deprecated | |
| 92 * @param commandName | |
| 93 * @return {@code true} iff the user has the permissions required by the | |
| 94 * command on the object. | |
| 95 * @throws ClassNotFoundException | |
| 96 */ | |
| 97 @Deprecated | |
| 98 public boolean canIssueCommand(String commandName) throws ClassNotFoundException { | |
| 99 return isUserAllowedOn(user, | |
| 100 (Class<? extends Command>) Class.forName("edu.harvard.iq.dataverse.engine.command.impl." + commandName), subject); | |
| 101 } | |
| 102 | |
| 103 public Set<Permission> get() { | |
| 104 return permissionsFor(user, subject); | |
| 105 } | |
| 106 | |
| 107 public boolean has(Permission p) { | |
| 108 return get().contains(p); | |
| 109 } | |
| 110 | |
| 111 public boolean has(String pName) { | |
| 112 return get().contains(Permission.valueOf(pName)); | |
| 113 } | |
| 114 | |
| 115 } | |
| 116 | |
| 117 public List<RoleAssignment> assignmentsOn(DvObject d) { | |
| 118 return em.createNamedQuery("RoleAssignment.listByDefinitionPointId", RoleAssignment.class) | |
| 119 .setParameter("definitionPointId", d.getId()).getResultList(); | |
| 120 } | |
| 121 | |
| 122 /** | |
| 123 * Returns the set of permission a user has over a dataverse object. | |
| 124 * This method takes into consideration group memberships as well. | |
| 125 * @param ra The role assignee. | |
| 126 * @param d The {@link DvObject} on which the user wants to operate | |
| 127 * @return the set of permissions {@code u} has over {@code d}. | |
| 128 */ | |
| 129 public Set<Permission> permissionsFor(RoleAssignee ra, DvObject d) { | |
| 130 | |
| 131 Set<Permission> permissions = EnumSet.noneOf(Permission.class); | |
| 132 | |
| 133 // Add permissions specifically given to the user | |
| 134 permissions.addAll( permissionsForSingleRoleAssignee(ra,d) ); | |
| 135 Set<Group> groupsRaBelongsTo = groupService.groupsFor(ra,d); | |
| 136 // Add permissions gained from groups | |
| 137 for ( Group g : groupsRaBelongsTo ) { | |
| 138 permissions.addAll( permissionsForSingleRoleAssignee(g,d) ); | |
| 139 } | |
| 140 | |
| 141 return permissions; | |
| 142 } | |
| 143 | |
| 144 public Set<Permission> permissionsForSingleRoleAssignee(RoleAssignee ra, DvObject d) { | |
| 145 // super user check | |
| 146 // @todo for 4.0, we are allowing superusers all permissions | |
| 147 // for secure data, we may need to restrict some of the permissions | |
| 148 if (ra instanceof AuthenticatedUser && ((AuthenticatedUser) ra).isSuperuser()) { | |
| 149 return EnumSet.allOf(Permission.class); | |
| 150 } | |
| 151 | |
| 152 Set<Permission> retVal = EnumSet.noneOf(Permission.class); | |
| 153 | |
| 154 if (d instanceof DataFile) { | |
| 155 // unrestricted files that are part of a release dataset | |
| 156 // automatically get download permission for everybody: | |
| 157 // -- L.A. 4.0 beta12 | |
| 158 | |
| 159 DataFile df = (DataFile)d; | |
| 160 | |
| 161 if (!df.isRestricted()) { | |
| 162 //logger.info("restricted? - nope."); | |
| 163 if (df.getOwner().getReleasedVersion() != null) { | |
| 164 //logger.info("file belongs to a dataset with a released version."); | |
| 165 if (df.getOwner().getReleasedVersion().getFileMetadatas() != null) { | |
| 166 //logger.info("going through the list of filemetadatas that belong to the released version."); | |
| 167 for (FileMetadata fm : df.getOwner().getReleasedVersion().getFileMetadatas()) { | |
| 168 if (df.equals(fm.getDataFile())) { | |
| 169 //logger.info("yep, found a match!"); | |
| 170 retVal.add(Permission.DownloadFile); | |
| 171 } | |
| 172 } | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 for (RoleAssignment asmnt : assignmentsFor(ra, d)) { | |
| 179 retVal.addAll(asmnt.getRole().permissions()); | |
| 180 } | |
| 181 | |
| 182 return retVal; | |
| 183 } | |
| 184 | |
| 185 /** | |
| 186 * Returns all the role assignments that are effective for {@code ra} over | |
| 187 * {@code d}. Traverses the containment hierarchy of the {@code d}. | |
| 188 * @param ra The role assignee whose role assignemnts we look for. | |
| 189 * @param d The dataverse object over which the roles are assigned | |
| 190 * @return A set of all the role assignments for {@code ra} over {@code d}. | |
| 191 */ | |
| 192 public Set<RoleAssignment> assignmentsFor(RoleAssignee ra, DvObject d) { | |
| 193 Set<RoleAssignment> assignments = new HashSet<>(); | |
| 194 while (d != null) { | |
| 195 assignments.addAll(roleService.directRoleAssignments(ra, d)); | |
| 196 if (d instanceof Dataverse && ((Dataverse) d).isEffectivelyPermissionRoot()) { | |
| 197 return assignments; | |
| 198 } else { | |
| 199 d = d.getOwner(); | |
| 200 } | |
| 201 } | |
| 202 | |
| 203 return assignments; | |
| 204 } | |
| 205 | |
| 206 /** | |
| 207 * For commands with no named dvObjects, this allows a quick check whether | |
| 208 * a user can issue the command on the dataverse or not. | |
| 209 * | |
| 210 * @param u | |
| 211 * @param commandClass | |
| 212 * @param dvo | |
| 213 * @return | |
| 214 * @deprecated As commands have dynamic permissions now, it is not enough to look at the static permissions anymore. | |
| 215 * @see #isUserAllowedOn(edu.harvard.iq.dataverse.authorization.RoleAssignee, edu.harvard.iq.dataverse.engine.command.Command, edu.harvard.iq.dataverse.DvObject) | |
| 216 */ | |
| 217 public boolean isUserAllowedOn(RoleAssignee u, Class<? extends Command> commandClass, DvObject dvo) { | |
| 218 Map<String, Set<Permission>> required = CH.permissionsRequired(commandClass); | |
| 219 return isUserAllowedOn(u, required, dvo); | |
| 220 } | |
| 221 | |
| 222 public boolean isUserAllowedOn(RoleAssignee u, Command<?> command, DvObject dvo) { | |
| 223 Map<String, Set<Permission>> required = command.getRequiredPermissions(); | |
| 224 return isUserAllowedOn(u, required, dvo); | |
| 225 } | |
| 226 | |
| 227 private boolean isUserAllowedOn(RoleAssignee u, Map<String, Set<Permission>> required, DvObject dvo) { | |
| 228 if (required.isEmpty() || required.get("") == null) { | |
| 229 logger.fine("IsUserAllowedOn: empty-true"); | |
| 230 return true; | |
| 231 } else { | |
| 232 Set<Permission> grantedUserPermissions = permissionsFor(u, dvo); | |
| 233 Set<Permission> requiredPermissionSet = required.get(""); | |
| 234 return grantedUserPermissions.containsAll(requiredPermissionSet); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 public PermissionQuery userOn(RoleAssignee u, DvObject d) { | |
| 239 if (u == null) { | |
| 240 // get guest user for dataverse d | |
| 241 u = new GuestUser(); | |
| 242 } | |
| 243 return new PermissionQuery(u, d); | |
| 244 } | |
| 245 | |
| 246 public PermissionQuery on(DvObject d) { | |
| 247 if (d == null) { | |
| 248 throw new IllegalArgumentException("Cannot query permissions on a null DvObject"); | |
| 249 } | |
| 250 if (d.getId() == null) { | |
| 251 throw new IllegalArgumentException("Cannot query permissions on a DvObject with a null id."); | |
| 252 } | |
| 253 return userOn(session.getUser(), d); | |
| 254 } | |
| 255 | |
| 256 /** | |
| 257 * Go from (User, Permission) to a list of Dataverse objects that the user | |
| 258 * has the permission on. | |
| 259 * | |
| 260 * @param user | |
| 261 * @param permission | |
| 262 * @return The list of dataverses {@code user} has permission {@code permission} on. | |
| 263 */ | |
| 264 public List<Dataverse> getDataversesUserHasPermissionOn(User user, Permission permission) { | |
| 265 /** | |
| 266 * @todo What about groups? And how can we make this more performant? | |
| 267 */ | |
| 268 Query nativeQuery = em.createNativeQuery("SELECT id FROM dvobject WHERE dtype = 'Dataverse' and id in (select definitionpoint_id from roleassignment where assigneeidentifier in ('" + user.getIdentifier() + "'));"); | |
| 269 List<Integer> dataverseIdsToCheck = nativeQuery.getResultList(); | |
| 270 List<Dataverse> dataversesUserHasPermissionOn = new LinkedList<>(); | |
| 271 for (int dvIdAsInt : dataverseIdsToCheck) { | |
| 272 Dataverse dataverse = dataverseService.find(Long.valueOf(dvIdAsInt)); | |
| 273 if (userOn(user, dataverse).has(permission)) { | |
| 274 dataversesUserHasPermissionOn.add(dataverse); | |
| 275 } | |
| 276 } | |
| 277 return dataversesUserHasPermissionOn; | |
| 278 } | |
| 279 | |
| 280 public List<AuthenticatedUser> getUsersWithPermissionOn(Permission permission, DvObject dvo) { | |
| 281 List<AuthenticatedUser> usersHasPermissionOn = new LinkedList<>(); | |
| 282 Set<RoleAssignment> ras = roleService.rolesAssignments(dvo); | |
| 283 for (RoleAssignment ra : ras) { | |
| 284 if (ra.getRole().permissions().contains(permission)) { | |
| 285 RoleAssignee raee = roleAssigneeService.getRoleAssignee(ra.getAssigneeIdentifier()); | |
| 286 usersHasPermissionOn.addAll(roleAssigneeService.getExplicitUsers(raee)); | |
| 287 } | |
| 288 } | |
| 289 | |
| 290 return usersHasPermissionOn; | |
| 291 } | |
| 292 | |
| 293 } |
