1 /*
2 * Copyright (c) 2002-2025, City of Paris
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright notice
10 * and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright notice
13 * and the following disclaimer in the documentation and/or other materials
14 * provided with the distribution.
15 *
16 * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *
32 * License 1.0
33 */
34 package fr.paris.lutece.portal.service.rbac;
35
36 import fr.paris.lutece.api.user.User;
37 import fr.paris.lutece.api.user.UserRole;
38 import fr.paris.lutece.portal.business.rbac.RBAC;
39 import fr.paris.lutece.portal.business.rbac.RBACHome;
40 import fr.paris.lutece.portal.business.user.AdminUser;
41 import fr.paris.lutece.util.ReferenceItem;
42 import fr.paris.lutece.util.ReferenceList;
43
44 import java.util.ArrayList;
45 import java.util.Collection;
46 import java.util.Collections;
47 import java.util.HashMap;
48 import java.util.Map;
49 import java.util.Set;
50 import java.util.stream.Collectors;
51
52 /**
53 * This class provides the main methods to control the access to a resource depending on the user's roles
54 */
55 public final class RBACService
56 {
57
58 /**
59 * ReferenceItem as an RBACResource
60 */
61 private static final class RBACReferenceItem implements RBACResource
62 {
63 private final String _strResourceType;
64 private final ReferenceItem _item;
65
66 /**
67 * Constructor
68 *
69 * @param strResourceType
70 * the resource type
71 * @param item
72 * the reference item
73 */
74 public RBACReferenceItem( String strResourceType, ReferenceItem item )
75 {
76 _strResourceType = strResourceType;
77 _item = item;
78 }
79
80 @Override
81 public String getResourceTypeCode( )
82 {
83 return _strResourceType;
84 }
85
86 @Override
87 public String getResourceId( )
88 {
89 return _item.getCode( );
90 }
91
92 /**
93 * The reference item
94 *
95 * @return the reference item
96 */
97 public ReferenceItem getItem( )
98 {
99 return _item;
100 }
101
102 }
103
104 /**
105 * Constructor
106 */
107 private RBACService( )
108 {
109 }
110
111 /**
112 * Check that a given user is allowed to access a resource for a given permission
113 *
114 * @param strResourceTypeCode
115 * the key of the resource type being considered
116 * @param strResourceId
117 * the id of the resource being considered
118 * @param strPermission
119 * the permission needed
120 * @param user
121 * the user trying to access the ressource
122 * @return true if the user can access the given resource with the given permission, false otherwise
123 */
124 public static boolean isAuthorized( String strResourceTypeCode, String strResourceId, String strPermission, User user )
125 {
126 // Check user roles
127 Collection<String> colRoles = RBACHome.findRoleKeys( strResourceTypeCode, strResourceId, strPermission );
128
129 for ( String strRole : colRoles )
130 {
131 if ( isUserInRole( user, strRole ) )
132 {
133 return true;
134 }
135 }
136
137 return false;
138 }
139
140 /**
141 * Check that a given user is allowed to access a resource for a given permission
142 *
143 * @param strResourceTypeCode
144 * the key of the resource type being considered
145 * @param strResourceId
146 * the id of the resource being considered
147 * @param strPermission
148 * the permission needed
149 * @param user
150 * the user trying to access the ressource
151 * @return true if the user can access the given resource with the given permission, false otherwise
152 * @deprecated use isAuthorized( String, String, String, User )
153 */
154 @Deprecated
155 public static boolean isAuthorized( String strResourceTypeCode, String strResourceId, String strPermission, AdminUser user )
156 {
157 return isAuthorized( strResourceTypeCode, strResourceId, strPermission, (User) user );
158 }
159
160 /**
161 * Check that a given user is allowed to access a resource for a given permission
162 *
163 * @param resource
164 * the resource object being considered
165 * @param strPermission
166 * the permission needed
167 * @param user
168 * the user trying to access the ressource
169 * @return true if the user can access the given resource with the given permission, false otherwise
170 */
171 public static boolean isAuthorized( RBACResource resource, String strPermission, User user )
172 {
173 boolean bAuthorized = false;
174
175 if ( resource != null )
176 {
177 bAuthorized = isAuthorized( resource.getResourceTypeCode( ), resource.getResourceId( ), strPermission, user );
178 }
179
180 return bAuthorized;
181 }
182
183 /**
184 * Check that a given user is allowed to access a resource for a given permission
185 *
186 * @param resource
187 * the resource object being considered
188 * @param strPermission
189 * the permission needed
190 * @param user
191 * the user trying to access the ressource
192 * @return true if the user can access the given resource with the given permission, false otherwise
193 * @deprecated use isAuthorized( RBACResource, String, User )
194 */
195 @Deprecated
196 public static boolean isAuthorized( RBACResource resource, String strPermission, AdminUser user )
197 {
198 return isAuthorized( resource, strPermission, (User) user );
199 }
200
201 /**
202 * Check that a given user is in the given role
203 *
204 * @param user
205 * The user
206 * @param strRole
207 * The role
208 * @return true if the user has the given role, false otherwise
209 */
210 public static boolean isUserInRole( User user, String strRole )
211 {
212 Map<String, UserRole> userRoles = user.getUserRoles( );
213
214 return userRoles.containsKey( strRole );
215 }
216
217 /**
218 * Check that a given user is in the given role
219 *
220 * @param user
221 * The user
222 * @param strRole
223 * The role
224 * @return true if the user has the given role, false otherwise
225 * @deprecated use isUserInRole( User, String )
226 */
227 @Deprecated
228 public static boolean isUserInRole( AdminUser user, String strRole )
229 {
230 return isUserInRole( (User) user, strRole );
231 }
232
233 /**
234 * Filter a collection of resources for a given user
235 *
236 * @param <E>
237 * The RBAC resource
238 * @param collection
239 * The collection to filter
240 * @param strPermission
241 * Permission to check
242 * @param user
243 * The user
244 * @return A filtered collection of resources
245 */
246 public static <E extends RBACResource> Collection<E> getAuthorizedCollection( Collection<E> collection, String strPermission, User user )
247 {
248 if ( user == null )
249 {
250 return Collections.emptyList( );
251 }
252 Map<String, Collection<RBAC>> rbacsByResourceType = new HashMap<>( );
253 RBACHome.findByPermissionAndRoles( strPermission, user.getUserRoles( ).keySet( ) ).stream( ).forEach( rbac -> {
254 rbacsByResourceType.computeIfAbsent( rbac.getResourceTypeKey( ), t -> new ArrayList<>( ) ).add( rbac );
255 } );
256 return collection.stream( )
257 .filter( resource -> rbacsByResourceType
258 .getOrDefault( resource.getResourceTypeCode( ), Collections.emptyList( ) ).stream( )
259 .anyMatch( rbac -> RBAC.WILDCARD_RESOURCES_ID.equals( rbac.getResourceId( ) )
260 || resource.getResourceId( ).equals( rbac.getResourceId( ) ) ) )
261 .collect( Collectors.toList( ) );
262 }
263
264 /**
265 * Filter a collection of resources for a given user
266 *
267 * @param <E>
268 * The RBAC resource
269 * @param collection
270 * The collection to filter
271 * @param strPermission
272 * Permission to check
273 * @param user
274 * The user
275 * @return A filtered collection of resources
276 * @deprecated use getAuthorizedCollection( Collection, String, User )
277 */
278 @Deprecated
279 public static <E extends RBACResource> Collection<E> getAuthorizedCollection( Collection<E> collection, String strPermission, AdminUser user )
280 {
281 return getAuthorizedCollection( collection, strPermission, (User) user );
282 }
283
284 /**
285 * Filter a Reference List for a given user
286 *
287 * @param listResources
288 * The list to filter
289 * @param strResourceType
290 * The resource type
291 * @param strPermission
292 * The permission to check
293 * @param user
294 * The user
295 * @return The filtered collection
296 */
297 public static ReferenceLists/lutece/util/ReferenceList.html#ReferenceList">ReferenceList getAuthorizedReferenceList( ReferenceList listResources, String strResourceType, String strPermission, User user )
298 {
299 return getAuthorizedCollection( listResources.stream( )
300 .map( item -> new RBACReferenceItem( strResourceType, item ) ).collect( Collectors.toList( ) ),
301 strPermission, user ).stream( ).map( RBACReferenceItem::getItem )
302 .collect( Collectors.toCollection( ReferenceList::new ) );
303 }
304
305 /**
306 * Filter a Reference List for a given user
307 *
308 * @param listResources
309 * The list to filter
310 * @param strResourceType
311 * The resource type
312 * @param strPermission
313 * The permission to check
314 * @param user
315 * The user
316 * @return The filtered collection
317 * @deprecated use getAuthorizedReferenceList( ReferenceList, String, String, User )
318 */
319 @Deprecated
320 public static ReferenceLists/lutece/util/ReferenceList.html#ReferenceList">ReferenceList getAuthorizedReferenceList( ReferenceList listResources, String strResourceType, String strPermission, AdminUser user )
321 {
322 return getAuthorizedReferenceList( listResources, strResourceType, strPermission, (User) user );
323 }
324
325 /**
326 * Filter a collection of RBACAction for a given user
327 *
328 * @param <E>
329 * The RBAC resource
330 * @param collection
331 * The collection to filter
332 * @param resource
333 * The resource
334 * @param user
335 * The user
336 * @return The filtered collection
337 */
338 public static <E extends RBACAction> Collection<E> getAuthorizedActionsCollection( Collection<E> collection, RBACResource resource, User user )
339 {
340 if ( collection.isEmpty( ) )
341 {
342 return collection;
343 }
344 Set<String> permissions = RBACHome
345 .findByPermissionsAndRoles(
346 collection.stream( ).map( RBACAction::getPermission ).collect( Collectors.toSet( ) ),
347 user.getUserRoles( ).keySet( ) )
348 .stream( ).filter( rbac -> resource.getResourceTypeCode( ).equals( rbac.getResourceTypeKey( ) ) )
349 .filter( rbac -> RBAC.WILDCARD_RESOURCES_ID.equals( rbac.getResourceId( ) )
350 || resource.getResourceId( ).equals( rbac.getResourceId( ) ) )
351 .map( RBAC::getPermissionKey ).collect( Collectors.toSet( ) );
352 return collection.stream( ).filter( action -> permissions.contains( action.getPermission( ) )
353 || permissions.contains( RBAC.WILDCARD_PERMISSIONS_KEY ) ).collect( Collectors.toList( ) );
354 }
355
356 /**
357 * Filter a collection of RBACAction for a given user
358 *
359 * @param <E>
360 * The RBAC resource
361 * @param collection
362 * The collection to filter
363 * @param resource
364 * The resource
365 * @param user
366 * The user
367 * @return The filtered collection
368 * @deprecated use getAuthorizedActionsCollection( Collection, RBACResource, User )
369 */
370 @Deprecated
371 public static <E extends RBACAction> Collection<E> getAuthorizedActionsCollection( Collection<E> collection, RBACResource resource, AdminUser user )
372 {
373 return getAuthorizedActionsCollection( collection, resource, (User) user );
374 }
375
376 }