View Javadoc

1   /*
2    * Copyright (C) 2017-2019 Centre National d'Etudes Spatiales (CNES).
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 3.0 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   * Lesser General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this library; if not, write to the Free Software
16   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17   * MA 02110-1301  USA
18   */
19  package fr.cnes.doi.db;
20  
21  import java.util.ArrayList;
22  import java.util.HashSet;
23  import java.util.List;
24  import java.util.Set;
25  import java.util.concurrent.CopyOnWriteArrayList;
26  
27  import org.restlet.Application;
28  import org.restlet.Request;
29  import org.restlet.Response;
30  import org.restlet.data.ClientInfo;
31  import org.restlet.engine.security.RoleMapping;
32  import org.restlet.security.Enroler;
33  import org.restlet.security.Group;
34  import org.restlet.security.Realm;
35  import org.restlet.security.Role;
36  import org.restlet.security.SecretVerifier;
37  import org.restlet.security.User;
38  
39  /**
40   * Had to change method "unmap" l.520, which threw
41   * ArrayIndexOutOfBoundsException
42   *
43   * @author disto
44   */
45  public final class MyMemoryRealm extends Realm {
46  
47      /**
48       * The modifiable list of role mappings.
49       */
50      private final List<RoleMapping> roleMappings = new CopyOnWriteArrayList<>();
51  
52      /**
53       * The modifiable list of root groups.
54       */
55      private final List<Group> rootGroups = new CopyOnWriteArrayList<>();
56  
57      /**
58       * The modifiable list of users.
59       */
60      private final List<User> users = new CopyOnWriteArrayList<>();
61  
62      /**
63       * Constructor.
64       */
65      public MyMemoryRealm() {
66          super();
67          setVerifier(new DefaultVerifier());
68          setEnroler(new DefaultEnroler());
69      }
70  
71      /**
72       * Recursively adds groups where a given user is a member.
73       *
74       * @param user The member user.
75       * @param userGroups The set of user groups to update.
76       * @param currentGroup The current group to inspect.
77       * @param stack The stack of ancestor groups.
78       * @param inheritOnly Indicates if only the ancestors groups that have their
79       * "inheritRoles" property enabled should be added.
80       */
81      private void addGroups(final User user, final Set<Group> userGroups,
82              final Group currentGroup, final List<Group> stack, final boolean inheritOnly) {
83          if ((currentGroup != null) && !stack.contains(currentGroup)) {
84              stack.add(currentGroup);
85  
86              if (currentGroup.getMemberUsers().contains(user)) {
87                  userGroups.add(currentGroup);
88  
89                  // Add the ancestor groups as well
90                  boolean inherit = !inheritOnly
91                          || currentGroup.isInheritingRoles();
92                  Group group;
93  
94                  for (int i = stack.size() - 2; inherit && (i >= 0); i--) {
95                      group = stack.get(i);
96                      userGroups.add(group);
97                      inherit = !inheritOnly || group.isInheritingRoles();
98                  }
99              }
100 
101             for (final Group group : currentGroup.getMemberGroups()) {
102                 addGroups(user, userGroups, group, stack, inheritOnly);
103             }
104         }
105     }
106 
107     /**
108      * Finds the set of groups where a given user is a member. Note that
109      * inheritable ancestors groups are also returned.
110      *
111      * @param user The member user.
112      * @return The set of groups.
113      */
114     public Set<Group> findGroups(final User user) {
115         return findGroups(user, true);
116     }
117 
118     /**
119      * Finds the set of groups where a given user is a member.
120      *
121      * @param user The member user.
122      * @param inheritOnly Indicates if only the ancestors groups that have their
123      * "inheritRoles" property enabled should be added.
124      * @return The set of groups.
125      */
126     public Set<Group> findGroups(final User user, final boolean inheritOnly) {
127         final Set<Group> result = new HashSet<>();
128         List<Group> stack;
129 
130         // Recursively find user groups
131         for (final Group group : getRootGroups()) {
132             stack = new ArrayList<>();
133             addGroups(user, result, group, stack, inheritOnly);
134         }
135 
136         return result;
137     }
138 
139     /**
140      * Finds the roles mapped to a given user group.
141      *
142      * @param application The parent application. Can't be null.
143      * @param userGroup The user group.
144      * @return The roles found.
145      * @throws IllegalArgumentException If application is null.
146      */
147     public Set<Role> findRoles(final Application application, final Group userGroup) {
148         if (application == null) {
149             throw new IllegalArgumentException(
150                     "The application argument can't be null");
151         }
152 
153         final Set<Role> result = new HashSet<>();
154         Object source;
155 
156         for (final RoleMapping mapping : getRoleMappings()) {
157             source = mapping.getSource();
158 
159             if ((userGroup != null) && userGroup.equals(source)) {
160                 if (mapping.getTarget().getApplication() == application) {
161                     result.add(mapping.getTarget());
162                 }
163             }
164         }
165 
166         return result;
167     }
168 
169     /**
170      * Finds the roles mapped to given user groups.
171      *
172      * @param application The parent application. Can't be null.
173      * @param userGroups The user groups.
174      * @return The roles found.
175      * @throws IllegalArgumentException If application is null.
176      */
177     public Set<Role> findRoles(final Application application, final Set<Group> userGroups) {
178         if (application == null) {
179             throw new IllegalArgumentException(
180                     "The application argument can't be null");
181         }
182 
183         final Set<Role> result = new HashSet<>();
184         Object source;
185 
186         for (final RoleMapping mapping : getRoleMappings()) {
187             source = mapping.getSource();
188 
189             if (userGroups != null && userGroups.contains(source)) {
190                 if (mapping.getTarget().getApplication() == application) {
191                     result.add(mapping.getTarget());
192                 }
193             }
194         }
195 
196         return result;
197     }
198 
199     /**
200      * Finds the roles mapped to a given user, for a specific application.
201      *
202      * @param application The parent application. Can't be null.
203      * @param user The user.
204      * @return The roles found.
205      * @throws IllegalArgumentException If application is null.
206      */
207     public Set<Role> findRoles(final Application application, final User user) {
208         if (application == null) {
209             throw new IllegalArgumentException(
210                     "The application argument can't be null");
211         }
212 
213         final Set<Role> result = new HashSet<>();
214         Object source;
215 
216         for (final RoleMapping mapping : getRoleMappings()) {
217             source = mapping.getSource();
218 
219             if ((user != null) && user.equals(source)) {
220                 if (mapping.getTarget().getApplication() == application) {
221                     result.add(mapping.getTarget());
222                 }
223             }
224         }
225 
226         return result;
227     }
228 
229     /**
230      * Finds the roles mapped to given user group.
231      *
232      * @param userGroup The user group.
233      * @return The roles found.
234      */
235     public Set<Role> findRoles(final Group userGroup) {
236         final Set<Role> result = new HashSet<>();
237         Object source;
238 
239         for (final RoleMapping mapping : getRoleMappings()) {
240             source = mapping.getSource();
241 
242             if ((userGroup != null) && userGroup.equals(source)) {
243                 result.add(mapping.getTarget());
244             }
245         }
246 
247         return result;
248     }
249 
250     /**
251      * Finds the roles mapped to given user groups.
252      *
253      * @param userGroups The user groups.
254      * @return The roles found.
255      */
256     public Set<Role> findRoles(final Set<Group> userGroups) {
257         final Set<Role> result = new HashSet<>();
258         Object source;
259 
260         for (final RoleMapping mapping : getRoleMappings()) {
261             source = mapping.getSource();
262 
263             if (userGroups != null && userGroups.contains(source)) {
264                 result.add(mapping.getTarget());
265             }
266         }
267 
268         return result;
269     }
270 
271     /**
272      * Finds the roles mapped to a given user.
273      *
274      * @param user The user.
275      * @return The roles found.
276      */
277     public Set<Role> findRoles(final User user) {
278         final Set<Role> result = new HashSet<>();
279         Object source;
280 
281         for (final RoleMapping mapping : getRoleMappings()) {
282             source = mapping.getSource();
283 
284             if (user != null && user.equals(source)) {
285                 result.add(mapping.getTarget());
286             }
287         }
288 
289         return result;
290     }
291 
292     /**
293      * Finds a user in the organization based on its identifier.
294      *
295      * @param userIdentifier The identifier to match.
296      * @return The matched user or null.
297      */
298     public User findUser(final String userIdentifier) {
299         User result = null;
300         User user;
301 
302         for (int i = 0; (result == null) && (i < getUsers().size()); i++) {
303             user = getUsers().get(i);
304 
305             if (user.getIdentifier().equals(userIdentifier)) {
306                 result = user;
307             }
308         }
309 
310         return result;
311     }
312 
313     /**
314      * Returns the modifiable list of role mappings.
315      *
316      * @return The modifiable list of role mappings.
317      */
318     private List<RoleMapping> getRoleMappings() {
319         return roleMappings;
320     }
321 
322     /**
323      * Returns the modifiable list of root groups.
324      *
325      * @return The modifiable list of root groups.
326      */
327     public List<Group> getRootGroups() {
328         return rootGroups;
329     }
330 
331     /**
332      * Returns the modifiable list of users.
333      *
334      * @return The modifiable list of users.
335      */
336     public List<User> getUsers() {
337         return users;
338     }
339 
340     /**
341      * Maps a group defined in a component to a role defined in the application.
342      *
343      * @param group The source group.
344      * @param role The target role.
345      */
346     public void map(final Group group, final Role role) {
347         getRoleMappings().add(new RoleMapping(group, role));
348     }
349 
350     /**
351      * Maps a user defined in a component to a role defined in the application.
352      *
353      * @param user The source user.
354      * @param application The parent application. Can't be null.
355      * @param roleName he target role name.
356      * @throws IllegalArgumentException If application is null.
357      */
358     public void map(final User user, final Application application, final String roleName) {
359         map(user, Role.get(application, roleName, null));
360     }
361 
362     /**
363      * Maps a user defined in a component to a role defined in the application.
364      *
365      * @param user The source user.
366      * @param role The target role.
367      */
368     public void map(final User user, final Role role) {
369         getRoleMappings().add(new RoleMapping(user, role));
370     }
371 
372     /**
373      * Sets the modifiable list of root groups. This method clears the current
374      * list and adds all entries in the parameter list.
375      *
376      * @param rootGroups A list of root groups.
377      */
378     public void setRootGroups(final List<Group> rootGroups) {
379         synchronized (getRootGroups()) {
380             if (rootGroups != getRootGroups()) {
381                 getRootGroups().clear();
382 
383                 if (rootGroups != null) {
384                     getRootGroups().addAll(rootGroups);
385                 }
386             }
387         }
388     }
389 
390     /**
391      * Sets the modifiable list of users. This method clears the current list
392      * and adds all entries in the parameter list.
393      *
394      * @param users A list of users.
395      */
396     public void setUsers(final List<User> users) {
397         synchronized (getUsers()) {
398             if (users != getUsers()) {
399                 getUsers().clear();
400 
401                 if (users != null) {
402                     getUsers().addAll(users);
403                 }
404             }
405         }
406     }
407 
408     /**
409      * Unmaps a group defined in a component from a role defined in the
410      * application.
411      *
412      * @param group The source group.
413      * @param application The parent application. Can't be null.
414      * @param roleName The target role name.
415      * @throws IllegalArgumentException If application is null.
416      */
417     public void unmap(final Group group, final Application application, final String roleName) {
418         unmap(group, Role.get(application, roleName, null));
419     }
420 
421     /**
422      * Unmaps a group defined in a component from a role defined in the
423      * application.
424      *
425      * @param group The source group.
426      * @param role The target role.
427      */
428     public void unmap(final Group group, final Role role) {
429         unmap((Object) group, role);
430     }
431 
432     /**
433      * Unmaps an element (user, group or organization) defined in a component
434      * from a role defined in the application.
435      *
436      * @param source The source group.
437      * @param role The target role.
438      */
439     private void unmap(final Object source, final Role role) {
440         RoleMapping mapping;
441 
442         for (int i = getRoleMappings().size() - 1; i >= 0; i--) {
443             mapping = getRoleMappings().get(i);
444 
445             if (mapping.getSource().equals(source) && mapping.getTarget().equals(role)) {
446                 getRoleMappings().remove(i);
447             }
448         }
449     }
450 
451     /**
452      * Unmaps a user defined in a component from a role defined in the
453      * application.
454      *
455      * @param user The source user.
456      * @param application The parent application. Can't be null.
457      * @param roleName The target role name.
458      * @throws IllegalArgumentException If application is null.
459      */
460     public void unmap(final User user, final Application application, final String roleName) {
461         unmap(user, Role.get(application, roleName, null));
462     }
463 
464     /**
465      * Unmaps a user defined in a component from a role defined in the
466      * application.
467      *
468      * @param user The source user.
469      * @param role The target role.
470      */
471     public void unmap(final User user, final Role role) {
472         unmap((Object) user, role);
473     }
474 
475     /**
476      * Enroler based on the default security model.
477      */
478     private class DefaultEnroler implements Enroler {
479 
480         /**
481          * {@inheritDoc}
482          */
483         @Override
484         public void enrole(final ClientInfo clientInfo) {
485             final User user = findUser(clientInfo.getUser().getIdentifier());
486 
487             if (user != null) {
488                 // Find all the inherited groups of this user
489                 final Set<Group> userGroups = findGroups(user);
490 
491                 // Add roles specific to this user
492                 final Set<Role> userRoles = findRoles(user);
493 
494                 for (final Role role : userRoles) {
495                     clientInfo.getRoles().add(role);
496                 }
497 
498                 // Add roles common to group members
499                 final Set<Role> groupRoles = findRoles(userGroups);
500 
501                 for (final Role role : groupRoles) {
502                     clientInfo.getRoles().add(role);
503                 }
504             }
505         }
506     }
507 
508     /**
509      * Verifier based on the default security model. It looks up users in the
510      * mapped organizations.
511      */
512     private class DefaultVerifier extends SecretVerifier {
513 
514         /**
515          * {@inheritDoc}
516          */
517         @Override
518         protected User createUser(final String identifier, final Request request,
519                 final Response response) {
520             final User result = new User(identifier);
521 
522             // Find the reference user
523             final User user = findUser(identifier);
524 
525             if (user != null) {
526                 // Copy the properties of the reference user
527                 result.setEmail(user.getEmail());
528                 result.setFirstName(user.getFirstName());
529                 result.setLastName(user.getLastName());
530             }
531 
532             return result;
533         }
534 
535         /**
536          * {@inheritDoc}
537          */
538         @Override
539         public int verify(final String identifier, final char[] secret) {
540             char[] actualSecret = null;
541             final User user = findUser(identifier);
542 
543             if (user != null) {
544                 actualSecret = user.getSecret();
545             }
546 
547             return compare(secret, actualSecret) ? RESULT_VALID : RESULT_INVALID;
548         }
549     }
550 }