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 
107     /* ------------------------------------------------------------ */
108     /** Get the identityService.
109      * @return the identityService
110      */
111     public IdentityService getIdentityService()
112     {
113         return _identityService;
114     }
115 
116 
117     /* ------------------------------------------------------------ */
118     /** Set the identityService.
119      * @param identityService the identityService to set
120      */
121     public void setIdentityService(IdentityService identityService)
122     {
123         _identityService = identityService;
124     }
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     /* ------------------------------------------------------------ */
141     public void setCallbackHandlerClass (String classname)
142     {
143         _callbackHandlerClass = classname;
144     }
145 
146     /* ------------------------------------------------------------ */
147     public void setRoleClassNames (String[] classnames)
148     {
149         ArrayList<String> tmp = new ArrayList<String>();
150         
151         if (classnames != null)
152             tmp.addAll(Arrays.asList(classnames));
153          
154         if (!tmp.contains(DEFAULT_ROLE_CLASS_NAME))
155             tmp.add(DEFAULT_ROLE_CLASS_NAME);
156         _roleClassNames = tmp.toArray(new String[tmp.size()]);
157     }
158 
159     /* ------------------------------------------------------------ */
160     public String[] getRoleClassNames()
161     {
162         return _roleClassNames;
163     }
164 
165     /* ------------------------------------------------------------ */
166     /**
167      * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
168      */
169     protected void doStart() throws Exception
170     {
171         if (_identityService==null)
172             _identityService=new DefaultIdentityService();
173         super.doStart();
174     }
175 
176     /* ------------------------------------------------------------ */
177     public UserIdentity login(final String username,final Object credentials)
178     {
179         try
180         {
181             CallbackHandler callbackHandler = new CallbackHandler()
182             {
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             //set up the login context
204             //TODO jaspi requires we provide the Configuration parameter
205             Subject subject = new Subject();
206             LoginContext loginContext = new LoginContext(_loginModuleName, subject, callbackHandler);
207 
208             loginContext.login();
209 
210             //login success
211             JAASUserPrincipal userPrincipal = new JAASUserPrincipal(getUserName(callbackHandler), subject, loginContext);
212             subject.getPrincipals().add(userPrincipal);
213             
214             return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject));
215         }
216         catch (LoginException e)
217         {
218             Log.warn(e);
219         }
220         catch (IOException e)
221         {
222             Log.warn(e);
223         }
224         catch (UnsupportedCallbackException e)
225         {
226            Log.warn(e);
227         }
228         return null;
229     }
230 
231     /* ------------------------------------------------------------ */
232     private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException
233     {
234         NameCallback nameCallback = new NameCallback("foo");
235         callbackHandler.handle(new Callback[] {nameCallback});
236         return nameCallback.getName();
237     }
238 
239     /* ------------------------------------------------------------ */
240     public void logout(UserIdentity user)
241     {
242         Set<JAASUserPrincipal> userPrincipals = user.getSubject().getPrincipals(JAASUserPrincipal.class);
243         LoginContext loginContext = userPrincipals.iterator().next().getLoginContext();
244         try
245         {
246             loginContext.logout();
247         }
248         catch (LoginException e)
249         {
250             Log.warn(e);
251         }
252     }
253 
254 
255     /* ------------------------------------------------------------ */
256     private String[] getGroups (Subject subject)
257     {
258         //get all the roles of the various types
259         String[] roleClassNames = getRoleClassNames();
260         Collection<String> groups = new LinkedHashSet<String>();
261         try
262         {
263             for (String roleClassName : roleClassNames)
264             {
265                 Class load_class = Thread.currentThread().getContextClassLoader().loadClass(roleClassName);
266                 Set<Principal> rolesForType = subject.getPrincipals(load_class);
267                 for (Principal principal : rolesForType)
268                 {
269                     groups.add(principal.getName());
270                 }
271             }
272             
273             return groups.toArray(new String[groups.size()]);
274         }
275         catch (ClassNotFoundException e)
276         {
277             throw new RuntimeException(e);
278         }
279     }
280 
281 }