View Javadoc
1   /**
2    * This file Copyright (c) 2003-2015 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.ArrayList;
39  import java.util.Collection;
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   * through 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 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         Collection<User> users = new ArrayList<User>();
140         for (String realmName : delegates.keySet()) {
141             try {
142                 UserManager userManager = delegates.get(realmName);
143                 users.addAll(userManager.getAllUsers());
144             } catch (UnsupportedOperationException e) {
145                 // Skip to next user manager if current is not supporting getAllUsers() method
146             }
147         }
148         return users;
149     }
150 
151     @Override
152     public void updateLastAccessTimestamp(final User user) {
153         delegateUntilSupported(new Op<Void>() {
154             @Override
155             public Void delegate(UserManager um) {
156                 um.updateLastAccessTimestamp(user);
157                 return null;
158             }
159         });
160     }
161 
162     private <RT> RT delegateUntilSupported(Op<RT> op) {
163         for (String realmName : delegates.keySet()) {
164             final UserManager um = delegates.get(realmName);
165             try {
166                 return op.delegate(um);
167             } catch (UnsupportedOperationException e) {
168                 // try the next delegate
169             }
170         }
171         throw new UnsupportedOperationException("None of the delegate UserManager supports this operation.");
172     }
173 
174     private <RT> RT delegateUntilNotNull(Op<RT> op) {
175         for (String realmName : delegates.keySet()) {
176             final UserManager um = delegates.get(realmName);
177             final RT result = op.delegate(um);
178             if (result != null) {
179                 return result;
180             }
181         }
182         return null;
183     }
184 
185     private <RT> RT delegateUntilSupportedAndNotNull(Op<RT> op) {
186         for (String realmName : delegates.keySet()) {
187             final UserManager um = delegates.get(realmName);
188             RT result = null;
189             try {
190                 result = op.delegate(um);
191             } catch (UnsupportedOperationException e) {
192                 // ignore;
193             }
194             if (result != null) {
195                 return result;
196             }
197         }
198         return null;
199     }
200 
201     private interface Op<RT> {
202         RT delegate(UserManager um);
203     }
204 
205     @Override
206     public boolean hasAny(final String principal, final String resourceName, final String resourceTypeName) {
207         return delegateUntilSupported(new Op<Boolean>() {
208             @Override
209             public Boolean delegate(UserManager um) {
210                 return um.hasAny(principal, resourceName, resourceTypeName);
211             }
212         });
213     }
214 
215     @Override
216     public Map<String, ACL> getACLs(final User user) {
217         return delegateUntilSupported(new Op<Map<String, ACL>>() {
218             @Override
219             public Map<String, ACL> delegate(UserManager um) {
220                 return um.getACLs(user);
221             }
222         });
223     }
224 
225     @Override
226     public User addRole(final User user, final String roleName) {
227         return delegateUntilNotNull(new Op<User>() {
228             @Override
229             public User delegate(UserManager um) {
230                 return um.addRole(user, roleName);
231             }
232         });
233     }
234 
235     @Override
236     public User addGroup(final User user, final String groupName) {
237         return delegateUntilNotNull(new Op<User>() {
238             @Override
239             public User delegate(UserManager um) {
240                 return um.addGroup(user, groupName);
241             }
242         });
243     }
244 
245     @Override
246     public int getLockTimePeriod() throws UnsupportedOperationException {
247         return delegateUntilSupported(new Op<Integer>() {
248             @Override
249             public Integer delegate(UserManager userManager) {
250                 return userManager.getLockTimePeriod();
251             }
252         });
253     }
254 
255     @Override
256     public int getMaxFailedLoginAttempts() throws UnsupportedOperationException {
257         return delegateUntilSupported(new Op<Integer>() {
258             @Override
259             public Integer delegate(UserManager userManager) {
260                 return userManager.getMaxFailedLoginAttempts();
261             }
262         });
263     }
264 
265     @Override
266     public void setLockTimePeriod(final int lockTimePeriod) throws UnsupportedOperationException {
267         delegateUntilSupported(new Op<Void>() {
268             @Override
269             public Void delegate(UserManager userManager) {
270                 userManager.setLockTimePeriod(lockTimePeriod);
271                 return null;
272             }
273         });
274     }
275 
276     @Override
277     public void setMaxFailedLoginAttempts(final int maxFailedLoginAttempts) throws UnsupportedOperationException {
278         delegateUntilSupported(new Op<Void>() {
279             @Override
280             public Void delegate(UserManager userManager) {
281                 userManager.setMaxFailedLoginAttempts(maxFailedLoginAttempts);
282                 return null;
283             }
284         });
285     }
286 
287     @Override
288     public User setProperty(final User user, final String propertyName, final Value propertyValue) throws UnsupportedOperationException {
289         return delegateUntilSupported(new Op<User>() {
290             @Override
291             public User delegate(UserManager userManager) {
292                 return userManager.setProperty(user, propertyName, propertyValue);
293             }
294         });
295     }
296 
297     @Override
298     public User setProperty(final User user, final String propertyName, final String propertyValue) {
299         return delegateUntilSupported(new Op<User>() {
300             @Override
301             public User delegate(UserManager um) {
302                 return um.setProperty(user, propertyName, propertyValue);
303             }
304         });
305     }
306 
307     @Override
308     public User removeGroup(final User user, final String groupName) {
309         return delegateUntilNotNull(new Op<User>() {
310             @Override
311             public User delegate(UserManager um) {
312                 return um.removeGroup(user, groupName);
313             }
314         });
315     }
316 
317     @Override
318     public User removeRole(final User user, final String roleName) {
319         return delegateUntilNotNull(new Op<User>() {
320             @Override
321             public User delegate(UserManager um) {
322                 return um.removeRole(user, roleName);
323             }
324         });
325     }
326 
327     @Override
328     public Collection<String> getUsersWithGroup(final String groupName) {
329         return delegateUntilSupported(new Op<Collection<String>>() {
330             @Override
331             public Collection<String> delegate(UserManager userManager) {
332                 return userManager.getUsersWithGroup(groupName);
333             }
334         });
335     }
336 
337     @Override
338     public Collection<String> getUsersWithRole(final String roleName) {
339         return delegateUntilSupported(new Op<Collection<String>>() {
340             @Override
341             public Collection<String> delegate(UserManager userManager) {
342                 return userManager.getUsersWithRole(roleName);
343             }
344         });
345     }
346 
347     @Override
348     public Collection<String> getUsersWithGroup(final String groupName, final boolean transitive) throws UnsupportedOperationException {
349         return delegateUntilSupported(new Op<Collection<String>>() {
350             @Override
351             public Collection<String> delegate(UserManager userManager) {
352                 return userManager.getUsersWithGroup(groupName, transitive);
353             }
354         });
355     }
356 
357 }