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