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