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