1. /*
  2. * @(#)NTLoginModule.java 1.8 03/01/23
  3. *
  4. * Copyright 2003 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.8, 01/23/03
  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 sharedState, Map options) {
  80. this.subject = subject;
  81. this.callbackHandler = callbackHandler;
  82. this.sharedState = sharedState;
  83. this.options = options;
  84. // initialize any configured options
  85. debug = "true".equalsIgnoreCase((String)options.get("debug"));
  86. debugNative="true".equalsIgnoreCase((String)options.get("debugNative"));
  87. if (debugNative == true) {
  88. debug = true;
  89. }
  90. }
  91. /**
  92. * Import underlying NT system identity information.
  93. *
  94. * <p>
  95. *
  96. * @return true in all cases since this <code>LoginModule</code>
  97. * should not be ignored.
  98. *
  99. * @exception FailedLoginException if the authentication fails. <p>
  100. *
  101. * @exception LoginException if this <code>LoginModule</code>
  102. * is unable to perform the authentication.
  103. */
  104. public boolean login() throws LoginException {
  105. succeeded = false; // Indicate not yet successful
  106. ntSystem = new NTSystem(debugNative);
  107. if (ntSystem == null) {
  108. if (debug) {
  109. System.out.println("\t\t[NTLoginModule] " +
  110. "Failed in NT login");
  111. }
  112. throw new FailedLoginException
  113. ("Failed in attempt to import the " +
  114. "underlying NT system identity information");
  115. }
  116. if (ntSystem.getName() == null) {
  117. throw new FailedLoginException
  118. ("Failed in attempt to import the " +
  119. "underlying NT system identity information");
  120. }
  121. userPrincipal = new NTUserPrincipal(ntSystem.getName());
  122. if (debug) {
  123. System.out.println("\t\t[NTLoginModule] " +
  124. "succeeded importing info: ");
  125. System.out.println("\t\t\tuser name = " +
  126. userPrincipal.getName());
  127. }
  128. if (ntSystem.getUserSID() != null) {
  129. userSID = new NTSidUserPrincipal(ntSystem.getUserSID());
  130. if (debug) {
  131. System.out.println("\t\t\tuser SID = " +
  132. userSID.getName());
  133. }
  134. }
  135. if (ntSystem.getDomain() != null) {
  136. userDomain = new NTDomainPrincipal(ntSystem.getDomain());
  137. if (debug) {
  138. System.out.println("\t\t\tuser domain = " +
  139. userDomain.getName());
  140. }
  141. }
  142. if (ntSystem.getDomainSID() != null) {
  143. domainSID =
  144. new NTSidDomainPrincipal(ntSystem.getDomainSID());
  145. if (debug) {
  146. System.out.println("\t\t\tuser domain SID = " +
  147. domainSID.getName());
  148. }
  149. }
  150. if (ntSystem.getPrimaryGroupID() != null) {
  151. primaryGroup =
  152. new NTSidPrimaryGroupPrincipal(ntSystem.getPrimaryGroupID());
  153. if (debug) {
  154. System.out.println("\t\t\tuser primary group = " +
  155. primaryGroup.getName());
  156. }
  157. }
  158. if (ntSystem.getGroupIDs() != null &&
  159. ntSystem.getGroupIDs().length > 0) {
  160. String groupSIDs[] = ntSystem.getGroupIDs();
  161. groups = new NTSidGroupPrincipal[groupSIDs.length];
  162. for (int i = 0; i < groupSIDs.length; i++) {
  163. groups[i] = new NTSidGroupPrincipal(groupSIDs[i]);
  164. if (debug) {
  165. System.out.println("\t\t\tuser group = " +
  166. groups[i].getName());
  167. }
  168. }
  169. }
  170. if (ntSystem.getImpersonationToken() != 0) {
  171. iToken = new NTNumericCredential(ntSystem.getImpersonationToken());
  172. if (debug) {
  173. System.out.println("\t\t\timpersonation token = " +
  174. ntSystem.getImpersonationToken());
  175. }
  176. }
  177. succeeded = true;
  178. return succeeded;
  179. }
  180. /**
  181. * <p> This method is called if the LoginContext's
  182. * overall authentication succeeded
  183. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
  184. * succeeded).
  185. *
  186. * <p> If this LoginModule's own authentication attempt
  187. * succeeded (checked by retrieving the private state saved by the
  188. * <code>login</code> method), then this method associates some
  189. * number of various <code>Principal</code>s
  190. * with the <code>Subject</code> located in the
  191. * <code>LoginModuleContext</code>. If this LoginModule's own
  192. * authentication attempted failed, then this method removes
  193. * any state that was originally saved.
  194. *
  195. * <p>
  196. *
  197. * @exception LoginException if the commit fails.
  198. *
  199. * @return true if this LoginModule's own login and commit
  200. * attempts succeeded, or false otherwise.
  201. */
  202. public boolean commit() throws LoginException {
  203. if (succeeded == false) {
  204. if (debug) {
  205. System.out.println("\t\t[NTLoginModule]: " +
  206. "did not add any Principals to Subject " +
  207. "because own authentication failed.");
  208. }
  209. return false;
  210. }
  211. if (subject.isReadOnly()) {
  212. throw new LoginException ("Subject is ReadOnly");
  213. }
  214. Set principals = subject.getPrincipals();
  215. // we must have a userPrincipal - everything else is optional
  216. if (!principals.contains(userPrincipal)) {
  217. principals.add(userPrincipal);
  218. }
  219. if (userSID != null && !principals.contains(userSID)) {
  220. principals.add(userSID);
  221. }
  222. if (userDomain != null && !principals.contains(userDomain)) {
  223. principals.add(userDomain);
  224. }
  225. if (domainSID != null && !principals.contains(domainSID)) {
  226. principals.add(domainSID);
  227. }
  228. if (primaryGroup != null && !principals.contains(primaryGroup)) {
  229. principals.add(primaryGroup);
  230. }
  231. for (int i = 0; groups != null && i < groups.length; i++) {
  232. if (!principals.contains(groups[i])) {
  233. principals.add(groups[i]);
  234. }
  235. }
  236. Set pubCreds = subject.getPublicCredentials();
  237. if (iToken != null && !pubCreds.contains(iToken)) {
  238. pubCreds.add(iToken);
  239. }
  240. commitSucceeded = true;
  241. return true;
  242. }
  243. /**
  244. * <p> This method is called if the LoginContext's
  245. * overall authentication failed.
  246. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
  247. * did not succeed).
  248. *
  249. * <p> If this LoginModule's own authentication attempt
  250. * succeeded (checked by retrieving the private state saved by the
  251. * <code>login</code> and <code>commit</code> methods),
  252. * then this method cleans up any state that was originally saved.
  253. *
  254. * <p>
  255. *
  256. * @exception LoginException if the abort fails.
  257. *
  258. * @return false if this LoginModule's own login and/or commit attempts
  259. * failed, and true otherwise.
  260. */
  261. public boolean abort() throws LoginException {
  262. if (debug) {
  263. System.out.println("\t\t[NTLoginModule]: " +
  264. "aborted authentication attempt");
  265. }
  266. if (succeeded == false) {
  267. return false;
  268. } else if (succeeded == true && commitSucceeded == false) {
  269. ntSystem = null;
  270. userPrincipal = null;
  271. userSID = null;
  272. userDomain = null;
  273. domainSID = null;
  274. primaryGroup = null;
  275. groups = null;
  276. iToken = null;
  277. succeeded = false;
  278. } else {
  279. // overall authentication succeeded and commit succeeded,
  280. // but someone else's commit failed
  281. logout();
  282. }
  283. return succeeded;
  284. }
  285. /**
  286. * Logout the user.
  287. *
  288. * <p> This method removes the <code>NTUserPrincipal</code>,
  289. * <code>NTDomainPrincipal</code>, <code>NTSidUserPrincipal</code>,
  290. * <code>NTSidDomainPrincipal</code>, <code>NTSidGroupPrincipal</code>s,
  291. * and <code>NTSidPrimaryGroupPrincipal</code>
  292. * that may have been added by the <code>commit</code> method.
  293. *
  294. * <p>
  295. *
  296. * @exception LoginException if the logout fails.
  297. *
  298. * @return true in all cases since this <code>LoginModule</code>
  299. * should not be ignored.
  300. */
  301. public boolean logout() throws LoginException {
  302. if (subject.isReadOnly()) {
  303. throw new LoginException ("Subject is ReadOnly");
  304. }
  305. Set principals = subject.getPrincipals();
  306. if (principals.contains(userPrincipal)) {
  307. principals.remove(userPrincipal);
  308. }
  309. if (principals.contains(userSID)) {
  310. principals.remove(userSID);
  311. }
  312. if (principals.contains(userDomain)) {
  313. principals.remove(userDomain);
  314. }
  315. if (principals.contains(domainSID)) {
  316. principals.remove(domainSID);
  317. }
  318. if (principals.contains(primaryGroup)) {
  319. principals.remove(primaryGroup);
  320. }
  321. for (int i = 0; groups != null && i < groups.length; i++) {
  322. if (principals.contains(groups[i])) {
  323. principals.remove(groups[i]);
  324. }
  325. }
  326. Set pubCreds = subject.getPublicCredentials();
  327. if (pubCreds.contains(iToken)) {
  328. pubCreds.remove(iToken);
  329. }
  330. succeeded = false;
  331. commitSucceeded = false;
  332. userPrincipal = null;
  333. userDomain = null;
  334. userSID = null;
  335. domainSID = null;
  336. groups = null;
  337. primaryGroup = null;
  338. iToken = null;
  339. ntSystem = null;
  340. if (debug) {
  341. System.out.println("\t\t[NTLoginModule] " +
  342. "completed logout processing");
  343. }
  344. return true;
  345. }
  346. }