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  
27  import org.apache.catalina.Realm;
28  import org.apache.catalina.connector.Request;
29  import org.ietf.jgss.GSSCredential;
30  import org.ietf.jgss.GSSException;
31  import org.ietf.jgss.GSSManager;
32  import org.ietf.jgss.GSSName;
33  
34  import jakarta.servlet.http.HttpServletResponse;
35  
36  /** A Windows Identity Authenticator which uses GSS-API to retrieve to currently logged in user. */
37  public class CurrentWindowsIdentityAuthenticator extends GSSAuthenticatorBase {
38  
39  	protected static final String CURRENT_WINDOWS_IDENTITY_METHOD = "CURRENT_WINDOWS_IDENTITY";
40  	protected static final String CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME = "CWI";
41  
42  	@Override
43  	protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
44  
45  		if (checkForCachedAuthentication(request, response, true)) {
46  			return true;
47  		}
48  
49  		LoginContext lc = null;
50  
51  		try {
52  			try {
53  				lc = new LoginContext(getLoginEntryName());
54  				lc.login();
55  			} catch (LoginException | SecurityException e) {
56  				logger.error(sm.getString("cwiAuthenticator.obtainFailed"), e);
57  
58  				sendUnauthorized(
59  						request, response, CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME, "cwiAuthenticator.obtainFailed");
60  				return false;
61  			}
62  
63  			final GSSManager manager = GSSManager.getInstance();
64  			final PrivilegedExceptionAction<GSSCredential> action = () -> manager.createCredential(
65  					null, GSSCredential.INDEFINITE_LIFETIME, KRB5_MECHANISM, GSSCredential.INITIATE_ONLY);
66  
67  			GSSCredential gssCredential = null;
68  
69  			try {
70  				gssCredential = Subject.doAs(lc.getSubject(), action);
71  			} catch (PrivilegedActionException e) {
72  				logger.error(sm.getString("cwiAuthenticator.obtainFailed"), e.getException());
73  
74  				sendUnauthorized(
75  						request, response, CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME, "cwiAuthenticator.obtainFailed");
76  				return false;
77  			}
78  
79  			try {
80  				Realm realm = context.getRealm();
81  				GSSName gssName = gssCredential.getName();
82  
83  				Principal principal = realm.authenticate(gssName, isStoreDelegatedCredential() ? gssCredential : null);
84  
85  				if (principal != null) {
86  					register(request, response, principal, getAuthMethod(), principal.getName(), null);
87  					return true;
88  				} else {
89  					sendUnauthorized(
90  							request,
91  							response,
92  							CURRENT_WINDOWS_IDENTITY_AUTH_SCHEME,
93  							"gssAuthenticatorBase.userNotFound",
94  							gssName);
95  					return false;
96  				}
97  			} catch (GSSException e) {
98  				logger.error(sm.getString("gssAuthenticatorBase.inquireNameFailed"), e);
99  
100 				sendInternalServerError(request, response, "gssAuthenticatorBase.inquireNameFailed");
101 				return false;
102 			}
103 		} finally {
104 			if (lc != null) {
105 				try {
106 					lc.logout();
107 				} catch (LoginException e) {
108 					; // Ignore
109 				}
110 			}
111 		}
112 	}
113 
114 	@Override
115 	protected String getAuthMethod() {
116 		return CURRENT_WINDOWS_IDENTITY_METHOD;
117 	}
118 }