View Javadoc

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