001: /*
002: * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.security.auth.module;
027:
028: import java.util.*;
029: import java.io.IOException;
030: import javax.security.auth.*;
031: import javax.security.auth.callback.*;
032: import javax.security.auth.login.*;
033: import javax.security.auth.spi.*;
034: import java.security.Principal;
035: import com.sun.security.auth.NTUserPrincipal;
036: import com.sun.security.auth.NTSidUserPrincipal;
037: import com.sun.security.auth.NTDomainPrincipal;
038: import com.sun.security.auth.NTSidDomainPrincipal;
039: import com.sun.security.auth.NTSidPrimaryGroupPrincipal;
040: import com.sun.security.auth.NTSidGroupPrincipal;
041: import com.sun.security.auth.NTNumericCredential;
042:
043: /**
044: * <p> This <code>LoginModule</code>
045: * renders a user's NT security information as some number of
046: * <code>Principal</code>s
047: * and associates them with a <code>Subject</code>.
048: *
049: * <p> This LoginModule recognizes the debug option.
050: * If set to true in the login Configuration,
051: * debug messages will be output to the output stream, System.out.
052: *
053: * <p> This LoginModule also recognizes the debugNative option.
054: * If set to true in the login Configuration,
055: * debug messages from the native component of the module
056: * will be output to the output stream, System.out.
057: *
058: * @version 1.18, 05/05/07
059: * @see javax.security.auth.spi.LoginModule
060: */
061: public class NTLoginModule implements LoginModule {
062:
063: private NTSystem ntSystem;
064:
065: // initial state
066: private Subject subject;
067: private CallbackHandler callbackHandler;
068: private Map<String, ?> sharedState;
069: private Map<String, ?> options;
070:
071: // configurable option
072: private boolean debug = false;
073: private boolean debugNative = false;
074:
075: // the authentication status
076: private boolean succeeded = false;
077: private boolean commitSucceeded = false;
078:
079: private NTUserPrincipal userPrincipal; // user name
080: private NTSidUserPrincipal userSID; // user SID
081: private NTDomainPrincipal userDomain; // user domain
082: private NTSidDomainPrincipal domainSID; // domain SID
083: private NTSidPrimaryGroupPrincipal primaryGroup; // primary group
084: private NTSidGroupPrincipal groups[]; // supplementary groups
085: private NTNumericCredential iToken; // impersonation token
086:
087: /**
088: * Initialize this <code>LoginModule</code>.
089: *
090: * <p>
091: *
092: * @param subject the <code>Subject</code> to be authenticated. <p>
093: *
094: * @param callbackHandler a <code>CallbackHandler</code> for communicating
095: * with the end user (prompting for usernames and
096: * passwords, for example). This particular LoginModule only
097: * extracts the underlying NT system information, so this
098: * parameter is ignored.<p>
099: *
100: * @param sharedState shared <code>LoginModule</code> state. <p>
101: *
102: * @param options options specified in the login
103: * <code>Configuration</code> for this particular
104: * <code>LoginModule</code>.
105: */
106: public void initialize(Subject subject,
107: CallbackHandler callbackHandler,
108: Map<String, ?> sharedState, Map<String, ?> options) {
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
118: .get("debugNative"));
119:
120: if (debugNative == true) {
121: debug = true;
122: }
123: }
124:
125: /**
126: * Import underlying NT system identity information.
127: *
128: * <p>
129: *
130: * @return true in all cases since this <code>LoginModule</code>
131: * should not be ignored.
132: *
133: * @exception FailedLoginException if the authentication fails. <p>
134: *
135: * @exception LoginException if this <code>LoginModule</code>
136: * is unable to perform the authentication.
137: */
138: public boolean login() throws LoginException {
139:
140: succeeded = false; // Indicate not yet successful
141:
142: ntSystem = new NTSystem(debugNative);
143: if (ntSystem == null) {
144: if (debug) {
145: System.out.println("\t\t[NTLoginModule] "
146: + "Failed in NT login");
147: }
148: throw new FailedLoginException(
149: "Failed in attempt to import the "
150: + "underlying NT system identity information");
151: }
152:
153: if (ntSystem.getName() == null) {
154: throw new FailedLoginException(
155: "Failed in attempt to import the "
156: + "underlying NT system identity information");
157: }
158: userPrincipal = new NTUserPrincipal(ntSystem.getName());
159: if (debug) {
160: System.out.println("\t\t[NTLoginModule] "
161: + "succeeded importing info: ");
162: System.out.println("\t\t\tuser name = "
163: + userPrincipal.getName());
164: }
165:
166: if (ntSystem.getUserSID() != null) {
167: userSID = new NTSidUserPrincipal(ntSystem.getUserSID());
168: if (debug) {
169: System.out.println("\t\t\tuser SID = "
170: + userSID.getName());
171: }
172: }
173: if (ntSystem.getDomain() != null) {
174: userDomain = new NTDomainPrincipal(ntSystem.getDomain());
175: if (debug) {
176: System.out.println("\t\t\tuser domain = "
177: + userDomain.getName());
178: }
179: }
180: if (ntSystem.getDomainSID() != null) {
181: domainSID = new NTSidDomainPrincipal(ntSystem
182: .getDomainSID());
183: if (debug) {
184: System.out.println("\t\t\tuser domain SID = "
185: + domainSID.getName());
186: }
187: }
188: if (ntSystem.getPrimaryGroupID() != null) {
189: primaryGroup = new NTSidPrimaryGroupPrincipal(ntSystem
190: .getPrimaryGroupID());
191: if (debug) {
192: System.out.println("\t\t\tuser primary group = "
193: + primaryGroup.getName());
194: }
195: }
196: if (ntSystem.getGroupIDs() != null
197: && ntSystem.getGroupIDs().length > 0) {
198:
199: String groupSIDs[] = ntSystem.getGroupIDs();
200: groups = new NTSidGroupPrincipal[groupSIDs.length];
201: for (int i = 0; i < groupSIDs.length; i++) {
202: groups[i] = new NTSidGroupPrincipal(groupSIDs[i]);
203: if (debug) {
204: System.out.println("\t\t\tuser group = "
205: + groups[i].getName());
206: }
207: }
208: }
209: if (ntSystem.getImpersonationToken() != 0) {
210: iToken = new NTNumericCredential(ntSystem
211: .getImpersonationToken());
212: if (debug) {
213: System.out.println("\t\t\timpersonation token = "
214: + ntSystem.getImpersonationToken());
215: }
216: }
217:
218: succeeded = true;
219: return succeeded;
220: }
221:
222: /**
223: * <p> This method is called if the LoginContext's
224: * overall authentication succeeded
225: * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
226: * succeeded).
227: *
228: * <p> If this LoginModule's own authentication attempt
229: * succeeded (checked by retrieving the private state saved by the
230: * <code>login</code> method), then this method associates some
231: * number of various <code>Principal</code>s
232: * with the <code>Subject</code> located in the
233: * <code>LoginModuleContext</code>. If this LoginModule's own
234: * authentication attempted failed, then this method removes
235: * any state that was originally saved.
236: *
237: * <p>
238: *
239: * @exception LoginException if the commit fails.
240: *
241: * @return true if this LoginModule's own login and commit
242: * attempts succeeded, or false otherwise.
243: */
244: public boolean commit() throws LoginException {
245: if (succeeded == false) {
246: if (debug) {
247: System.out.println("\t\t[NTLoginModule]: "
248: + "did not add any Principals to Subject "
249: + "because own authentication failed.");
250: }
251: return false;
252: }
253: if (subject.isReadOnly()) {
254: throw new LoginException("Subject is ReadOnly");
255: }
256: Set<Principal> principals = subject.getPrincipals();
257:
258: // we must have a userPrincipal - everything else is optional
259: if (!principals.contains(userPrincipal)) {
260: principals.add(userPrincipal);
261: }
262: if (userSID != null && !principals.contains(userSID)) {
263: principals.add(userSID);
264: }
265:
266: if (userDomain != null && !principals.contains(userDomain)) {
267: principals.add(userDomain);
268: }
269: if (domainSID != null && !principals.contains(domainSID)) {
270: principals.add(domainSID);
271: }
272:
273: if (primaryGroup != null && !principals.contains(primaryGroup)) {
274: principals.add(primaryGroup);
275: }
276: for (int i = 0; groups != null && i < groups.length; i++) {
277: if (!principals.contains(groups[i])) {
278: principals.add(groups[i]);
279: }
280: }
281:
282: Set<Object> pubCreds = subject.getPublicCredentials();
283: if (iToken != null && !pubCreds.contains(iToken)) {
284: pubCreds.add(iToken);
285: }
286: commitSucceeded = true;
287: return true;
288: }
289:
290: /**
291: * <p> This method is called if the LoginContext's
292: * overall authentication failed.
293: * (the relevant REQUIRED, REQUISITE, SUFFICIENT and OPTIONAL LoginModules
294: * did not succeed).
295: *
296: * <p> If this LoginModule's own authentication attempt
297: * succeeded (checked by retrieving the private state saved by the
298: * <code>login</code> and <code>commit</code> methods),
299: * then this method cleans up any state that was originally saved.
300: *
301: * <p>
302: *
303: * @exception LoginException if the abort fails.
304: *
305: * @return false if this LoginModule's own login and/or commit attempts
306: * failed, and true otherwise.
307: */
308: public boolean abort() throws LoginException {
309: if (debug) {
310: System.out.println("\t\t[NTLoginModule]: "
311: + "aborted authentication attempt");
312: }
313:
314: if (succeeded == false) {
315: return false;
316: } else if (succeeded == true && commitSucceeded == false) {
317: ntSystem = null;
318: userPrincipal = null;
319: userSID = null;
320: userDomain = null;
321: domainSID = null;
322: primaryGroup = null;
323: groups = null;
324: iToken = null;
325: succeeded = false;
326: } else {
327: // overall authentication succeeded and commit succeeded,
328: // but someone else's commit failed
329: logout();
330: }
331: return succeeded;
332: }
333:
334: /**
335: * Logout the user.
336: *
337: * <p> This method removes the <code>NTUserPrincipal</code>,
338: * <code>NTDomainPrincipal</code>, <code>NTSidUserPrincipal</code>,
339: * <code>NTSidDomainPrincipal</code>, <code>NTSidGroupPrincipal</code>s,
340: * and <code>NTSidPrimaryGroupPrincipal</code>
341: * that may have been added by the <code>commit</code> method.
342: *
343: * <p>
344: *
345: * @exception LoginException if the logout fails.
346: *
347: * @return true in all cases since this <code>LoginModule</code>
348: * should not be ignored.
349: */
350: public boolean logout() throws LoginException {
351:
352: if (subject.isReadOnly()) {
353: throw new LoginException("Subject is ReadOnly");
354: }
355: Set<Principal> principals = subject.getPrincipals();
356: if (principals.contains(userPrincipal)) {
357: principals.remove(userPrincipal);
358: }
359: if (principals.contains(userSID)) {
360: principals.remove(userSID);
361: }
362: if (principals.contains(userDomain)) {
363: principals.remove(userDomain);
364: }
365: if (principals.contains(domainSID)) {
366: principals.remove(domainSID);
367: }
368: if (principals.contains(primaryGroup)) {
369: principals.remove(primaryGroup);
370: }
371: for (int i = 0; groups != null && i < groups.length; i++) {
372: if (principals.contains(groups[i])) {
373: principals.remove(groups[i]);
374: }
375: }
376:
377: Set<Object> pubCreds = subject.getPublicCredentials();
378: if (pubCreds.contains(iToken)) {
379: pubCreds.remove(iToken);
380: }
381:
382: succeeded = false;
383: commitSucceeded = false;
384: userPrincipal = null;
385: userDomain = null;
386: userSID = null;
387: domainSID = null;
388: groups = null;
389: primaryGroup = null;
390: iToken = null;
391: ntSystem = null;
392:
393: if (debug) {
394: System.out.println("\t\t[NTLoginModule] "
395: + "completed logout processing");
396: }
397: return true;
398: }
399: }
|