View Javadoc

1   /*
2    * $Id: DefaultLoginModule.java 8467 2007-09-18 11:44:20Z marie.rizzo $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSource, Inc.  All rights reserved.  http://www.mulesource.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.extras.jaas.loginmodule;
12  
13  import org.mule.extras.jaas.MuleJaasPrincipal;
14  
15  import java.io.IOException;
16  import java.util.List;
17  import java.util.Map;
18  import java.util.Set;
19  import java.util.Vector;
20  
21  import javax.security.auth.Subject;
22  import javax.security.auth.callback.Callback;
23  import javax.security.auth.callback.CallbackHandler;
24  import javax.security.auth.callback.NameCallback;
25  import javax.security.auth.callback.PasswordCallback;
26  import javax.security.auth.callback.UnsupportedCallbackException;
27  import javax.security.auth.login.FailedLoginException;
28  import javax.security.auth.login.LoginException;
29  import javax.security.auth.spi.LoginModule;
30  
31  /**
32   * This is the Default Login Module for the Mule Jaas Authentication.
33   * It extends Jaas' own LoginModule interface.
34   */
35  public class DefaultLoginModule implements LoginModule
36  {
37  
38      // Callback Handlers
39      private CallbackHandler callbackHandler;
40  
41      // the authentication status
42      private boolean succeeded = false;
43      private boolean commitSucceeded = false;
44  
45      // username and password
46      private String username;
47      private String password;
48      private String credentials;
49      private List credentialList;
50      private Subject subject;
51  
52      /**
53       * Abort if authentication fails
54       * 
55       * @return boolean
56       * @throws LoginException
57       */
58      public final boolean abort() throws LoginException
59      {
60          if (!succeeded)
61          {
62              return false;
63          }
64          else if (succeeded && !commitSucceeded)
65          {
66              // login succeeded but overall authentication failed
67              succeeded = false;
68              username = null;
69              if (password != null)
70              {
71                  password = null;
72              }
73          }
74          else
75          {
76              // overall authentication succeeded and commit succeeded,
77              // but someone else's commit failed
78              logout();
79          }
80          return true;
81      }
82  
83      /**
84       * Commit if authentication succeeds, otherwise return false
85       * 
86       * @return boolean
87       * @throws LoginException
88       */
89      public final boolean commit() throws LoginException
90      {
91          if (!succeeded)
92          {
93              return false;
94          }
95          else
96          {
97              // set the principal just authenticated in the subject
98              if (subject == null) 
99              {
100                 return false;
101             }
102             MuleJaasPrincipal principal = new MuleJaasPrincipal(username); 
103             Set entities = subject.getPrincipals();
104             if (!entities.contains(principal))
105             {
106               entities.add(principal);
107             }
108 
109             // in any case, clean out state
110             username = null;
111             password = null;
112             commitSucceeded = true;
113             return true;
114         }
115     }
116     
117     /**
118      * Initialises the callbackHandler, the credentials and the credentials list
119      * 
120      * @param subject
121      * @param callbackHandler
122      * @param sharedState
123      * @param options
124      */
125     public final void initialize(Subject subject,
126                                  CallbackHandler callbackHandler,
127                                  Map sharedState,
128                                  Map options)
129     {
130         this.subject = subject;
131         this.callbackHandler = callbackHandler;
132 
133         this.credentials = (String) options.get("credentials");
134         this.credentialList = getCredentialList(this.credentials);
135     }
136 
137     /**
138      * This method attempts to login the user by checking his credentials against
139      * those of the authorised users.
140      * 
141      * @throws LoginException This is thrown either when there is no callback Handler
142      *             or else when the user fails to be authenticated
143      */
144     public final boolean login() throws LoginException
145     {
146         if (callbackHandler == null)
147         {
148             throw new LoginException("Error: no CallbackHandler available "
149                                      + "to garner authentication information from the user");
150         }
151 
152         if (callbackHandler == null)
153         {
154             throw new LoginException("no handler");
155         }
156 
157         NameCallback nameCb = new NameCallback("user: ");
158         PasswordCallback passCb = new PasswordCallback("password: ", true);
159 
160         // Create the callbacks to send to the Callback Handler
161         Callback[] callbacks = new Callback[]{nameCb, passCb};
162 
163         // Call the handler to get the username and password of the user.
164         try
165         {
166             callbackHandler.handle(callbacks);
167         }
168         catch (IOException e)
169         {
170             throw new LoginException(e.toString());
171         }
172         catch (UnsupportedCallbackException e)
173         {
174             throw new LoginException("Error: " + e.getCallback().toString()
175                                      + " not available to garner authentication information "
176                                      + "from the user");
177         }
178 
179         username = nameCb.getName();
180         password = new String(passCb.getPassword());
181 
182         boolean usernameCorrect = false;
183         boolean passwordCorrect = false;
184         succeeded = false;
185 
186         // check the username and password against the list of authorised users
187         for (int i = 0; i < credentialList.size(); i = i + 2)
188         {
189             if (username.equals(credentialList.get(i).toString()))
190             {
191                 usernameCorrect = true;
192             }
193             else
194             {
195                 usernameCorrect = false;
196             }
197 
198             if (password.equals(credentialList.get(i + 1).toString()))
199             {
200                 passwordCorrect = true;
201             }
202             else
203             {
204                 passwordCorrect = false;
205             }
206 
207             // only if both the username and password are correct will the user be
208             // authenticated
209             if ((usernameCorrect) & (passwordCorrect))
210             {
211                 succeeded = true;
212             }
213         }
214 
215         if (succeeded)
216         {
217             return true;
218         }
219         else
220         {
221             succeeded = false;
222             username = null;
223             password = null;
224             if (!usernameCorrect)
225             {
226                 throw new FailedLoginException("User Name Incorrect");
227             }
228             else
229             {
230                 throw new FailedLoginException("Password Incorrect");
231             }
232         }
233     }
234     
235     /**
236      * Returns true when authentication succeeds or false when it fails
237      * 
238      * @return succeeded
239      */
240     public final boolean logout()
241     {
242         return succeeded;
243     }
244 
245     /**
246      * This method parses the credentials string and populates the credentials list
247      * against which the username and password submitted with the request will be
248      * checked
249      * 
250      * @param credentials
251      * @return outputList
252      */
253     public final List getCredentialList(String credentials)
254     {
255         boolean semicolonIsFound = false;
256         boolean dividerIsFound = false;
257         char[] credentialArray = credentials.toCharArray();
258         String username = "";
259         String password = "";
260         List outputList = new Vector();
261 
262         for (int i = 0; i < credentials.length(); i++)
263         {
264             if ((credentialArray[i] != ':') && (!dividerIsFound))
265             {
266                 username = username + credentialArray[i];
267             }
268             else if ((credentialArray[i] == ':') && (!dividerIsFound))
269             {
270                 dividerIsFound = true;
271             }
272             else if ((credentialArray[i] != ';') && (!semicolonIsFound) && (dividerIsFound))
273             {
274                 password = password + credentialArray[i];
275             }
276             else if ((credentialArray[i] != ';') && (!semicolonIsFound) && (dividerIsFound))
277             {
278                 password = password + credentialArray[i];
279             }
280             else if ((credentialArray[i] == ';') && (!semicolonIsFound) && (dividerIsFound))
281             {
282                 outputList.add(username);
283                 outputList.add(password);
284                 semicolonIsFound = false;
285                 dividerIsFound = false;
286                 username = "";
287                 password = "";
288             }
289         }
290         return outputList;
291     }
292 }