View Javadoc
1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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  package org.eclipse.jetty.jaas.spi;
20  
21  import java.io.IOException;
22  import java.security.Principal;
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.Map;
27  
28  import javax.security.auth.Subject;
29  import javax.security.auth.callback.Callback;
30  import javax.security.auth.callback.CallbackHandler;
31  import javax.security.auth.callback.NameCallback;
32  import javax.security.auth.callback.PasswordCallback;
33  import javax.security.auth.callback.UnsupportedCallbackException;
34  import javax.security.auth.login.FailedLoginException;
35  import javax.security.auth.login.LoginException;
36  import javax.security.auth.spi.LoginModule;
37  
38  import org.eclipse.jetty.jaas.JAASPrincipal;
39  import org.eclipse.jetty.jaas.JAASRole;
40  import org.eclipse.jetty.jaas.callback.ObjectCallback;
41  
42  /**
43   * AbstractLoginModule
44   *
45   * Abstract base class for all LoginModules. Subclasses should
46   * just need to implement getUserInfo method.
47   */
48  public abstract class AbstractLoginModule implements LoginModule
49  {
50      private CallbackHandler callbackHandler;
51  
52      private boolean authState = false;
53      private boolean commitState = false;
54      private JAASUserInfo currentUser;
55      private Subject subject;
56  
57      /**
58       * JAASUserInfo
59       *
60       * This class unites the UserInfo data with jaas concepts
61       * such as Subject and Principals
62       */
63      public class JAASUserInfo
64      {
65          private UserInfo user;
66          private Principal principal;
67          private List<JAASRole> roles;
68  
69          public JAASUserInfo (UserInfo u)
70          {
71              this.user = u;
72              this.principal = new JAASPrincipal(u.getUserName());
73          }
74  
75          public String getUserName ()
76          {
77              return this.user.getUserName();
78          }
79  
80          public Principal getPrincipal()
81          {
82              return this.principal;
83          }
84  
85   
86          public void setJAASInfo (Subject subject)
87          {
88              subject.getPrincipals().add(this.principal);
89              subject.getPrivateCredentials().add(this.user.getCredential());
90              subject.getPrincipals().addAll(roles);
91          }
92  
93          public void unsetJAASInfo (Subject subject)
94          {
95              subject.getPrincipals().remove(this.principal);
96              subject.getPrivateCredentials().remove(this.user.getCredential());
97              subject.getPrincipals().removeAll(this.roles);
98          }
99  
100         public boolean checkCredential (Object suppliedCredential)
101         {
102             return this.user.checkCredential(suppliedCredential);
103         }
104         
105         public void fetchRoles() throws Exception
106         {
107             this.user.fetchRoles();
108             this.roles = new ArrayList<JAASRole>();
109             if (this.user.getRoleNames() != null)
110             {
111                 Iterator<String> itor = this.user.getRoleNames().iterator();
112                 while (itor.hasNext())
113                     this.roles.add(new JAASRole((String)itor.next()));
114             }
115         }
116     }
117 
118     public Subject getSubject ()
119     {
120         return this.subject;
121     }
122 
123     public void setSubject (Subject s)
124     {
125         this.subject = s;
126     }
127 
128     public JAASUserInfo getCurrentUser()
129     {
130         return this.currentUser;
131     }
132 
133     public void setCurrentUser (JAASUserInfo u)
134     {
135         this.currentUser = u;
136     }
137 
138     public CallbackHandler getCallbackHandler()
139     {
140         return this.callbackHandler;
141     }
142 
143     public void setCallbackHandler(CallbackHandler h)
144     {
145         this.callbackHandler = h;
146     }
147 
148     public boolean isAuthenticated()
149     {
150         return this.authState;
151     }
152 
153     public boolean isCommitted ()
154     {
155         return this.commitState;
156     }
157 
158     public void setAuthenticated (boolean authState)
159     {
160         this.authState = authState;
161     }
162 
163     public void setCommitted (boolean commitState)
164     {
165         this.commitState = commitState;
166     }
167     /**
168      * @see javax.security.auth.spi.LoginModule#abort()
169      * @throws LoginException if unable to abort
170      */
171     public boolean abort() throws LoginException
172     {
173         this.currentUser = null;
174         return (isAuthenticated() && isCommitted());
175     }
176 
177     /**
178      * @see javax.security.auth.spi.LoginModule#commit()
179      * @return true if committed, false if not (likely not authenticated)
180      * @throws LoginException if unable to commit
181      */
182     public boolean commit() throws LoginException
183     {
184         if (!isAuthenticated())
185         {
186             currentUser = null;
187             setCommitted(false);
188             return false;
189         }
190 
191         setCommitted(true);
192         currentUser.setJAASInfo(subject);
193         return true;
194     }
195 
196 
197     public Callback[] configureCallbacks ()
198     {
199 
200         Callback[] callbacks = new Callback[3];
201         callbacks[0] = new NameCallback("Enter user name");
202         callbacks[1] = new ObjectCallback();
203         callbacks[2] = new PasswordCallback("Enter password", false); //only used if framework does not support the ObjectCallback
204         return callbacks;
205     }
206     
207     
208     public boolean isIgnored ()
209     {
210         return false;
211     }
212     
213     
214     public abstract UserInfo getUserInfo (String username) throws Exception;
215 
216 
217 
218     /**
219      * @see javax.security.auth.spi.LoginModule#login()
220      * @return true if is authenticated, false otherwise
221      * @throws LoginException if unable to login
222      */
223     public boolean login() throws LoginException
224     {
225         try
226         {  
227             if (isIgnored())
228                 return false;
229             
230             if (callbackHandler == null)
231                 throw new LoginException ("No callback handler");
232 
233             Callback[] callbacks = configureCallbacks();
234             callbackHandler.handle(callbacks);
235 
236             String webUserName = ((NameCallback)callbacks[0]).getName();
237             Object webCredential = null;
238 
239             webCredential = ((ObjectCallback)callbacks[1]).getObject(); //first check if ObjectCallback has the credential
240             if (webCredential == null)
241                 webCredential = ((PasswordCallback)callbacks[2]).getPassword(); //use standard PasswordCallback
242 
243             if ((webUserName == null) || (webCredential == null))
244             {
245                 setAuthenticated(false);
246                 throw new FailedLoginException();
247             }
248 
249             UserInfo userInfo = getUserInfo(webUserName);
250 
251             if (userInfo == null)
252             {
253                 setAuthenticated(false);
254                 throw new FailedLoginException();
255             }
256 
257             currentUser = new JAASUserInfo(userInfo);
258             setAuthenticated(currentUser.checkCredential(webCredential));
259           
260             if (isAuthenticated())
261             {
262                 currentUser.fetchRoles();
263                 return true;
264             }
265             else
266                 throw new FailedLoginException();
267         }
268         catch (IOException e)
269         {
270             throw new LoginException (e.toString());
271         }
272         catch (UnsupportedCallbackException e)
273         {
274             throw new LoginException (e.toString());
275         }
276         catch (Exception e)
277         {
278             if (e instanceof LoginException)
279                 throw (LoginException)e;
280             throw new LoginException (e.toString());
281         }
282     }
283 
284     /**
285      * @see javax.security.auth.spi.LoginModule#logout()
286      * @return true always
287      * @throws LoginException if unable to logout
288      */
289     public boolean logout() throws LoginException
290     {
291         this.currentUser.unsetJAASInfo(this.subject);
292         this.currentUser = null;
293         return true;
294     }
295 
296     /**
297      * @see javax.security.auth.spi.LoginModule#initialize(javax.security.auth.Subject, javax.security.auth.callback.CallbackHandler, java.util.Map, java.util.Map)
298      * @param subject the subject
299      * @param callbackHandler the callback handler
300      * @param sharedState the shared state map
301      * @param options the option map
302      */
303     public void initialize(Subject subject, CallbackHandler callbackHandler,
304             Map<String,?> sharedState, Map<String,?> options)
305     {
306         this.callbackHandler = callbackHandler;
307         this.subject = subject;
308     }
309 
310 }