View Javadoc
1   /**
2    * This file Copyright (c) 2003-2018 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.cms.security;
35  
36  import info.magnolia.cms.security.auth.ACL;
37  
38  import java.util.Collection;
39  import java.util.HashSet;
40  import java.util.Map;
41  
42  import javax.jcr.Value;
43  import javax.security.auth.Subject;
44  
45  /**
46   * A {@link UserManager} delegating to a set of user managers. The first user manager which does not
47   * throw an {@link UnsupportedOperationException} will be used.
48   */
49  public class DelegatingUserManager implements UserManager {
50  
51      private final Map<String, UserManager> delegates;
52  
53      /**
54       * @param delegates <String realm, UserManager delegate>
55       */
56      public DelegatingUserManager(Map<String, UserManager> delegates) {
57          this.delegates = delegates;
58      }
59  
60      @Override
61      public User createUser(final String name, final String pw) throws UnsupportedOperationException {
62          final Op<User> op = new Op<User>() {
63              @Override
64              public User delegate(UserManager um) {
65                  return um.createUser(name, pw);
66              }
67          };
68          return delegateUntilSupported(op);
69      }
70  
71      @Override
72      public User createUser(final String path, final String name, final String pw) throws UnsupportedOperationException {
73          final Op<User> op = new Op<User>() {
74              @Override
75              public User delegate(UserManager um) {
76                  return um.createUser(path, name, pw);
77              }
78          };
79          return delegateUntilSupported(op);
80      }
81  
82      @Override
83      public User../../../info/magnolia/cms/security/User.html#User">User changePassword(User user, String newPassword) throws UnsupportedOperationException {
84          throw new UnsupportedOperationException("Please use a specific instance of UserManager to do this.");
85      }
86  
87      @Override
88      public User getAnonymousUser() {
89          return delegateUntilSupported(new Op<User>() {
90              @Override
91              public User delegate(UserManager um) {
92                  return um.getAnonymousUser();
93              }
94          });
95      }
96  
97      @Override
98      public User getSystemUser() {
99          return delegateUntilSupported(new Op<User>() {
100             @Override
101             public User delegate(UserManager um) {
102                 return um.getSystemUser();
103             }
104         });
105     }
106 
107     @Override
108     public User getUser(final String name) throws UnsupportedOperationException {
109         return delegateUntilSupportedAndNotNull(new Op<User>() {
110             @Override
111             public User delegate(UserManager um) {
112                 return um.getUser(name);
113             }
114         });
115     }
116 
117     @Override
118     public User getUserById(final String id) throws UnsupportedOperationException {
119         return delegateUntilSupportedAndNotNull(new Op<User>() {
120             @Override
121             public User delegate(UserManager um) {
122                 return um.getUserById(id);
123             }
124         });
125     }
126 
127     @Override
128     public User getUser(final Subject subject) throws UnsupportedOperationException {
129         return delegateUntilSupportedAndNotNull(new Op<User>() {
130             @Override
131             public User delegate(UserManager um) {
132                 return um.getUser(subject);
133             }
134         });
135     }
136 
137     @Override
138     public Collection<User> getAllUsers() throws UnsupportedOperationException {
139         return delegateAndCollectSilently(new Op<Collection<User>>() {
140             @Override
141             public Collection<User> delegate(UserManager userManager) {
142                 return userManager.getAllUsers();
143             }
144         });
145     }
146 
147     @Override
148     public void updateLastAccessTimestamp(final User user) {
149         delegateUntilSupported(new Op<Void>() {
150             @Override
151             public Void delegate(UserManager um) {
152                 um.updateLastAccessTimestamp(user);
153                 return null;
154             }
155         });
156     }
157 
158     private <RT> RT delegateUntilSupported(Op<RT> op) {
159         for (String realmName : delegates.keySet()) {
160             final UserManager um = delegates.get(realmName);
161             try {
162                 return op.delegate(um);
163             } catch (UnsupportedOperationException e) {
164                 // try the next delegate
165             }
166         }
167         throw new UnsupportedOperationException("None of the delegate UserManager supports this operation.");
168     }
169 
170     private <RT> RT delegateUntilNotNull(Op<RT> op) {
171         for (String realmName : delegates.keySet()) {
172             final UserManager um = delegates.get(realmName);
173             final RT result = op.delegate(um);
174             if (result != null) {
175                 return result;
176             }
177         }
178         return null;
179     }
180 
181     private <RT> RT delegateUntilSupportedAndNotNull(Op<RT> op) {
182         for (String realmName : delegates.keySet()) {
183             final UserManager um = delegates.get(realmName);
184             RT result = null;
185             try {
186                 result = op.delegate(um);
187             } catch (UnsupportedOperationException e) {
188                 // ignore;
189             }
190             if (result != null) {
191                 return result;
192             }
193         }
194         return null;
195     }
196 
197     private <RT extends Collection> RT delegateAndCollectSilently(Op<RT> op) {
198         RT results = (RT) new HashSet<>();
199         for (String realmName : delegates.keySet()) {
200             final UserManager um = delegates.get(realmName);
201             try {
202                 RT result = op.delegate(um);
203                 if (result != null) {
204                     results.addAll(result);
205                 }
206             } catch (UnsupportedOperationException e) {
207                 // Should keep silently
208             }
209         }
210         return results;
211     }
212 
213     private interface Op<RT> {
214         RT delegate(UserManager um);
215     }
216 
217     @Override
218     public boolean hasAny(final String principal, final String resourceName, final String resourceTypeName) {
219         return delegateUntilSupported(new Op<Boolean>() {
220             @Override
221             public Boolean delegate(UserManager um) {
222                 return um.hasAny(principal, resourceName, resourceTypeName);
223             }
224         });
225     }
226 
227     @Override
228     public Map<String, ACL> getACLs(final User user) {
229         return delegateUntilSupported(new Op<Map<String, ACL>>() {
230             @Override
231             public Map<String, ACL> delegate(UserManager um) {
232                 return um.getACLs(user);
233             }
234         });
235     }
236 
237     @Override
238     public UserUser.html#User">User addRole(final User user, final String roleName) {
239         return delegateUntilNotNull(new Op<User>() {
240             @Override
241             public User delegate(UserManager um) {
242                 return um.addRole(user, roleName);
243             }
244         });
245     }
246 
247     @Override
248     public Userser.html#User">User addGroup(final User user, final String groupName) {
249         return delegateUntilNotNull(new Op<User>() {
250             @Override
251             public User delegate(UserManager um) {
252                 return um.addGroup(user, groupName);
253             }
254         });
255     }
256 
257     @Override
258     public int getLockTimePeriod() throws UnsupportedOperationException {
259         return delegateUntilSupported(new Op<Integer>() {
260             @Override
261             public Integer delegate(UserManager userManager) {
262                 return userManager.getLockTimePeriod();
263             }
264         });
265     }
266 
267     @Override
268     public int getMaxFailedLoginAttempts() throws UnsupportedOperationException {
269         return delegateUntilSupported(new Op<Integer>() {
270             @Override
271             public Integer delegate(UserManager userManager) {
272                 return userManager.getMaxFailedLoginAttempts();
273             }
274         });
275     }
276 
277     @Override
278     public void setLockTimePeriod(final int lockTimePeriod) throws UnsupportedOperationException {
279         delegateUntilSupported(new Op<Void>() {
280             @Override
281             public Void delegate(UserManager userManager) {
282                 userManager.setLockTimePeriod(lockTimePeriod);
283                 return null;
284             }
285         });
286     }
287 
288     @Override
289     public void setMaxFailedLoginAttempts(final int maxFailedLoginAttempts) throws UnsupportedOperationException {
290         delegateUntilSupported(new Op<Void>() {
291             @Override
292             public Void delegate(UserManager userManager) {
293                 userManager.setMaxFailedLoginAttempts(maxFailedLoginAttempts);
294                 return null;
295             }
296         });
297     }
298 
299     @Override
300     public User.html#User">User setProperty(final User user, final String propertyName, final Value propertyValue) throws UnsupportedOperationException {
301         return delegateUntilSupported(new Op<User>() {
302             @Override
303             public User delegate(UserManager userManager) {
304                 return userManager.setProperty(user, propertyName, propertyValue);
305             }
306         });
307     }
308 
309     @Override
310     public User.html#User">User setProperty(final User user, final String propertyName, final String propertyValue) {
311         return delegateUntilSupported(new Op<User>() {
312             @Override
313             public User delegate(UserManager um) {
314                 return um.setProperty(user, propertyName, propertyValue);
315             }
316         });
317     }
318 
319     @Override
320     public User.html#User">User removeGroup(final User user, final String groupName) {
321         return delegateUntilNotNull(new Op<User>() {
322             @Override
323             public User delegate(UserManager um) {
324                 return um.removeGroup(user, groupName);
325             }
326         });
327     }
328 
329     @Override
330     public Userr.html#User">User removeRole(final User user, final String roleName) {
331         return delegateUntilNotNull(new Op<User>() {
332             @Override
333             public User delegate(UserManager um) {
334                 return um.removeRole(user, roleName);
335             }
336         });
337     }
338 
339     @Override
340     public Collection<String> getUsersWithGroup(final String groupName) {
341         return delegateAndCollectSilently(new Op<Collection<String>>() {
342             @Override
343             public Collection<String> delegate(UserManager userManager) {
344                 return userManager.getUsersWithGroup(groupName);
345             }
346         });
347     }
348 
349     @Override
350     public Collection<String> getUsersWithRole(final String roleName) {
351         return delegateAndCollectSilently(new Op<Collection<String>>() {
352             @Override
353             public Collection<String> delegate(UserManager userManager) {
354                 return userManager.getUsersWithRole(roleName);
355             }
356         });
357     }
358 
359     @Override
360     public Collection<String> getUsersWithGroup(final String groupName, final boolean transitive) throws UnsupportedOperationException {
361         return delegateAndCollectSilently(new Op<Collection<String>>() {
362             @Override
363             public Collection<String> delegate(UserManager userManager) {
364                 return userManager.getUsersWithGroup(groupName, transitive);
365             }
366         });
367     }
368 }