44import com .cosium .spring .data .jpa .entity .graph .domain .EntityGraphUtils ;
55import org .apache .shiro .authz .UnauthorizedException ;
66import org .ohdsi .webapi .model .CommonEntity ;
7- import org .ohdsi .webapi .security .dto .RoleDTO ;
87import org .ohdsi .webapi .security .model .EntityPermissionSchema ;
98import org .ohdsi .webapi .security .model .EntityPermissionSchemaResolver ;
109import org .ohdsi .webapi .security .model .EntityType ;
3433import javax .annotation .PostConstruct ;
3534import java .io .Serializable ;
3635import java .util .Arrays ;
37- import java .util .Collection ;
38- import java .util .HashMap ;
39- import java .util .HashSet ;
4036import java .util .List ;
4137import java .util .Map ;
4238import java .util .Objects ;
4339import java .util .Set ;
44- import java .util .concurrent .ConcurrentHashMap ;
45- import java .util .function .Function ;
4640import java .util .stream .Collectors ;
41+ import org .apache .shiro .SecurityUtils ;
42+ import org .apache .shiro .authz .Permission ;
43+ import org .apache .shiro .authz .permission .WildcardPermission ;
44+ import org .apache .shiro .subject .Subject ;
4745
4846@ Service
4947public class PermissionService {
@@ -64,9 +62,6 @@ public class PermissionService {
6462 @ Value ("#{!'${security.provider}'.equals('DisabledSecurity')}" )
6563 private boolean securityEnabled ;
6664
67- private ThreadLocal <ConcurrentHashMap <EntityType , ConcurrentHashMap <String , Set <RoleDTO >>>> permissionCache =
68- ThreadLocal .withInitial (ConcurrentHashMap ::new );
69-
7065 private final EntityGraph PERMISSION_ENTITY_GRAPH = EntityGraphUtils .fromAttributePaths ("rolePermissions" , "rolePermissions.role" );
7166
7267 public PermissionService (
@@ -133,14 +128,14 @@ public void checkCommonEntityOwnership(EntityType entityType, Integer entityId)
133128
134129 public Map <String , String > getPermissionTemplates (EntityPermissionSchema permissionSchema , AccessType accessType ) {
135130
136- switch (accessType ) {
137- case WRITE :
138- return permissionSchema .getWritePermissions ();
139- case READ :
140- return permissionSchema .getReadPermissions ();
141- default :
142- throw new UnsupportedOperationException ();
143- }
131+ switch (accessType ) {
132+ case WRITE :
133+ return permissionSchema .getWritePermissions ();
134+ case READ :
135+ return permissionSchema .getReadPermissions ();
136+ default :
137+ throw new UnsupportedOperationException ();
138+ }
144139 }
145140
146141 public List <RoleEntity > finaAllRolesHavingPermissions (List <String > permissions ) {
@@ -178,97 +173,28 @@ private boolean isCurrentUserOwnerOf(CommonEntity entity) {
178173 return Objects .equals (owner .getLogin (), loggedInUsername );
179174 }
180175
176+ public List <Permission > getEntityPermissions (EntityType entityType , Number id , AccessType accessType ) {
177+ Set <String > permissionTemplates = getTemplatesForType (entityType , accessType ).keySet ();
181178
182- public void preparePermissionCache (EntityType entityType , Set <String > permissionTemplates ) {
183- if (permissionCache .get ().get (entityType ) == null ) {
184- final ConcurrentHashMap <String , Set <RoleDTO >> rolesForEntity = new ConcurrentHashMap <>();
185- permissionCache .get ().put (entityType , rolesForEntity );
186-
187- List <String > permissionsSQLTemplates = permissionTemplates .stream ()
188- .map (pt -> getPermissionSqlTemplate (pt ))
189- .collect (Collectors .toList ());
190-
191- Map <Long , RoleDTO > roleDTOMap = new HashMap <>();
192- permissionsSQLTemplates .forEach (p -> {
193- Iterable <PermissionEntity > permissionEntities = permissionRepository .findByValueLike (p , PERMISSION_ENTITY_GRAPH );
194- for (PermissionEntity permissionEntity : permissionEntities ) {
195- Set <RoleDTO > roles = rolesForEntity .get (permissionEntity .getValue ());
196- if (roles == null ) {
197- rolesForEntity .put (permissionEntity .getValue (), new HashSet <>());
198- }
199- Set <RoleDTO > cachedRoles = rolesForEntity .get (permissionEntity .getValue ());
200- permissionEntity .getRolePermissions ().forEach (rp -> {
201- RoleDTO roleDTO = roleDTOMap .get (rp .getRole ().getId ());
202- if (roleDTO == null ) {
203- roleDTO = conversionService .convert (rp .getRole (), RoleDTO .class );
204- roleDTOMap .put (roleDTO .getId (), roleDTO );
205- }
206- cachedRoles .add (roleDTO );
207- });
208- }
209- });
210- }
211- }
212-
213- public List <RoleDTO > getRolesHavingPermissions (EntityType entityType , Number id ) {
214- Set <String > permissionTemplates = getTemplatesForType (entityType , AccessType .WRITE ).keySet ();
215- preparePermissionCache (entityType , permissionTemplates );
216-
217- List <String > permissions = permissionTemplates .stream ()
218- .map (pt -> getPermission (pt , id ))
179+ List <Permission > permissions = permissionTemplates .stream ()
180+ .map (pt -> new WildcardPermission (getPermission (pt , id )))
219181 .collect (Collectors .toList ());
220- int fitCount = permissions .size ();
221- Map <RoleDTO , Long > roleMap = permissions .stream ()
222- .filter (p -> permissionCache .get ().get (entityType ).get (p ) != null )
223- .flatMap (p -> permissionCache .get ().get (entityType ).get (p ).stream ())
224- .collect (Collectors .groupingBy (Function .identity (), Collectors .counting ()));
225- List <RoleDTO > roles = roleMap .entrySet ().stream ()
226- .filter (es -> es .getValue () == fitCount )
227- .map (es -> es .getKey ())
228- .collect (Collectors .toList ());
229- return roles ;
230- }
231-
232- public List <RoleDTO > getRolesHavingReadPermissions (EntityType entityType , Number id ) {
233- Set <String > permissionTemplates = getTemplatesForType (entityType , AccessType .READ ).keySet ();
234- preparePermissionCache (entityType , permissionTemplates );
235-
236- List <String > permissions = permissionTemplates .stream ()
237- .map (pt -> getPermission (pt , id ))
238- .collect (Collectors .toList ());
239- int fitCount = permissions .size ();
240- Map <RoleDTO , Long > roleMap = permissions .stream ()
241- .filter (p -> permissionCache .get ().get (entityType ).get (p ) != null )
242- .flatMap (p -> permissionCache .get ().get (entityType ).get (p ).stream ())
243- .collect (Collectors .groupingBy (Function .identity (), Collectors .counting ()));
244- List <RoleDTO > roles = roleMap .entrySet ().stream ()
245- .filter (es -> es .getValue () == fitCount )
246- .map (es -> es .getKey ())
247- .collect (Collectors .toList ());
248- return roles ;
249- }
250-
251- public void clearPermissionCache () {
252- this .permissionCache .set (new ConcurrentHashMap <>());
182+ return permissions ;
253183 }
254184
255- public boolean hasWriteAccess (CommonEntity entity ) {
185+ public boolean hasAccess (CommonEntity entity , AccessType accessType ) {
256186 boolean hasAccess = false ;
257187 if (securityEnabled && entity .getCreatedBy () != null ) {
258188 try {
189+ Subject subject = SecurityUtils .getSubject ();
259190 String login = this .permissionManager .getSubjectName ();
260191 UserSimpleAuthorizationInfo authorizationInfo = this .permissionManager .getAuthorizationInfo (login );
261192 if (Objects .equals (authorizationInfo .getUserId (), entity .getCreatedBy ().getId ())) {
262193 hasAccess = true ; // the role is the one that created the artifact
263194 } else {
264195 EntityType entityType = entityPermissionSchemaResolver .getEntityType (entity .getClass ());
265-
266- List <RoleDTO > roles = getRolesHavingPermissions (entityType , entity .getId ());
267-
268- Collection <String > userRoles = authorizationInfo .getRoles ();
269- hasAccess = roles .stream ()
270- .anyMatch (r -> userRoles .stream ()
271- .anyMatch (re -> re .equals (r .getName ())));
196+ List <Permission > permsToCheck = getEntityPermissions (entityType , entity .getId (), accessType );
197+ hasAccess = permsToCheck .stream ().allMatch (p -> subject .isPermitted (p ));
272198 }
273199 } catch (Exception e ) {
274200 logger .error ("Error getting user roles and permissions" , e );
@@ -277,43 +203,24 @@ public boolean hasWriteAccess(CommonEntity entity) {
277203 }
278204 return hasAccess ;
279205 }
280-
206+
207+ public boolean hasWriteAccess (CommonEntity entity ) {
208+ return hasAccess (entity , AccessType .WRITE );
209+ }
281210
282211 public boolean hasReadAccess (CommonEntity entity ) {
283- boolean hasAccess = false ;
284- if (securityEnabled && entity .getCreatedBy () != null ) {
285- try {
286- String login = this .permissionManager .getSubjectName ();
287- UserSimpleAuthorizationInfo authorizationInfo = this .permissionManager .getAuthorizationInfo (login );
288- if (Objects .equals (authorizationInfo .getUserId (), entity .getCreatedBy ().getId ())){
289- hasAccess = true ; // the role is the one that created the artifact
290- } else {
291- EntityType entityType = entityPermissionSchemaResolver .getEntityType (entity .getClass ());
292-
293- List <RoleDTO > roles = getRolesHavingReadPermissions (entityType , entity .getId ());
294-
295- Collection <String > userRoles = authorizationInfo .getRoles ();
296- hasAccess = roles .stream ()
297- .anyMatch (r -> userRoles .stream ()
298- .anyMatch (re -> re .equals (r .getName ())));
299- }
300- } catch (Exception e ) {
301- logger .error ("Error getting user roles and permissions" , e );
302- throw new RuntimeException (e );
303- }
304- }
305- return hasAccess ;
212+ return hasAccess (entity , AccessType .READ );
306213 }
307214
308215 public void fillWriteAccess (CommonEntity entity , CommonEntityDTO entityDTO ) {
309216 if (securityEnabled && entity .getCreatedBy () != null ) {
310- entityDTO .setHasWriteAccess (hasWriteAccess (entity ));
217+ entityDTO .setHasWriteAccess (hasAccess (entity , AccessType . WRITE ));
311218 }
312219 }
313220
314221 public void fillReadAccess (CommonEntity entity , CommonEntityDTO entityDTO ) {
315222 if (securityEnabled && entity .getCreatedBy () != null ) {
316- entityDTO .setHasReadAccess (hasReadAccess (entity ));
223+ entityDTO .setHasReadAccess (hasAccess (entity , AccessType . READ ));
317224 }
318225 }
319226
0 commit comments