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 }