ref #6867 using runAsAuthentication ROLE_USERMANAGER to grant per entity authorities
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / service / 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.service;
10
11 import java.util.EnumSet;
12
13 import org.apache.log4j.Logger;
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.beans.factory.annotation.Qualifier;
16 import org.springframework.security.authentication.AnonymousAuthenticationToken;
17 import org.springframework.security.authentication.AuthenticationProvider;
18 import org.springframework.security.core.Authentication;
19 import org.springframework.security.core.context.SecurityContext;
20 import org.springframework.security.core.context.SecurityContextHolder;
21 import org.springframework.security.core.userdetails.UserDetails;
22 import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken;
23
24 import com.vaadin.spring.annotation.SpringComponent;
25 import com.vaadin.spring.annotation.UIScope;
26
27 import eu.etaxonomy.cdm.api.application.CdmRepository;
28 import eu.etaxonomy.cdm.api.application.RunAsAuthenticator;
29 import eu.etaxonomy.cdm.database.PermissionDeniedException;
30 import eu.etaxonomy.cdm.model.common.CdmBase;
31 import eu.etaxonomy.cdm.model.common.User;
32 import eu.etaxonomy.cdm.persistence.hibernate.permission.CRUD;
33 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthority;
34 import eu.etaxonomy.cdm.persistence.hibernate.permission.CdmAuthorityParsingException;
35 import eu.etaxonomy.cdm.persistence.hibernate.permission.ICdmPermissionEvaluator;
36 import eu.etaxonomy.cdm.persistence.hibernate.permission.Role;
37 import eu.etaxonomy.cdm.vaadin.security.RolesAndPermissions;
38 import eu.etaxonomy.cdm.vaadin.security.VaadinUserHelper;
39
40 /**
41 * @author a.kohlbecker
42 * @since May 19, 2017
43 *
44 */
45 @SpringComponent
46 @UIScope
47 public class CdmUserHelper extends VaadinUserHelper {
48
49 public static final Logger logger = Logger.getLogger(CdmUserHelper.class);
50
51 @Autowired
52 private ICdmPermissionEvaluator permissionEvaluator;
53
54 @Autowired
55 @Qualifier("cdmRepository")
56 private CdmRepository repo;
57
58 @Autowired
59 @Qualifier("runAsAuthenticationProvider")
60 AuthenticationProvider runAsAuthenticationProvider;
61
62 RunAsAuthenticator runAsAutheticator = new RunAsAuthenticator();
63
64 public CdmUserHelper(){
65 super();
66 runAsAutheticator.setRunAsAuthenticationProvider(runAsAuthenticationProvider);
67
68 }
69
70 @Override
71 public boolean userIsAutheticated() {
72 Authentication authentication = getAuthentication();
73 if(authentication != null){
74 return authentication.isAuthenticated();
75 }
76 return false;
77 }
78
79
80 @Override
81 public boolean userIsAnnonymous() {
82 Authentication authentication = getAuthentication();
83 return authentication != null
84 && authentication.isAuthenticated()
85 && authentication instanceof AnonymousAuthenticationToken;
86 }
87
88 @Override
89 public String userName() {
90 Authentication authentication = getAuthentication();
91 if(authentication != null) {
92 return authentication.getName();
93 }
94 return null;
95 }
96
97 @Override
98 public boolean userIsAdmin() {
99 Authentication authentication = getAuthentication();
100 if(authentication != null) {
101 return authentication.getAuthorities().stream().anyMatch(a -> {
102 return a.getAuthority().equals(Role.ROLE_ADMIN.getAuthority());
103 });
104 }
105 return false;
106 }
107
108 @Override
109 public boolean userIsRegistrationCurator() {
110 Authentication authentication = getAuthentication();
111 if(authentication != null) {
112 return authentication.getAuthorities().stream().anyMatch(a -> {
113 return a.equals(RolesAndPermissions.ROLE_CURATION)
114 // doing faster regex check here instreas of using CdmAuthoritiy.fromString()
115 || a.getAuthority().matches("^Registration\\.\\[.*UPDATE");
116 });
117 }
118 return false;
119 }
120
121 @Override
122 public boolean userHasPermission(CdmBase entity, Object ... args){
123 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
124 try {
125 return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
126 } catch (PermissionDeniedException e){
127 //IGNORE
128 }
129 return false;
130 }
131
132 @Override
133 public boolean userHasPermission(Class<? extends CdmBase> cdmType, Integer entitiyId, Object ... args){
134 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
135 try {
136 CdmBase entity = repo.getCommonService().find(cdmType, entitiyId);
137 return permissionEvaluator.hasPermission(getAuthentication(), entity, crudSet);
138 } catch (PermissionDeniedException e){
139 //IGNORE
140 }
141 return false;
142 }
143
144 @Override
145 public boolean userHasPermission(Class<? extends CdmBase> cdmType, Object ... args){
146 EnumSet<CRUD> crudSet = crudSetFromArgs(args);
147 try {
148 return permissionEvaluator.hasPermission(getAuthentication(), cdmType, crudSet);
149 } catch (PermissionDeniedException e){
150 //IGNORE
151 }
152 return false;
153 }
154
155 public void logout() {
156 SecurityContext context = SecurityContextHolder.getContext();
157 context.setAuthentication(null);
158 SecurityContextHolder.clearContext();
159 }
160
161
162 private EnumSet<CRUD> crudSetFromArgs(Object[] args) {
163 EnumSet<CRUD> crudSet = EnumSet.noneOf(CRUD.class);
164 for(int i = 0; i < args.length; i++){
165 try {
166 crudSet.add(CRUD.valueOf(args[i].toString()));
167 } catch (Exception e){
168 throw new IllegalArgumentException("could not add " + args[i], e);
169 }
170 }
171 return crudSet;
172 }
173
174
175 /**
176 * @return
177 *
178 * FIXME is it ok to use the SecurityContextHolder or do we need to hold the context in the vaadin session?
179 */
180 private SecurityContext currentSecurityContext() {
181 return SecurityContextHolder.getContext();
182 }
183
184 /**
185 * @return
186 */
187 private Authentication getAuthentication() {
188 return currentSecurityContext().getAuthentication();
189 }
190
191 /**
192 * {@inheritDoc}
193 */
194 @Override
195 public void createAuthorityFor(String username, CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
196 UserDetails userDetails = repo.getUserService().loadUserByUsername(username);
197 if(userDetails != null){
198 runAsAutheticator.runAsAuthentication(Role.ROLE_USER_MANAGER);
199 User user = (User)userDetails;
200 CdmAuthority authority = new CdmAuthority(cdmEntity, property, crud);
201 try {
202 user.getGrantedAuthorities().add(authority.asNewGrantedAuthority());
203 } catch (CdmAuthorityParsingException e) {
204 throw new RuntimeException(e);
205 }
206 repo.getSession().flush();
207 runAsAutheticator.restoreAuthentication();
208 logger.debug("new authority for " + username + ": " + authority.toString());
209 Authentication authentication = new PreAuthenticatedAuthenticationToken(user, user.getPassword(), user.getAuthorities());
210 SecurityContextHolder.getContext().setAuthentication(authentication);
211 logger.debug("security context refreshed with user " + username);
212 }
213
214 }
215
216 /**
217 * @param username
218 * @param cdmType
219 * @param entitiyId
220 * @param crud
221 * @return
222 */
223 @Override
224 public void createAuthorityFor(String username, Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
225
226 CdmBase cdmEntity = repo.getCommonService().find(cdmType, entitiyId);
227
228 createAuthorityFor(username,cdmEntity, crud, property);
229 }
230
231 /**
232 * {@inheritDoc}
233 */
234 @Override
235 public void createAuthorityForCurrentUser(CdmBase cdmEntity, EnumSet<CRUD> crud, String property) {
236 createAuthorityFor(userName(), cdmEntity, crud, property);
237
238 }
239
240 /**
241 * @param cdmType
242 * @param entitiyId
243 * @param crud
244 * @return
245 */
246 @Override
247 public void createAuthorityForCurrentUser(Class<? extends CdmBase> cdmType, Integer entitiyId, EnumSet<CRUD> crud, String property) {
248 createAuthorityFor(userName(), cdmType, entitiyId, crud, property);
249 }
250
251 }