View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  
20  package org.eclipse.jetty.security;
21  
22  import java.io.IOException;
23  import java.io.Serializable;
24  import java.security.Principal;
25  import java.util.Map;
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.ConcurrentMap;
28  
29  import javax.security.auth.Subject;
30  import javax.servlet.ServletRequest;
31  
32  import org.eclipse.jetty.server.UserIdentity;
33  import org.eclipse.jetty.util.component.AbstractLifeCycle;
34  import org.eclipse.jetty.util.log.Log;
35  import org.eclipse.jetty.util.log.Logger;
36  import org.eclipse.jetty.util.security.Credential;
37  
38  
39  
40  /* ------------------------------------------------------------ */
41  /**
42   * A login service that keeps UserIdentities in a concurrent map
43   * either as the source or a cache of the users.
44   *
45   */
46  public abstract class MappedLoginService extends AbstractLifeCycle implements LoginService
47  {
48      private static final Logger LOG = Log.getLogger(MappedLoginService.class);
49  
50      protected IdentityService _identityService=new DefaultIdentityService();
51      protected String _name;
52      protected final ConcurrentMap<String, UserIdentity> _users=new ConcurrentHashMap<String, UserIdentity>();
53  
54      /* ------------------------------------------------------------ */
55      protected MappedLoginService()
56      {
57      }
58  
59      /* ------------------------------------------------------------ */
60      /** Get the name.
61       * @return the name
62       */
63      public String getName()
64      {
65          return _name;
66      }
67  
68      /* ------------------------------------------------------------ */
69      /** Get the identityService.
70       * @return the identityService
71       */
72      public IdentityService getIdentityService()
73      {
74          return _identityService;
75      }
76  
77      /* ------------------------------------------------------------ */
78      /** Get the users.
79       * @return the users
80       */
81      public ConcurrentMap<String, UserIdentity> getUsers()
82      {
83          return _users;
84      }
85  
86      /* ------------------------------------------------------------ */
87      /** Set the identityService.
88       * @param identityService the identityService to set
89       */
90      public void setIdentityService(IdentityService identityService)
91      {
92          if (isRunning())
93              throw new IllegalStateException("Running");
94          _identityService = identityService;
95      }
96  
97      /* ------------------------------------------------------------ */
98      /** Set the name.
99       * @param name the name to set
100      */
101     public void setName(String name)
102     {
103         if (isRunning())
104             throw new IllegalStateException("Running");
105         _name = name;
106     }
107 
108     /* ------------------------------------------------------------ */
109     /** Set the users.
110      * @param users the users to set
111      */
112     public void setUsers(Map<String, UserIdentity> users)
113     {
114         if (isRunning())
115             throw new IllegalStateException("Running");
116         _users.clear();
117         _users.putAll(users);
118     }
119 
120     /* ------------------------------------------------------------ */
121     /**
122      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
123      */
124     @Override
125     protected void doStart() throws Exception
126     {
127         loadUsers();
128         super.doStart();
129     }
130 
131     /* ------------------------------------------------------------ */
132     @Override
133     protected void doStop() throws Exception
134     {
135         super.doStop();
136     }
137 
138     /* ------------------------------------------------------------ */
139     public void logout(UserIdentity identity)
140     {
141         LOG.debug("logout {}",identity);
142         
143         //TODO should remove the user?????
144     }
145 
146     /* ------------------------------------------------------------ */
147     @Override
148     public String toString()
149     {
150         return this.getClass().getSimpleName()+"["+_name+"]";
151     }
152 
153     /* ------------------------------------------------------------ */
154     /** Put user into realm.
155      * Called by implementations to put the user data loaded from
156      * file/db etc into the user structure.
157      * @param userName User name
158      * @param info a UserIdentity instance, or a String password or Credential instance
159      * @return User instance
160      */
161     protected synchronized UserIdentity putUser(String userName, Object info)
162     {
163         final UserIdentity identity;
164         if (info instanceof UserIdentity)
165             identity=(UserIdentity)info;
166         else
167         {
168             Credential credential = (info instanceof Credential)?(Credential)info:Credential.getCredential(info.toString());
169 
170             Principal userPrincipal = new KnownUser(userName,credential);
171             Subject subject = new Subject();
172             subject.getPrincipals().add(userPrincipal);
173             subject.getPrivateCredentials().add(credential);
174             subject.setReadOnly();
175             identity=_identityService.newUserIdentity(subject,userPrincipal,IdentityService.NO_ROLES);
176         }
177 
178         _users.put(userName,identity);
179         return identity;
180     }
181 
182     /* ------------------------------------------------------------ */
183     /** Put user into realm.
184      * @param userName The user to add
185      * @param credential The users Credentials
186      * @param roles The users roles
187      * @return UserIdentity
188      */
189     public synchronized UserIdentity putUser(String userName, Credential credential, String[] roles)
190     {
191         Principal userPrincipal = new KnownUser(userName,credential);
192         Subject subject = new Subject();
193         subject.getPrincipals().add(userPrincipal);
194         subject.getPrivateCredentials().add(credential);
195 
196         if (roles!=null)
197             for (String role : roles)
198                 subject.getPrincipals().add(new RolePrincipal(role));
199 
200         subject.setReadOnly();
201         UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
202         _users.put(userName,identity);
203         return identity;
204     }
205     
206     
207 
208     
209     public synchronized UserIdentity putUser (KnownUser userPrincipal, String[] roles)
210     {
211         Subject subject = new Subject();
212         subject.getPrincipals().add(userPrincipal);
213         subject.getPrivateCredentials().add(userPrincipal._credential);
214         if (roles!=null)
215             for (String role : roles)
216                 subject.getPrincipals().add(new RolePrincipal(role));
217         subject.setReadOnly();
218         UserIdentity identity=_identityService.newUserIdentity(subject,userPrincipal,roles);
219         _users.put(userPrincipal._name,identity);
220         return identity;
221     }
222     
223 
224     /* ------------------------------------------------------------ */
225     public void removeUser(String username)
226     {
227         _users.remove(username);
228     }
229 
230     /* ------------------------------------------------------------ */
231     /**
232      * @see org.eclipse.jetty.security.LoginService#login(java.lang.String, java.lang.Object, ServletRequest)
233      */
234     public UserIdentity login(String username, Object credentials, ServletRequest request)
235     {
236         if (username == null)
237             return null;
238         
239         UserIdentity user = _users.get(username);
240 
241         if (user==null)
242         {
243             KnownUser userPrincipal = loadUserInfo(username);
244             if (userPrincipal.authenticate(credentials))
245             {
246                 //safe to load the roles
247                 String[] roles = loadRoleInfo(userPrincipal);
248                 user = putUser(userPrincipal, roles);
249                 return user;
250             }
251         }
252         else
253         {
254             UserPrincipal principal = (UserPrincipal)user.getUserPrincipal();
255             if (principal.authenticate(credentials))
256                 return user;
257         }
258         return null;
259     }
260 
261     /* ------------------------------------------------------------ */
262     public boolean validate(UserIdentity user)
263     {
264         if (_users.containsKey(user.getUserPrincipal().getName()))
265             return true;
266 
267         if (loadUser(user.getUserPrincipal().getName())!=null)
268             return true;
269 
270         return false;
271     }
272     /* ------------------------------------------------------------ */
273     protected abstract String[] loadRoleInfo (KnownUser user);
274     /* ------------------------------------------------------------ */
275     protected abstract KnownUser loadUserInfo (String username);
276     /* ------------------------------------------------------------ */
277     protected abstract UserIdentity loadUser(String username);
278 
279     /* ------------------------------------------------------------ */
280     protected abstract void loadUsers() throws IOException;
281 
282 
283     /* ------------------------------------------------------------ */
284     /* ------------------------------------------------------------ */
285     /* ------------------------------------------------------------ */
286     public interface UserPrincipal extends Principal,Serializable
287     {
288         boolean authenticate(Object credentials);
289         public boolean isAuthenticated();
290     }
291 
292     /* ------------------------------------------------------------ */
293     /* ------------------------------------------------------------ */
294     /* ------------------------------------------------------------ */
295     public static class RolePrincipal implements Principal,Serializable
296     {
297         private static final long serialVersionUID = 2998397924051854402L;
298         private final String _roleName;
299         public RolePrincipal(String name)
300         {
301             _roleName=name;
302         }
303         public String getName()
304         {
305             return _roleName;
306         }
307     }
308 
309     /* ------------------------------------------------------------ */
310     /* ------------------------------------------------------------ */
311     /* ------------------------------------------------------------ */
312     public static class Anonymous implements UserPrincipal,Serializable
313     {
314         private static final long serialVersionUID = 1097640442553284845L;
315 
316         public boolean isAuthenticated()
317         {
318             return false;
319         }
320 
321         public String getName()
322         {
323             return "Anonymous";
324         }
325 
326         public boolean authenticate(Object credentials)
327         {
328             return false;
329         }
330 
331     }
332 
333     /* ------------------------------------------------------------ */
334     /* ------------------------------------------------------------ */
335     /* ------------------------------------------------------------ */
336     public static class KnownUser implements UserPrincipal,Serializable
337     {
338         private static final long serialVersionUID = -6226920753748399662L;
339         private final String _name;
340         private final Credential _credential;
341 
342         /* -------------------------------------------------------- */
343         public KnownUser(String name,Credential credential)
344         {
345             _name=name;
346             _credential=credential;
347         }
348 
349         /* -------------------------------------------------------- */
350         public boolean authenticate(Object credentials)
351         {
352             return _credential!=null && _credential.check(credentials);
353         }
354 
355         /* ------------------------------------------------------------ */
356         public String getName()
357         {
358             return _name;
359         }
360 
361         /* -------------------------------------------------------- */
362         public boolean isAuthenticated()
363         {
364             return true;
365         }
366 
367         /* -------------------------------------------------------- */
368         @Override
369         public String toString()
370         {
371             return _name;
372         }
373     }
374 }
375