ref #7597 Use LongRunningTaskService for taxon aggregation
[cdmlib.git] / cdmlib-services / src / main / java / eu / etaxonomy / cdm / api / utility / CdmUserHelper.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.api.utility;
10
11 import java.io.Serializable;
12 import java.util.Collection;
13 import java.util.EnumSet;
14 import java.util.HashSet;
15 import java.util.Set;
16 import java.util.UUID;
17
18 import org.apache.log4j.Logger;
19 import org.springframework.beans.factory.annotation.Autowired;
20 import org.springframework.beans.factory.annotation.Qualifier;
21 import org.springframework.context.annotation.Lazy;
22 import org.springframework.security.authentication.AnonymousAuthenticationToken;
23 import org.springframework.security.authentication.AuthenticationProvider;
24 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
25 import org.springframework.security.core.Authentication;
26 import org.springframework.security.core.GrantedAuthority;
27 import org.springframework.security.core.context.SecurityContext;
28 import org.springframework.security.core.context.SecurityContextHolder;
29 import org.springframework.security.core.userdetails.UserDetails;
30 import org.springframework.transaction.TransactionStatus;
31
32 import eu.etaxonomy.cdm.api.application.CdmRepository;
33 import eu.etaxonomy.cdm.api.application.RunAsAuthenticator;
34 import eu.etaxonomy.cdm.database.PermissionDeniedException;
35 import eu.etaxonomy.cdm.model.common.CdmBase;
36 import eu.etaxonomy.cdm.model.common.GrantedAuthorityImpl;
37 import eu.etaxonomy.cdm.model.common.User;
38 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
39 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
40 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthorityParsingException;
41 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmPermissionClass;
42 import eu.etaxonomy.cdm.persistence.hibernate.permission.ICdmPermissionEvaluator;
43 import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
44
45 /**
46 * @author a.kohlbecker
47 * @since May 19, 2017
48 *
49 */
50 public class CdmUserHelper implements UserHelper, Serializable {
51
52 private static final long serialVersionUID = -2521474709047255979L;
53
54 public static final Logger logger = Logger.getLogger(CdmUserHelper.class);
55
56 @Autowired
57 private ICdmPermissionEvaluator permissionEvaluator;
58
59 @Autowired
60 @Lazy
61 @Qualifier("cdmRepository")
62 private CdmRepository repo;
63
64 AuthenticationProvider runAsAuthenticationProvider;
65
66 @Autowired(required=false)
67 @Qualifier("runAsAuthenticationProvider")
68 public void setRunAsAuthenticationProvider(AuthenticationProvider runAsAuthenticationProvider){
69 this.runAsAuthenticationProvider = runAsAuthenticationProvider;
70 runAsAutheticator.setRunAsAuthenticationProvider(runAsAuthenticationProvider);
71 }
72
73 RunAsAuthenticator runAsAutheticator = new RunAsAuthenticator();
74
75 private SecurityContextAccess securityContextAccess;
76
77 public CdmUserHelper(){
78 super();
79 }
80
81 @Override
82 public boolean userIsAutheticated() {
83 Authentication authentication = getAuthentication();
84 if(authentication != null){
85 return authentication.isAuthenticated();
86 }
87 return false;
88 }
89
90
91 @Override
92 public boolean userIsAnnonymous() {
93 Authentication authentication = getAuthentication();
94 return authentication != null
95 && authentication.isAuthenticated()
96 && authentication instanceof AnonymousAuthenticationToken;
97 }
98
99 @Override
100 public User user() {
101 Authentication authentication = getAuthentication();
102 if(authentication != null && authentication.getPrincipal() != null) {
103 return (User) authentication.getPrincipal();
104 }
105 return null;
106 }
107
108 @Override
109 public String userName() {
110 Authentication authentication = getAuthentication();
111 if(authentication != null) {
112 return authentication.getName();
113 }
114 return null;
115 }
116
117 @Override
118 public boolean userIsAdmin() {
119 Authentication authentication = getAuthentication();
120 if(authentication != null) {
121 return authentication.getAuthorities().stream().anyMatch(a -> {
122 return a.getAuthority().equals(Role.ROLE_ADMIN.getAuthority());
123 });
124 }
125 return false;
126 }
127
128 /**
129 * {@inheritDoc}
130 */
131 @Override
132 public boolean userIs(RoleProbe roleProbe) {
133 return roleProbe.checkForRole(getAuthentication());
134 }
135
136 @Override
137 public boolean userHasPermission(CdmBase entity, Object ... args){
138 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
139 try {
140 return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
141 } catch (PermissionDeniedException e){
142 //IGNORE
143 }
144 return false;
145 }
146
147 @Override
148 public boolean userHasPermission(Class<? extends CdmBase> cdmType, Integer entitiyId, Object ... args){
149 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
150 try {
151 CdmBase entity = repo.getCommonService().find(cdmType, entitiyId);
152 return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
153 } catch (PermissionDeniedException e){
154 //IGNORE
155 }
156 return false;
157 }
158
159 @Override
160 public boolean userHasPermission(Class<? extends CdmBase> cdmType, UUID entitiyUuid, Object ... args){
161 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
162 try {
163 CdmBase entity = repo.getCommonService().find(cdmType, entitiyUuid);
164 return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
165 } catch (PermissionDeniedException e){
166 //IGNORE
167 }
168 return false;
169 }
170
171 @Override
172 public boolean userHasPermission(Class<? extends CdmBase> cdmType, Object ... args){
173 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
174 try {
175 return permissionEvaluator.hasPermission(getAuthentication(), cdmType, crudSet);
176 } catch (PermissionDeniedException e){
177 //IGNORE
178 }
179 return false;
180 }
181
182 @Override
183 public void logout() {
184 SecurityContext context = SecurityContextHolder.getContext();
185 context.setAuthentication(null);
186 SecurityContextHolder.clearContext();
187 }
188
189
190 private EnumSet<CRUD> crudSetFromArgs(Object[] args) {
191 EnumSet<CRUD> crudSet = EnumSet.noneOf(CRUD.class);
192 for(int i = 0; i < args.length; i++){
193 try {
194 crudSet.add(CRUD.valueOf(args[i].toString()));
195 } catch (Exception e){
196 throw new IllegalArgumentException("could not add " + args[i], e);
197 }
198 }
199 return crudSet;
200 }
201
202
203 private SecurityContext currentSecurityContext() {
204 if(securityContextAccess != null){
205 return securityContextAccess.currentSecurityContext();
206 }
207 return SecurityContextHolder.getContext();
208 }
209
210 /**
211 * @return
212 */
213 @Override
214 public Authentication getAuthentication() {
215 return currentSecurityContext().getAuthentication();
216 }
217
218 /**
219 * {@inheritDoc}
220 *
221 */
222 @Override
223 public CdmAuthority createAuthorityFor(String username, CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
224
225 TransactionStatus txStatus = repo.startTransaction();
226 UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
227 boolean newAuthorityAdded = false;
228 CdmAuthority authority = null;
229 User user = (User)userDetails;
230 if(userDetails != null){
231 try{
232 getRunAsAutheticator().runAsAuthentication(Role.ROLE_USER_MANAGER);
233 authority = new CdmAuthority(cdmEntity, property, crud);
234 try {
235 GrantedAuthorityImpl grantedAuthority = repo.getGrantedAuthorityService().findAuthorityString(authority.toString());
236 if(grantedAuthority == null){
237 grantedAuthority = authority.asNewGrantedAuthority();
238 }
239 newAuthorityAdded = user.getGrantedAuthorities().add(grantedAuthority);
240 } catch (CdmAuthorityParsingException e) {
241 throw new RuntimeException(e);
242 }
243 repo.getSession().flush();
244 } finally {
245 // in any case restore the previous authentication
246 getRunAsAutheticator().restoreAuthentication();
247 }
248 logger.debug("new authority for " + username + ": " + authority.toString());
249 Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
250 SecurityContextHolder.getContext().setAuthentication(authentication);
251 logger.debug("security context refreshed with user " + username);
252 }
253 repo.commitTransaction(txStatus);
254 return newAuthorityAdded ? authority : null;
255
256 }
257
258 /**
259 * @param username
260 * @param cdmType
261 * @param entitiyId
262 * @param crud
263 * @return
264 */
265 @Override
266 public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
267
268 CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyId);
269 return createAuthorityFor(username, cdmEntity, crud, property);
270 }
271
272 /**
273 * @param username
274 * @param cdmType
275 * @param entitiyUuid
276 * @param crud
277 * @return
278 */
279 @Override
280 public CdmAuthority createAuthorityFor(String username, Class<? extends CdmBase> cdmType, UUID entitiyUuid, EnumSet<CRUD> crud, String property) {
281
282 CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyUuid);
283 return createAuthorityFor(username, cdmEntity, crud, property);
284 }
285
286 /**
287 * {@inheritDoc}
288 */
289 @Override
290 public CdmAuthority createAuthorityForCurrentUser(CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
291 return createAuthorityFor(userName(), cdmEntity, crud, property);
292
293 }
294
295 /**
296 * @param cdmType
297 * @param entitiyId
298 * @param crud
299 * @return
300 */
301 @Override
302 public CdmAuthority createAuthorityForCurrentUser(Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
303 return createAuthorityFor(userName(), cdmType, entitiyId, crud, property);
304 }
305
306 /**
307 * @param cdmType
308 * @param entitiyUuid
309 * @param crud
310 * @return
311 */
312 @Override
313 public CdmAuthority createAuthorityForCurrentUser(Class<? extends CdmBase> cdmType, UUID entitiyUuid, EnumSet<CRUD> crud, String property) {
314 return createAuthorityFor(userName(), cdmType, entitiyUuid, crud, property);
315 }
316
317 /**
318 * {@inheritDoc}
319 */
320 @Override
321 public void removeAuthorityForCurrentUser(CdmAuthority cdmAuthority) {
322 removeAuthorityForCurrentUser(userName(), cdmAuthority);
323
324 }
325
326 /**
327 * {@inheritDoc}
328 */
329 @Override
330 public void removeAuthorityForCurrentUser(String username, CdmAuthority cdmAuthority) {
331
332 UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
333 if(userDetails != null){
334 getRunAsAutheticator().runAsAuthentication(Role.ROLE_USER_MANAGER);
335 User user = (User)userDetails;
336 user.getGrantedAuthorities().remove(cdmAuthority);
337 repo.getSession().flush();
338 getRunAsAutheticator().restoreAuthentication();
339 Authentication authentication = new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
340 SecurityContextHolder.getContext().setAuthentication(authentication);
341 logger.debug("security context refreshed with user " + username);
342 }
343
344 }
345
346 /**
347 * {@inheritDoc}
348 */
349 @Override
350 public Collection<CdmAuthority> findUserPermissions(CdmBase cdmEntity, EnumSet<CRUD> crud) {
351 Set<CdmAuthority> matches = new HashSet<>();
352 CdmPermissionClass permissionClass = CdmPermissionClass.getValueOf(cdmEntity);
353 Collection<? extends GrantedAuthority> authorities = getAuthentication().getAuthorities();
354 for(GrantedAuthority ga : authorities){
355 try {
356 CdmAuthority cdmAuthority = CdmAuthority.fromGrantedAuthority(ga);
357 if(cdmAuthority.getPermissionClass().equals(permissionClass)){
358 if(cdmAuthority.getOperation().containsAll(crud)){
359 if(cdmAuthority.hasTargetUuid() && cdmAuthority.getTargetUUID().equals(cdmEntity.getUuid())){
360 matches.add(cdmAuthority);
361 } else {
362 matches.add(cdmAuthority);
363 }
364 }
365 }
366 } catch (CdmAuthorityParsingException e) {
367 continue;
368 }
369 }
370 return matches;
371 }
372
373 /**
374 * @param securityContextAccess the securityContextAccess to set
375 */
376 @Override
377 public void setSecurityContextAccess(SecurityContextAccess securityContextAccess) {
378 this.securityContextAccess = securityContextAccess;
379 }
380
381 /**
382 * @return the runAsAutheticator
383 */
384 public RunAsAuthenticator getRunAsAutheticator() {
385 if(runAsAutheticator == null){
386 throw new RuntimeException("RunAsAuthenticator is missing! The application needs to be configured with security context.");
387 }
388 return runAsAutheticator;
389 }
390
391 }