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