View Javadoc

1   // ========================================================================
2   // Copyright (c) 2003-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  package org.eclipse.jetty.plus.jaas;
15  
16  import java.io.IOException;
17  import java.security.Principal;
18  import java.util.ArrayList;
19  import java.util.Arrays;
20  import java.util.Collection;
21  import java.util.LinkedHashSet;
22  import java.util.Set;
23  
24  import javax.security.auth.Subject;
25  import javax.security.auth.callback.Callback;
26  import javax.security.auth.callback.CallbackHandler;
27  import javax.security.auth.callback.NameCallback;
28  import javax.security.auth.callback.PasswordCallback;
29  import javax.security.auth.callback.UnsupportedCallbackException;
30  import javax.security.auth.login.LoginContext;
31  import javax.security.auth.login.LoginException;
32  
33  import org.eclipse.jetty.plus.jaas.callback.ObjectCallback;
34  import org.eclipse.jetty.security.DefaultIdentityService;
35  import org.eclipse.jetty.security.IdentityService;
36  import org.eclipse.jetty.security.LoginService;
37  import org.eclipse.jetty.server.UserIdentity;
38  import org.eclipse.jetty.util.Loader;
39  import org.eclipse.jetty.util.component.AbstractLifeCycle;
40  import org.eclipse.jetty.util.log.Log;
41  
42  /* ---------------------------------------------------- */
43  /** JAASLoginService
44   * 
45   * @org.apache.xbean.XBean element="jaasUserRealm" description="Creates a UserRealm suitable for use with JAAS"
46   */
47  public class JAASLoginService extends AbstractLifeCycle implements LoginService
48  {
49      public static String DEFAULT_ROLE_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASRole";
50      public static String[] DEFAULT_ROLE_CLASS_NAMES = {DEFAULT_ROLE_CLASS_NAME};
51  	
52      protected String[] _roleClassNames = DEFAULT_ROLE_CLASS_NAMES;
53      protected String _callbackHandlerClass;
54      protected String _realmName;
55      protected String _loginModuleName;
56      protected JAASUserPrincipal _defaultUser = new JAASUserPrincipal(null, null, null);
57      protected IdentityService _identityService;
58   
59      /* ---------------------------------------------------- */
60      /**
61       * Constructor.
62       *
63       */
64      public JAASLoginService()
65      {
66      }
67      
68  
69      /* ---------------------------------------------------- */
70      /**
71       * Constructor.
72       *
73       * @param name the name of the realm
74       */
75      public JAASLoginService(String name)
76      {
77          this();
78          _realmName = name;
79          _loginModuleName = name;
80      }
81  
82  
83      /* ---------------------------------------------------- */
84      /**
85       * Get the name of the realm.
86       *
87       * @return name or null if not set.
88       */
89      public String getName()
90      {
91          return _realmName;
92      }
93  
94  
95      /* ---------------------------------------------------- */
96      /**
97       * Set the name of the realm
98       *
99       * @param name a <code>String</code> value
100      */
101     public void setName (String name)
102     {
103         _realmName = name;
104     }
105 
106     /* ------------------------------------------------------------ */
107     /** Get the identityService.
108      * @return the identityService
109      */
110     public IdentityService getIdentityService()
111     {
112         return _identityService;
113     }
114 
115     /* ------------------------------------------------------------ */
116     /** Set the identityService.
117      * @param identityService the identityService to set
118      */
119     public void setIdentityService(IdentityService identityService)
120     {
121         _identityService = identityService;
122     }
123 
124     /* ------------------------------------------------------------ */
125     /**
126      * Set the name to use to index into the config
127      * file of LoginModules.
128      *
129      * @param name a <code>String</code> value
130      */
131     public void setLoginModuleName (String name)
132     {
133         _loginModuleName = name;
134     }
135 
136     /* ------------------------------------------------------------ */
137     public void setCallbackHandlerClass (String classname)
138     {
139         _callbackHandlerClass = classname;
140     }
141 
142     /* ------------------------------------------------------------ */
143     public void setRoleClassNames (String[] classnames)
144     {
145         ArrayList<String> tmp = new ArrayList<String>();
146         
147         if (classnames != null)
148             tmp.addAll(Arrays.asList(classnames));
149          
150         if (!tmp.contains(DEFAULT_ROLE_CLASS_NAME))
151             tmp.add(DEFAULT_ROLE_CLASS_NAME);
152         _roleClassNames = tmp.toArray(new String[tmp.size()]);
153     }
154 
155     /* ------------------------------------------------------------ */
156     public String[] getRoleClassNames()
157     {
158         return _roleClassNames;
159     }
160 
161     /* ------------------------------------------------------------ */
162     /**
163      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
164      */
165     protected void doStart() throws Exception
166     {
167         if (_identityService==null)
168             _identityService=new DefaultIdentityService();
169         super.doStart();
170     }
171 
172     /* ------------------------------------------------------------ */
173     public UserIdentity login(final String username,final Object credentials)
174     {
175         try
176         {
177             CallbackHandler callbackHandler = null;
178             
179             
180             if (_callbackHandlerClass == null)
181             {
182                 callbackHandler = new CallbackHandler()
183                 {
184                     public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
185                     {
186                         for (Callback callback: callbacks)
187                         {
188                             if (callback instanceof NameCallback)
189                             {
190                                 ((NameCallback)callback).setName(username);
191                             }
192                             else if (callback instanceof PasswordCallback)
193                             {
194                                 ((PasswordCallback)callback).setPassword((char[]) credentials.toString().toCharArray());
195                             }
196                             else if (callback instanceof ObjectCallback)
197                             {
198                                 ((ObjectCallback)callback).setObject(credentials);
199                             }
200                         }
201                     }
202                 };
203             }
204             else
205             {
206                 Class clazz = Loader.loadClass(getClass(), _callbackHandlerClass);
207                 callbackHandler = (CallbackHandler)clazz.newInstance();
208             }
209             //set up the login context
210             //TODO jaspi requires we provide the Configuration parameter
211             Subject subject = new Subject();
212             LoginContext loginContext = new LoginContext(_loginModuleName, subject, callbackHandler);
213 
214             loginContext.login();
215 
216             //login success
217             JAASUserPrincipal userPrincipal = new JAASUserPrincipal(getUserName(callbackHandler), subject, loginContext);
218             subject.getPrincipals().add(userPrincipal);
219             
220             return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject));
221         }
222         catch (LoginException e)
223         {
224             Log.warn(e);
225         }
226         catch (IOException e)
227         {
228             Log.warn(e);
229         }
230         catch (UnsupportedCallbackException e)
231         {
232            Log.warn(e);
233         }
234         catch (InstantiationException e)
235         {
236             Log.warn(e);
237         }
238         catch (IllegalAccessException e)
239         {
240             Log.warn(e);
241         }
242         catch (ClassNotFoundException e)
243         {
244             Log.warn(e);
245         }
246         return null;
247     }
248 
249     /* ------------------------------------------------------------ */
250     public boolean validate(UserIdentity user)
251     {
252         // TODO optionally check user is still valid
253         return true;
254     }
255 
256     /* ------------------------------------------------------------ */
257     private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException
258     {
259         NameCallback nameCallback = new NameCallback("foo");
260         callbackHandler.handle(new Callback[] {nameCallback});
261         return nameCallback.getName();
262     }
263 
264     /* ------------------------------------------------------------ */
265     public void logout(UserIdentity user)
266     {
267         Set<JAASUserPrincipal> userPrincipals = user.getSubject().getPrincipals(JAASUserPrincipal.class);
268         LoginContext loginContext = userPrincipals.iterator().next().getLoginContext();
269         try
270         {
271             loginContext.logout();
272         }
273         catch (LoginException e)
274         {
275             Log.warn(e);
276         }
277     }
278 
279 
280     /* ------------------------------------------------------------ */
281     @SuppressWarnings({ "unchecked", "rawtypes" })
282     private String[] getGroups (Subject subject)
283     {
284         //get all the roles of the various types
285         String[] roleClassNames = getRoleClassNames();
286         Collection<String> groups = new LinkedHashSet<String>();
287         try
288         {
289             for (String roleClassName : roleClassNames)
290             {
291                 Class load_class = Thread.currentThread().getContextClassLoader().loadClass(roleClassName);
292                 Set<Principal> rolesForType = subject.getPrincipals(load_class);
293                 for (Principal principal : rolesForType)
294                 {
295                     groups.add(principal.getName());
296                 }
297             }
298             
299             return groups.toArray(new String[groups.size()]);
300         }
301         catch (ClassNotFoundException e)
302         {
303             throw new RuntimeException(e);
304         }
305     }
306 
307 }