1 /*
2  * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.security.Principal;
25 import java.util.Arrays;
26 import java.util.Map;
27 import javax.security.auth.Subject;
28 import javax.security.auth.callback.Callback;
29 import javax.security.auth.callback.CallbackHandler;
30 import javax.security.auth.callback.NameCallback;
31 import javax.security.auth.callback.PasswordCallback;
32 import javax.security.auth.callback.UnsupportedCallbackException;
33 import javax.security.auth.login.FailedLoginException;
34 import javax.security.auth.login.LoginException;
35 import javax.security.auth.spi.LoginModule;
36 
37 /**
38  * This code was based on JAAS demo code, small modification is made for testing
39  * purpose.
40  */
41 public class SmartLoginModule implements LoginModule {
42 
43     // initial state
44     private Subject subject;
45     private CallbackHandler callbackHandler;
46 
47     // the authentication status
48     private boolean succeeded = false;
49     private boolean commitSucceeded = false;
50 
51     // username and password
52     private String username;
53     private char[] password;
54 
55     // Default values for this login module. In real world,
56     // don't do it in this way!
57     private String myUsername;
58     private char[] myPassword;
59     private String header;
60 
61     // testUser's SamplePrincipal
62     private SamplePrincipal userPrincipal;
63 
SmartLoginModule()64     public SmartLoginModule() {
65         this("testUser",
66                 new char[]{'t', 'e', 's', 't', 'P', 'a', 's', 's',
67                     'w', 'o', 'r', 'd', '1'},
68                 "SmartLoginModule1: ");
69     }
70 
SmartLoginModule(String userName, char[] password, String header)71     public SmartLoginModule(String userName, char[] password, String header) {
72         myUsername = userName;
73         myPassword = password;
74         this.header = header;
75     }
76 
77     @Override
abort()78     public boolean abort() throws LoginException {
79         if (!succeeded) {
80             return false;
81         } else if (succeeded && !commitSucceeded) {
82             // login succeeded but overall authentication failed
83             succeeded = false;
84             username = null;
85             password = null;
86             userPrincipal = null;
87         } else {
88             // overall authentication succeeded and commit succeeded,
89             // but someone else's commit failed
90             logout();
91         }
92         return true;
93     }
94 
95     @Override
commit()96     public boolean commit() throws LoginException {
97         if (!succeeded) {
98             return false;
99         } else {
100             // add a Principal (authenticated identity) to the Subject
101             // assume the user we authenticated is the SamplePrincipal
102             userPrincipal = new SamplePrincipal(username);
103             if (!subject.getPrincipals().contains(userPrincipal)) {
104                 subject.getPrincipals().add(userPrincipal);
105             }
106             // in any case, clean out state
107             username = null;
108             password = null;
109             commitSucceeded = true;
110             return true;
111         }
112     }
113 
114     @Override
initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState, Map<String, ?> options)115     public void initialize(Subject subject, CallbackHandler callbackHandler,
116             Map<String, ?> sharedState, Map<String, ?> options) {
117         this.subject = subject;
118         this.callbackHandler = callbackHandler;
119     }
120 
121     @Override
login()122     public boolean login() throws LoginException {
123         if (callbackHandler == null) {
124             throw new LoginException("Error: no CallbackHandler available to "
125                     + "garner authentication information from the user");
126         }
127 
128         Callback[] callbacks = new Callback[2];
129         callbacks[0] = new NameCallback(header + "user name: ");
130         callbacks[1] = new PasswordCallback(header + "password: ", false);
131 
132         try {
133             callbackHandler.handle(callbacks);
134             username = ((NameCallback) callbacks[0]).getName();
135             char[] tmpPassword
136                     = ((PasswordCallback) callbacks[1]).getPassword();
137             if (tmpPassword == null) {
138                 tmpPassword = new char[0];
139             }
140             password = new char[tmpPassword.length];
141             System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);
142             ((PasswordCallback) callbacks[1]).clearPassword();
143         } catch (java.io.IOException ioe) {
144             throw (LoginException) new LoginException().initCause(ioe);
145         } catch (UnsupportedCallbackException uce) {
146             throw new LoginException("Error: " + header
147                     + uce.getCallback().toString()
148                     + " not available to garner authentication information "
149                     + "from the user");
150         }
151 
152         // verify the username/password
153         if (username.equals(myUsername)
154                 && Arrays.equals(password, myPassword)) {
155             System.out.println("\t\t" + header + " authentication succeeded");
156             succeeded = true;
157             return true;
158         } else {
159             // authentication failed -- clean out state
160             System.out.println("\t\t" + header + " authentication failed");
161             printDebugInfo();
162             succeeded = false;
163             username = null;
164             password = null;
165             throw new FailedLoginException("User Name or Password Incorrect");
166         }
167     }
168 
169     @Override
logout()170     public boolean logout() throws LoginException {
171         subject.getPrincipals().remove(userPrincipal);
172         succeeded = false;
173         succeeded = commitSucceeded;
174         username = null;
175         password = null;
176         userPrincipal = null;
177         return true;
178     }
179 
180     // print debugging information
printDebugInfo()181     private void printDebugInfo() {
182         System.out.println("\t\t" + header + " correct user name: "
183                 + myUsername);
184         System.out.println("\t\t" + header + " user entered user name: "
185                 + username);
186         System.out.print("\t\t" + header + " correct password: ");
187         for (char c : myPassword) {
188             System.out.print(c);
189         }
190         System.out.println();
191         System.out.print("\t\t" + header + " user entered password: ");
192         for (char c : password) {
193             System.out.print(c);
194         }
195         System.out.println();
196     }
197 }
198 
199 class SamplePrincipal implements Principal, java.io.Serializable {
200 
201     /**
202      * @serial
203      */
204     private String name;
205 
206     /**
207      * Create a SamplePrincipal with a Sample username.
208      *
209      * @param name the Sample username for this user.
210      * @exception NullPointerException if the <code>name</code> is
211      * <code>null</code>.
212      */
SamplePrincipal(String name)213     public SamplePrincipal(String name) {
214         if (name == null) {
215             throw new NullPointerException("illegal null input");
216         }
217 
218         this.name = name;
219     }
220 
221     @Override
getName()222     public String getName() {
223         return name;
224     }
225 
226     @Override
toString()227     public String toString() {
228         return "SamplePrincipal:  " + name;
229     }
230 
231     @Override
equals(Object o)232     public boolean equals(Object o) {
233         if (o == null) {
234             return false;
235         }
236 
237         if (this == o) {
238             return true;
239         }
240 
241         if (!(o instanceof SamplePrincipal)) {
242             return false;
243         }
244         SamplePrincipal that = (SamplePrincipal) o;
245 
246         return this.getName().equals(that.getName());
247     }
248 
249     @Override
hashCode()250     public int hashCode() {
251         return name.hashCode();
252     }
253 }
254