1. /*
  2. * @(#)SolarisLoginModule.java 1.7 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.SolarisPrincipal;
  15. import com.sun.security.auth.SolarisNumericUserPrincipal;
  16. import com.sun.security.auth.SolarisNumericGroupPrincipal;
  17. /**
  18. * <p> This <code>LoginModule</code> imports a user's Solaris
  19. * <code>Principal</code> information (<code>SolarisPrincipal</code>,
  20. * <code>SolarisNumericUserPrincipal</code>,
  21. * and <code>SolarisNumericGroupPrincipal</code>)
  22. * and associates them with the current <code>Subject</code>.
  23. *
  24. * <p> This LoginModule recognizes the debug option.
  25. * If set to true in the login Configuration,
  26. * debug messages will be output to the output stream, System.out.
  27. * @deprecated As of JDK1.4, replaced by
  28. * <code>com.sun.security.auth.module.UnixLoginModule</code>.
  29. * This LoginModule is entirely deprecated and
  30. * is here to allow for a smooth transition to the new
  31. * UnixLoginModule.
  32. *
  33. * @version 1.19, 01/11/00
  34. */
  35. public class SolarisLoginModule implements LoginModule {
  36. // initial state
  37. private Subject subject;
  38. private CallbackHandler callbackHandler;
  39. private Map sharedState;
  40. private Map options;
  41. // configurable option
  42. private boolean debug = true;
  43. // SolarisSystem to retrieve underlying system info
  44. private SolarisSystem ss;
  45. // the authentication status
  46. private boolean succeeded = false;
  47. private boolean commitSucceeded = false;
  48. // Underlying system info
  49. private SolarisPrincipal userPrincipal;
  50. private SolarisNumericUserPrincipal UIDPrincipal;
  51. private SolarisNumericGroupPrincipal GIDPrincipal;
  52. private LinkedList supplementaryGroups = new LinkedList();
  53. /**
  54. * Initialize this <code>LoginModule</code>.
  55. *
  56. * <p>
  57. *
  58. * @param subject the <code>Subject</code> to be authenticated. <p>
  59. *
  60. * @param callbackHandler a <code>CallbackHandler</code> for communicating
  61. * with the end user (prompting for usernames and
  62. * passwords, for example). <p>
  63. *
  64. * @param sharedState shared <code>LoginModule</code> state. <p>
  65. *
  66. * @param options options specified in the login
  67. * <code>Configuration</code> for this particular
  68. * <code>LoginModule</code>.
  69. */
  70. public void initialize(Subject subject, CallbackHandler callbackHandler,
  71. Map sharedState, Map options) {
  72. this.subject = subject;
  73. this.callbackHandler = callbackHandler;
  74. this.sharedState = sharedState;
  75. this.options = options;
  76. // initialize any configured options
  77. debug = "true".equalsIgnoreCase((String)options.get("debug"));
  78. }
  79. /**
  80. * Authenticate the user (first phase).
  81. *
  82. * <p> The implementation of this method attempts to retrieve the user's
  83. * Solaris <code>Subject</code> information by making a native Solaris
  84. * system call.
  85. *
  86. * <p>
  87. *
  88. * @exception FailedLoginException if attempts to retrieve the underlying
  89. * system information fail.
  90. *
  91. * @return true in all cases (this <code>LoginModule</code>
  92. * should not be ignored).
  93. */
  94. public boolean login() throws LoginException {
  95. long[] solarisGroups = null;
  96. ss = new SolarisSystem();
  97. if (ss == null) {
  98. succeeded = false;
  99. throw new FailedLoginException
  100. ("Failed in attempt to import " +
  101. "the underlying system identity information");
  102. } else {
  103. userPrincipal = new SolarisPrincipal(ss.getUsername());
  104. UIDPrincipal = new SolarisNumericUserPrincipal(ss.getUid());
  105. GIDPrincipal = new SolarisNumericGroupPrincipal(ss.getGid(), true);
  106. if (ss.getGroups() != null && ss.getGroups().length > 0)
  107. solarisGroups = ss.getGroups();
  108. for (int i = 0; i < solarisGroups.length; i++) {
  109. SolarisNumericGroupPrincipal ngp =
  110. new SolarisNumericGroupPrincipal
  111. (solarisGroups[i], false);
  112. if (!ngp.getName().equals(GIDPrincipal.getName()))
  113. supplementaryGroups.add(ngp);
  114. }
  115. if (debug) {
  116. System.out.println("\t\t[SolarisLoginModule]: " +
  117. "succeeded importing info: ");
  118. System.out.println("\t\t\tuid = " + ss.getUid());
  119. System.out.println("\t\t\tgid = " + ss.getGid());
  120. solarisGroups = ss.getGroups();
  121. for (int i = 0; i < solarisGroups.length; i++) {
  122. System.out.println("\t\t\tsupp gid = " + solarisGroups[i]);
  123. }
  124. }
  125. succeeded = true;
  126. return true;
  127. }
  128. }
  129. /**
  130. * Commit the authentication (second phase).
  131. *
  132. * <p> This method is called if the LoginContext's
  133. * overall authentication succeeded
  134. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
  135. * succeeded).
  136. *
  137. * <p> If this LoginModule's own authentication attempt
  138. * succeeded (the importing of the Solaris authentication information
  139. * succeeded), then this method associates the Solaris Principals
  140. * with the <code>Subject</code> currently tied to the
  141. * <code>LoginModule</code>. If this LoginModule's
  142. * authentication attempted failed, then this method removes
  143. * any state that was originally saved.
  144. *
  145. * <p>
  146. *
  147. * @exception LoginException if the commit fails
  148. *
  149. * @return true if this LoginModule's own login and commit attempts
  150. * succeeded, or false otherwise.
  151. */
  152. public boolean commit() throws LoginException {
  153. if (succeeded == false) {
  154. if (debug) {
  155. System.out.println("\t\t[SolarisLoginModule]: " +
  156. "did not add any Principals to Subject " +
  157. "because own authentication failed.");
  158. }
  159. return false;
  160. }
  161. if (subject.isReadOnly()) {
  162. throw new LoginException ("Subject is Readonly");
  163. }
  164. if (!subject.getPrincipals().contains(userPrincipal))
  165. subject.getPrincipals().add(userPrincipal);
  166. if (!subject.getPrincipals().contains(UIDPrincipal))
  167. subject.getPrincipals().add(UIDPrincipal);
  168. if (!subject.getPrincipals().contains(GIDPrincipal))
  169. subject.getPrincipals().add(GIDPrincipal);
  170. for (int i = 0; i < supplementaryGroups.size(); i++) {
  171. if (!subject.getPrincipals().contains
  172. ((SolarisNumericGroupPrincipal)supplementaryGroups.get(i)))
  173. subject.getPrincipals().add((SolarisNumericGroupPrincipal)
  174. supplementaryGroups.get(i));
  175. }
  176. if (debug) {
  177. System.out.println("\t\t[SolarisLoginModule]: " +
  178. "added SolarisPrincipal,");
  179. System.out.println("\t\t\t\tSolarisNumericUserPrincipal,");
  180. System.out.println("\t\t\t\tSolarisNumericGroupPrincipal(s),");
  181. System.out.println("\t\t\t to Subject");
  182. }
  183. commitSucceeded = true;
  184. return true;
  185. }
  186. /**
  187. * Abort the authentication (second phase).
  188. *
  189. * <p> This method is called if the LoginContext's
  190. * overall authentication failed.
  191. * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
  192. * did not succeed).
  193. *
  194. * <p> This method cleans up any state that was originally saved
  195. * as part of the authentication attempt from the <code>login</code>
  196. * and <code>commit</code> methods.
  197. *
  198. * <p>
  199. *
  200. * @exception LoginException if the abort fails
  201. *
  202. * @return false if this LoginModule's own login and/or commit attempts
  203. * failed, and true otherwise.
  204. */
  205. public boolean abort() throws LoginException {
  206. if (debug) {
  207. System.out.println("\t\t[SolarisLoginModule]: " +
  208. "aborted authentication attempt");
  209. }
  210. if (succeeded == false) {
  211. return false;
  212. } else if (succeeded == true && commitSucceeded == false) {
  213. // Clean out state
  214. succeeded = false;
  215. ss = null;
  216. userPrincipal = null;
  217. UIDPrincipal = null;
  218. GIDPrincipal = null;
  219. supplementaryGroups = new LinkedList();
  220. } else {
  221. // overall authentication succeeded and commit succeeded,
  222. // but someone else's commit failed
  223. logout();
  224. }
  225. return true;
  226. }
  227. /**
  228. * Logout the user
  229. *
  230. * <p> This method removes the Principals associated
  231. * with the <code>Subject</code>.
  232. *
  233. * <p>
  234. *
  235. * @exception LoginException if the logout fails
  236. *
  237. * @return true in all cases (this <code>LoginModule</code>
  238. * should not be ignored).
  239. */
  240. public boolean logout() throws LoginException {
  241. if (debug) {
  242. System.out.println("\t\t[SolarisLoginModule]: " +
  243. "Entering logout");
  244. }
  245. if (subject.isReadOnly()) {
  246. throw new LoginException ("Subject is Readonly");
  247. }
  248. // remove the added Principals from the Subject
  249. subject.getPrincipals().remove(userPrincipal);
  250. subject.getPrincipals().remove(UIDPrincipal);
  251. subject.getPrincipals().remove(GIDPrincipal);
  252. for (int i = 0; i < supplementaryGroups.size(); i++) {
  253. subject.getPrincipals().remove
  254. ((SolarisNumericGroupPrincipal)supplementaryGroups.get(i));
  255. }
  256. // clean out state
  257. ss = null;
  258. succeeded = false;
  259. commitSucceeded = false;
  260. userPrincipal = null;
  261. UIDPrincipal = null;
  262. GIDPrincipal = null;
  263. supplementaryGroups = new LinkedList();
  264. if (debug) {
  265. System.out.println("\t\t[SolarisLoginModule]: " +
  266. "logged out Subject");
  267. }
  268. return true;
  269. }
  270. }