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