4
4
import com .cosium .spring .data .jpa .entity .graph .domain .EntityGraphUtils ;
5
5
import org .apache .shiro .authz .UnauthorizedException ;
6
6
import org .ohdsi .webapi .model .CommonEntity ;
7
- import org .ohdsi .webapi .security .dto .RoleDTO ;
8
7
import org .ohdsi .webapi .security .model .EntityPermissionSchema ;
9
8
import org .ohdsi .webapi .security .model .EntityPermissionSchemaResolver ;
10
9
import org .ohdsi .webapi .security .model .EntityType ;
34
33
import javax .annotation .PostConstruct ;
35
34
import java .io .Serializable ;
36
35
import java .util .Arrays ;
37
- import java .util .Collection ;
38
- import java .util .HashMap ;
39
- import java .util .HashSet ;
40
36
import java .util .List ;
41
37
import java .util .Map ;
42
38
import java .util .Objects ;
43
39
import java .util .Set ;
44
- import java .util .concurrent .ConcurrentHashMap ;
45
- import java .util .function .Function ;
46
40
import 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 ;
47
45
48
46
@ Service
49
47
public class PermissionService {
@@ -64,9 +62,6 @@ public class PermissionService {
64
62
@ Value ("#{!'${security.provider}'.equals('DisabledSecurity')}" )
65
63
private boolean securityEnabled ;
66
64
67
- private ThreadLocal <ConcurrentHashMap <EntityType , ConcurrentHashMap <String , Set <RoleDTO >>>> permissionCache =
68
- ThreadLocal .withInitial (ConcurrentHashMap ::new );
69
-
70
65
private final EntityGraph PERMISSION_ENTITY_GRAPH = EntityGraphUtils .fromAttributePaths ("rolePermissions" , "rolePermissions.role" );
71
66
72
67
public PermissionService (
@@ -133,14 +128,14 @@ public void checkCommonEntityOwnership(EntityType entityType, Integer entityId)
133
128
134
129
public Map <String , String > getPermissionTemplates (EntityPermissionSchema permissionSchema , AccessType accessType ) {
135
130
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
+ }
144
139
}
145
140
146
141
public List <RoleEntity > finaAllRolesHavingPermissions (List <String > permissions ) {
@@ -178,97 +173,28 @@ private boolean isCurrentUserOwnerOf(CommonEntity entity) {
178
173
return Objects .equals (owner .getLogin (), loggedInUsername );
179
174
}
180
175
176
+ public List <Permission > getEntityPermissions (EntityType entityType , Number id , AccessType accessType ) {
177
+ Set <String > permissionTemplates = getTemplatesForType (entityType , accessType ).keySet ();
181
178
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 )))
219
181
.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 ;
253
183
}
254
184
255
- public boolean hasWriteAccess (CommonEntity entity ) {
185
+ public boolean hasAccess (CommonEntity entity , AccessType accessType ) {
256
186
boolean hasAccess = false ;
257
187
if (securityEnabled && entity .getCreatedBy () != null ) {
258
188
try {
189
+ Subject subject = SecurityUtils .getSubject ();
259
190
String login = this .permissionManager .getSubjectName ();
260
191
UserSimpleAuthorizationInfo authorizationInfo = this .permissionManager .getAuthorizationInfo (login );
261
192
if (Objects .equals (authorizationInfo .getUserId (), entity .getCreatedBy ().getId ())) {
262
193
hasAccess = true ; // the role is the one that created the artifact
263
194
} else {
264
195
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 ));
272
198
}
273
199
} catch (Exception e ) {
274
200
logger .error ("Error getting user roles and permissions" , e );
@@ -277,43 +203,24 @@ public boolean hasWriteAccess(CommonEntity entity) {
277
203
}
278
204
return hasAccess ;
279
205
}
280
-
206
+
207
+ public boolean hasWriteAccess (CommonEntity entity ) {
208
+ return hasAccess (entity , AccessType .WRITE );
209
+ }
281
210
282
211
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 );
306
213
}
307
214
308
215
public void fillWriteAccess (CommonEntity entity , CommonEntityDTO entityDTO ) {
309
216
if (securityEnabled && entity .getCreatedBy () != null ) {
310
- entityDTO .setHasWriteAccess (hasWriteAccess (entity ));
217
+ entityDTO .setHasWriteAccess (hasAccess (entity , AccessType . WRITE ));
311
218
}
312
219
}
313
220
314
221
public void fillReadAccess (CommonEntity entity , CommonEntityDTO entityDTO ) {
315
222
if (securityEnabled && entity .getCreatedBy () != null ) {
316
- entityDTO .setHasReadAccess (hasReadAccess (entity ));
223
+ entityDTO .setHasReadAccess (hasAccess (entity , AccessType . READ ));
317
224
}
318
225
}
319
226
0 commit comments