2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
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.
9 package eu
.etaxonomy
.cdm
.api
.utility
;
11 import java
.io
.Serializable
;
12 import java
.util
.Collection
;
13 import java
.util
.EnumSet
;
14 import java
.util
.HashSet
;
16 import java
.util
.UUID
;
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
;
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
;
46 * @author a.kohlbecker
50 public class CdmUserHelper
implements UserHelper
, Serializable
{
52 private static final long serialVersionUID
= -2521474709047255979L;
54 public static final Logger logger
= Logger
.getLogger(CdmUserHelper
.class);
57 private ICdmPermissionEvaluator permissionEvaluator
;
61 @Qualifier("cdmRepository")
62 private CdmRepository repo
;
64 AuthenticationProvider runAsAuthenticationProvider
;
66 @Autowired(required
=false)
67 @Qualifier("runAsAuthenticationProvider")
68 public void setRunAsAuthenticationProvider(AuthenticationProvider runAsAuthenticationProvider
){
69 this.runAsAuthenticationProvider
= runAsAuthenticationProvider
;
70 runAsAutheticator
.setRunAsAuthenticationProvider(runAsAuthenticationProvider
);
73 RunAsAuthenticator runAsAutheticator
= new RunAsAuthenticator();
75 private SecurityContextAccess securityContextAccess
;
77 public CdmUserHelper(){
82 public boolean userIsAutheticated() {
83 Authentication authentication
= getAuthentication();
84 if(authentication
!= null){
85 return authentication
.isAuthenticated();
92 public boolean userIsAnnonymous() {
93 Authentication authentication
= getAuthentication();
94 return authentication
!= null
95 && authentication
.isAuthenticated()
96 && authentication
instanceof AnonymousAuthenticationToken
;
101 Authentication authentication
= getAuthentication();
102 if(authentication
!= null && authentication
.getPrincipal() != null) {
103 return (User
) authentication
.getPrincipal();
109 public String
userName() {
110 Authentication authentication
= getAuthentication();
111 if(authentication
!= null) {
112 return authentication
.getName();
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());
132 public boolean userIs(RoleProbe roleProbe
) {
133 return roleProbe
.checkForRole(getAuthentication());
137 public boolean userHasPermission(CdmBase entity
, Object
... args
){
138 EnumSet
<CRUD
> crudSet
= crudSetFromArgs(args
);
140 return permissionEvaluator
.hasPermission(getAuthentication(), entity
, crudSet
);
141 } catch (PermissionDeniedException e
){
148 public boolean userHasPermission(Class
<?
extends CdmBase
> cdmType
, Integer entitiyId
, Object
... args
){
149 EnumSet
<CRUD
> crudSet
= crudSetFromArgs(args
);
151 CdmBase entity
= repo
.getCommonService().find(cdmType
, entitiyId
);
152 return permissionEvaluator
.hasPermission(getAuthentication(), entity
, crudSet
);
153 } catch (PermissionDeniedException e
){
160 public boolean userHasPermission(Class
<?
extends CdmBase
> cdmType
, UUID entitiyUuid
, Object
... args
){
161 EnumSet
<CRUD
> crudSet
= crudSetFromArgs(args
);
163 CdmBase entity
= repo
.getCommonService().find(cdmType
, entitiyUuid
);
164 return permissionEvaluator
.hasPermission(getAuthentication(), entity
, crudSet
);
165 } catch (PermissionDeniedException e
){
172 public boolean userHasPermission(Class
<?
extends CdmBase
> cdmType
, Object
... args
){
173 EnumSet
<CRUD
> crudSet
= crudSetFromArgs(args
);
175 return permissionEvaluator
.hasPermission(getAuthentication(), cdmType
, crudSet
);
176 } catch (PermissionDeniedException e
){
183 public void logout() {
184 SecurityContext context
= SecurityContextHolder
.getContext();
185 context
.setAuthentication(null);
186 SecurityContextHolder
.clearContext();
190 private EnumSet
<CRUD
> crudSetFromArgs(Object
[] args
) {
191 EnumSet
<CRUD
> crudSet
= EnumSet
.noneOf(CRUD
.class);
192 for(int i
= 0; i
< args
.length
; i
++){
194 crudSet
.add(CRUD
.valueOf(args
[i
].toString()));
195 } catch (Exception e
){
196 throw new IllegalArgumentException("could not add " + args
[i
], e
);
203 private SecurityContext
currentSecurityContext() {
204 if(securityContextAccess
!= null){
205 return securityContextAccess
.currentSecurityContext();
207 return SecurityContextHolder
.getContext();
214 public Authentication
getAuthentication() {
215 return currentSecurityContext().getAuthentication();
223 public CdmAuthority
createAuthorityFor(String username
, CdmBase cdmEntity
, EnumSet
<CRUD
> crud
, String property
) {
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){
232 getRunAsAutheticator().runAsAuthentication(Role
.ROLE_USER_MANAGER
);
233 authority
= new CdmAuthority(cdmEntity
, property
, crud
);
235 GrantedAuthorityImpl grantedAuthority
= repo
.getGrantedAuthorityService().findAuthorityString(authority
.toString());
236 if(grantedAuthority
== null){
237 grantedAuthority
= authority
.asNewGrantedAuthority();
239 newAuthorityAdded
= user
.getGrantedAuthorities().add(grantedAuthority
);
240 } catch (CdmAuthorityParsingException e
) {
241 throw new RuntimeException(e
);
243 repo
.getSession().flush();
245 // in any case restore the previous authentication
246 getRunAsAutheticator().restoreAuthentication();
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
);
253 repo
.commitTransaction(txStatus
);
254 return newAuthorityAdded ? authority
: null;
266 public CdmAuthority
createAuthorityFor(String username
, Class
<?
extends CdmBase
> cdmType
, Integer entitiyId
, EnumSet
<CRUD
> crud
, String property
) {
268 CdmBase cdmEntity
= repo
.getCommonService().find(cdmType
, entitiyId
);
269 return createAuthorityFor(username
, cdmEntity
, crud
, property
);
280 public CdmAuthority
createAuthorityFor(String username
, Class
<?
extends CdmBase
> cdmType
, UUID entitiyUuid
, EnumSet
<CRUD
> crud
, String property
) {
282 CdmBase cdmEntity
= repo
.getCommonService().find(cdmType
, entitiyUuid
);
283 return createAuthorityFor(username
, cdmEntity
, crud
, property
);
290 public CdmAuthority
createAuthorityForCurrentUser(CdmBase cdmEntity
, EnumSet
<CRUD
> crud
, String property
) {
291 return createAuthorityFor(userName(), cdmEntity
, crud
, property
);
302 public CdmAuthority
createAuthorityForCurrentUser(Class
<?
extends CdmBase
> cdmType
, Integer entitiyId
, EnumSet
<CRUD
> crud
, String property
) {
303 return createAuthorityFor(userName(), cdmType
, entitiyId
, crud
, property
);
313 public CdmAuthority
createAuthorityForCurrentUser(Class
<?
extends CdmBase
> cdmType
, UUID entitiyUuid
, EnumSet
<CRUD
> crud
, String property
) {
314 return createAuthorityFor(userName(), cdmType
, entitiyUuid
, crud
, property
);
321 public void removeAuthorityForCurrentUser(CdmAuthority cdmAuthority
) {
322 removeAuthorityForCurrentUser(userName(), cdmAuthority
);
330 public void removeAuthorityForCurrentUser(String username
, CdmAuthority cdmAuthority
) {
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
);
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
){
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
);
362 matches
.add(cdmAuthority
);
366 } catch (CdmAuthorityParsingException e
) {
374 * @param securityContextAccess the securityContextAccess to set
377 public void setSecurityContextAccess(SecurityContextAccess securityContextAccess
) {
378 this.securityContextAccess
= securityContextAccess
;
382 * @return the runAsAutheticator
384 public RunAsAuthenticator
getRunAsAutheticator() {
385 if(runAsAutheticator
== null){
386 throw new RuntimeException("RunAsAuthenticator is missing! The application needs to be configured with security context.");
388 return runAsAutheticator
;