View Javadoc
1   /*
2    * Copyright 2013–2026 Michael Osipov
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package net.sf.michaelo.tomcat.authenticator;
17  
18  import java.io.IOException;
19  import java.security.Principal;
20  import java.security.PrivilegedActionException;
21  import java.security.PrivilegedExceptionAction;
22  
23  import javax.security.auth.Subject;
24  import javax.security.auth.login.LoginContext;
25  import javax.security.auth.login.LoginException;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.apache.catalina.Realm;
29  import org.apache.catalina.connector.Request;
30  import org.ietf.jgss.GSSCredential;
31  import org.ietf.jgss.GSSException;
32  import org.ietf.jgss.GSSManager;
33  import org.ietf.jgss.GSSName;
34  
35  /** A Windows Identity Authenticator which uses GSS-API to retrieve to currently logged in user. */
36  public class CurrentWindowsIdentityAuthenticator extends GSSAuthenticatorBase {
37  
38  	protected static final String CURRENT_WINDOWS_IDENTITY_METHOD = "CURRENT_WINDOWS_IDENTITY";
39  	protected static final String CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME = "CWI";
40  
41  	@Override
42  	protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
43  
44  		if (checkForCachedAuthentication(request, response, true)) {
45  			return true;
46  		}
47  
48  		LoginContext lc = null;
49  
50  		try {
51  			try {
52  				lc = new LoginContext(getLoginEntryName());
53  				lc.login();
54  			} catch (LoginException | SecurityException e) {
55  				logger.error(sm.getString("cwiAuthenticator.obtainFailed"), e);
56  
57  				sendUnauthorized(
58  						request, response, CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME, "cwiAuthenticator.obtainFailed");
59  				return false;
60  			}
61  
62  			final GSSManager manager = GSSManager.getInstance();
63  			final PrivilegedExceptionAction<GSSCredential> action = () -> manager.createCredential(
64  					null, GSSCredential.INDEFINITE_LIFETIME, KRB5_MECHANISM, GSSCredential.INITIATE_ONLY);
65  
66  			GSSCredential gssCredential = null;
67  
68  			try {
69  				gssCredential = Subject.doAs(lc.getSubject(), action);
70  			} catch (PrivilegedActionException e) {
71  				logger.error(sm.getString("cwiAuthenticator.obtainFailed"), e.getException());
72  
73  				sendUnauthorized(
74  						request, response, CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME, "cwiAuthenticator.obtainFailed");
75  				return false;
76  			}
77  
78  			try {
79  				Realm realm = context.getRealm();
80  				GSSName gssName = gssCredential.getName();
81  
82  				Principal principal = realm.authenticate(gssName, isStoreDelegatedCredential() ? gssCredential : null);
83  
84  				if (principal != null) {
85  					register(request, response, principal, getAuthMethod(), principal.getName(), null);
86  					return true;
87  				} else {
88  					sendUnauthorized(
89  							request,
90  							response,
91  							CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME,
92  							"gssAuthenticatorBase.userNotFound",
93  							gssName);
94  					return false;
95  				}
96  			} catch (GSSException e) {
97  				logger.error(sm.getString("gssAuthenticatorBase.inquireNameFailed"), e);
98  
99  				sendInternalServerError(request, response, "gssAuthenticatorBase.inquireNameFailed");
100 				return false;
101 			}
102 		} finally {
103 			if (lc != null) {
104 				try {
105 					lc.logout();
106 				} catch (LoginException e) {
107 					; // Ignore
108 				}
109 			}
110 		}
111 	}
112 
113 	@Override
114 	protected String getAuthMethod() {
115 		return CURRENT_WINDOWS_IDENTITY_METHOD;
116 	}
117 }