1 /* 2 * Copyright (c) 2000, 2006, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.security.auth.module; 27 28 import java.util.*; 29 import java.io.IOException; 30 import javax.security.auth.*; 31 import javax.security.auth.callback.*; 32 import javax.security.auth.login.*; 33 import javax.security.auth.spi.*; 34 import java.security.Principal; 35 import com.sun.security.auth.NTUserPrincipal; 36 import com.sun.security.auth.NTSidUserPrincipal; 37 import com.sun.security.auth.NTDomainPrincipal; 38 import com.sun.security.auth.NTSidDomainPrincipal; 39 import com.sun.security.auth.NTSidPrimaryGroupPrincipal; 40 import com.sun.security.auth.NTSidGroupPrincipal; 41 import com.sun.security.auth.NTNumericCredential; 42 43 /** 44 * <p> This <code>LoginModule</code> 45 * renders a user's NT security information as some number of 46 * <code>Principal</code>s 47 * and associates them with a <code>Subject</code>. 48 * 49 * <p> This LoginModule recognizes the debug option. 50 * If set to true in the login Configuration, 51 * debug messages will be output to the output stream, System.out. 52 * 53 * <p> This LoginModule also recognizes the debugNative option. 54 * If set to true in the login Configuration, 55 * debug messages from the native component of the module 56 * will be output to the output stream, System.out. 57 * 58 * @see javax.security.auth.spi.LoginModule 59 */ 60 public class NTLoginModule implements LoginModule { 61 62 private NTSystem ntSystem; 63 64 // initial state 65 private Subject subject; 66 private CallbackHandler callbackHandler; 67 private Map<String, ?> sharedState; 68 private Map<String, ?> options; 69 70 // configurable option 71 private boolean debug = false; 72 private boolean debugNative = false; 73 74 // the authentication status 75 private boolean succeeded = false; 76 private boolean commitSucceeded = false; 77 78 private NTUserPrincipal userPrincipal; // user name 79 private NTSidUserPrincipal userSID; // user SID 80 private NTDomainPrincipal userDomain; // user domain 81 private NTSidDomainPrincipal domainSID; // domain SID 82 private NTSidPrimaryGroupPrincipal primaryGroup; // primary group 83 private NTSidGroupPrincipal groups[]; // supplementary groups 84 private NTNumericCredential iToken; // impersonation token 85 86 /** 87 * Initialize this <code>LoginModule</code>. 88 * 89 * <p> 90 * 91 * @param subject the <code>Subject</code> to be authenticated. <p> 92 * 93 * @param callbackHandler a <code>CallbackHandler</code> for communicating 94 * with the end user (prompting for usernames and 95 * passwords, for example). This particular LoginModule only 96 * extracts the underlying NT system information, so this 97 * parameter is ignored.<p> 98 * 99 * @param sharedState shared <code>LoginModule</code> state. <p> 100 * 101 * @param options options specified in the login 102 * <code>Configuration</code> for this particular 103 * <code>LoginModule</code>. 104 */ 105 public void initialize(Subject subject, CallbackHandler callbackHandler, 106 Map<String,?> sharedState, 107 Map<String,?> options) 108 { 109 110 this.subject = subject; 111 this.callbackHandler = callbackHandler; 112 this.sharedState = sharedState; 113 this.options = options; 114 115 // initialize any configured options 116 debug = "true".equalsIgnoreCase((String)options.get("debug")); 117 debugNative="true".equalsIgnoreCase((String)options.get("debugNative")); 118 119 if (debugNative == true) { 120 debug = true; 121 } 122 } 123 124 /** 125 * Import underlying NT system identity information. 126 * 127 * <p> 128 * 129 * @return true in all cases since this <code>LoginModule</code> 130 * should not be ignored. 131 * 132 * @exception FailedLoginException if the authentication fails. <p> 133 * 134 * @exception LoginException if this <code>LoginModule</code> 135 * is unable to perform the authentication. 136 */ 137 public boolean login() throws LoginException { 138 139 succeeded = false; // Indicate not yet successful 140 141 ntSystem = new NTSystem(debugNative); 142 if (ntSystem == null) { 143 if (debug) { 144 System.out.println("\t\t[NTLoginModule] " + 145 "Failed in NT login"); 146 } 147 throw new FailedLoginException 148 ("Failed in attempt to import the " + 149 "underlying NT system identity information"); 150 } 151 152 if (ntSystem.getName() == null) { 153 throw new FailedLoginException 154 ("Failed in attempt to import the " + 155 "underlying NT system identity information"); 156 } 157 userPrincipal = new NTUserPrincipal(ntSystem.getName()); 158 if (debug) { 159 System.out.println("\t\t[NTLoginModule] " + 160 "succeeded importing info: "); 161 System.out.println("\t\t\tuser name = " + 162 userPrincipal.getName()); 163 } 164 165 if (ntSystem.getUserSID() != null) { 166 userSID = new NTSidUserPrincipal(ntSystem.getUserSID()); 167 if (debug) { 168 System.out.println("\t\t\tuser SID = " + 169 userSID.getName()); 170 } 171 } 172 if (ntSystem.getDomain() != null) { 173 userDomain = new NTDomainPrincipal(ntSystem.getDomain()); 174 if (debug) { 175 System.out.println("\t\t\tuser domain = " + 176 userDomain.getName()); 177 } 178 } 179 if (ntSystem.getDomainSID() != null) { 180 domainSID = 181 new NTSidDomainPrincipal(ntSystem.getDomainSID()); 182 if (debug) { 183 System.out.println("\t\t\tuser domain SID = " + 184 domainSID.getName()); 185 } 186 } 187 if (ntSystem.getPrimaryGroupID() != null) { 188 primaryGroup = 189 new NTSidPrimaryGroupPrincipal(ntSystem.getPrimaryGroupID()); 190 if (debug) { 191 System.out.println("\t\t\tuser primary group = " + 192 primaryGroup.getName()); 193 } 194 } 195 if (ntSystem.getGroupIDs() != null && 196 ntSystem.getGroupIDs().length > 0) { 197 198 String groupSIDs[] = ntSystem.getGroupIDs(); 199 groups = new NTSidGroupPrincipal[groupSIDs.length]; 200 for (int i = 0; i < groupSIDs.length; i++) { 201 groups[i] = new NTSidGroupPrincipal(groupSIDs[i]); 202 if (debug) { 203 System.out.println("\t\t\tuser group = " + 204 groups[i].getName()); 205 } 206 } 207 } 208 if (ntSystem.getImpersonationToken() != 0) { 209 iToken = new NTNumericCredential(ntSystem.getImpersonationToken()); 210 if (debug) { 211 System.out.println("\t\t\timpersonation token = " + 212 ntSystem.getImpersonationToken()); 213 } 214 } 215 216 succeeded = true; 217 return succeeded; 218 } 219 220 /** 221 * <p> This method is called if the LoginContext's 222 * overall authentication succeeded 223 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules 224 * succeeded). 225 * 226 * <p> If this LoginModule's own authentication attempt 227 * succeeded (checked by retrieving the private state saved by the 228 * <code>login</code> method), then this method associates some 229 * number of various <code>Principal</code>s 230 * with the <code>Subject</code> located in the 231 * <code>LoginModuleContext</code>. If this LoginModule's own 232 * authentication attempted failed, then this method removes 233 * any state that was originally saved. 234 * 235 * <p> 236 * 237 * @exception LoginException if the commit fails. 238 * 239 * @return true if this LoginModule's own login and commit 240 * attempts succeeded, or false otherwise. 241 */ 242 public boolean commit() throws LoginException { 243 if (succeeded == false) { 244 if (debug) { 245 System.out.println("\t\t[NTLoginModule]: " + 246 "did not add any Principals to Subject " + 247 "because own authentication failed."); 248 } 249 return false; 250 } 251 if (subject.isReadOnly()) { 252 throw new LoginException ("Subject is ReadOnly"); 253 } 254 Set<Principal> principals = subject.getPrincipals(); 255 256 // we must have a userPrincipal - everything else is optional 257 if (!principals.contains(userPrincipal)) { 258 principals.add(userPrincipal); 259 } 260 if (userSID != null && !principals.contains(userSID)) { 261 principals.add(userSID); 262 } 263 264 if (userDomain != null && !principals.contains(userDomain)) { 265 principals.add(userDomain); 266 } 267 if (domainSID != null && !principals.contains(domainSID)) { 268 principals.add(domainSID); 269 } 270 271 if (primaryGroup != null && !principals.contains(primaryGroup)) { 272 principals.add(primaryGroup); 273 } 274 for (int i = 0; groups != null && i < groups.length; i++) { 275 if (!principals.contains(groups[i])) { 276 principals.add(groups[i]); 277 } 278 } 279 280 Set<Object> pubCreds = subject.getPublicCredentials(); 281 if (iToken != null && !pubCreds.contains(iToken)) { 282 pubCreds.add(iToken); 283 } 284 commitSucceeded = true; 285 return true; 286 } 287 288 289 /** 290 * <p> This method is called if the LoginContext's 291 * overall authentication failed. 292 * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules 293 * did not succeed). 294 * 295 * <p> If this LoginModule's own authentication attempt 296 * succeeded (checked by retrieving the private state saved by the 297 * <code>login</code> and <code>commit</code> methods), 298 * then this method cleans up any state that was originally saved. 299 * 300 * <p> 301 * 302 * @exception LoginException if the abort fails. 303 * 304 * @return false if this LoginModule's own login and/or commit attempts 305 * failed, and true otherwise. 306 */ 307 public boolean abort() throws LoginException { 308 if (debug) { 309 System.out.println("\t\t[NTLoginModule]: " + 310 "aborted authentication attempt"); 311 } 312 313 if (succeeded == false) { 314 return false; 315 } else if (succeeded == true && commitSucceeded == false) { 316 ntSystem = null; 317 userPrincipal = null; 318 userSID = null; 319 userDomain = null; 320 domainSID = null; 321 primaryGroup = null; 322 groups = null; 323 iToken = null; 324 succeeded = false; 325 } else { 326 // overall authentication succeeded and commit succeeded, 327 // but someone else's commit failed 328 logout(); 329 } 330 return succeeded; 331 } 332 333 /** 334 * Logout the user. 335 * 336 * <p> This method removes the <code>NTUserPrincipal</code>, 337 * <code>NTDomainPrincipal</code>, <code>NTSidUserPrincipal</code>, 338 * <code>NTSidDomainPrincipal</code>, <code>NTSidGroupPrincipal</code>s, 339 * and <code>NTSidPrimaryGroupPrincipal</code> 340 * that may have been added by the <code>commit</code> method. 341 * 342 * <p> 343 * 344 * @exception LoginException if the logout fails. 345 * 346 * @return true in all cases since this <code>LoginModule</code> 347 * should not be ignored. 348 */ 349 public boolean logout() throws LoginException { 350 351 if (subject.isReadOnly()) { 352 throw new LoginException ("Subject is ReadOnly"); 353 } 354 Set<Principal> principals = subject.getPrincipals(); 355 if (principals.contains(userPrincipal)) { 356 principals.remove(userPrincipal); 357 } 358 if (principals.contains(userSID)) { 359 principals.remove(userSID); 360 } 361 if (principals.contains(userDomain)) { 362 principals.remove(userDomain); 363 } 364 if (principals.contains(domainSID)) { 365 principals.remove(domainSID); 366 } 367 if (principals.contains(primaryGroup)) { 368 principals.remove(primaryGroup); 369 } 370 for (int i = 0; groups != null && i < groups.length; i++) { 371 if (principals.contains(groups[i])) { 372 principals.remove(groups[i]); 373 } 374 } 375 376 Set<Object> pubCreds = subject.getPublicCredentials(); 377 if (pubCreds.contains(iToken)) { 378 pubCreds.remove(iToken); 379 } 380 381 succeeded = false; 382 commitSucceeded = false; 383 userPrincipal = null; 384 userDomain = null; 385 userSID = null; 386 domainSID = null; 387 groups = null; 388 primaryGroup = null; 389 iToken = null; 390 ntSystem = null; 391 392 if (debug) { 393 System.out.println("\t\t[NTLoginModule] " + 394 "completed logout processing"); 395 } 396 return true; 397 } 398 }