View Javadoc

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