blob: f0e280536922c72983e8421e85aea463a3a33dfb [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package com.sun.security.auth.module;
27
28import java.util.*;
29import java.io.IOException;
30import javax.security.auth.*;
31import javax.security.auth.callback.*;
32import javax.security.auth.login.*;
33import javax.security.auth.spi.*;
34import java.security.Principal;
35import com.sun.security.auth.NTUserPrincipal;
36import com.sun.security.auth.NTSidUserPrincipal;
37import com.sun.security.auth.NTDomainPrincipal;
38import com.sun.security.auth.NTSidDomainPrincipal;
39import com.sun.security.auth.NTSidPrimaryGroupPrincipal;
40import com.sun.security.auth.NTSidGroupPrincipal;
41import 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 */
60public 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}