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