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