/
AltKerberosAuthenticationHandler.java
147 lines (136 loc) · 5.46 KB
/
AltKerberosAuthenticationHandler.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License. See accompanying LICENSE file.
*/
package org.apache.hadoop.security.authentication.server;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.hadoop.security.authentication.client.AuthenticationException;
/**
* The {@link AltKerberosAuthenticationHandler} behaves exactly the same way as
* the {@link KerberosAuthenticationHandler}, except that it allows for an
* alternative form of authentication for browsers while still using Kerberos
* for Java access. This is an abstract class that should be subclassed
* to allow a developer to implement their own custom authentication for browser
* access. The alternateAuthenticate method will be called whenever a request
* comes from a browser.
*/
public abstract class AltKerberosAuthenticationHandler
extends KerberosAuthenticationHandler {
/**
* Constant that identifies the authentication mechanism.
*/
public static final String TYPE = "alt-kerberos";
/**
* Constant for the configuration property that indicates which user agents
* are not considered browsers (comma separated)
*/
public static final String NON_BROWSER_USER_AGENTS =
TYPE + ".non-browser.user-agents";
private static final String NON_BROWSER_USER_AGENTS_DEFAULT =
"java,curl,wget,perl";
private String[] nonBrowserUserAgents;
/**
* Returns the authentication type of the authentication handler,
* 'alt-kerberos'.
*
* @return the authentication type of the authentication handler,
* 'alt-kerberos'.
*/
@Override
public String getType() {
return TYPE;
}
@Override
public void init(Properties config) throws ServletException {
super.init(config);
nonBrowserUserAgents = config.getProperty(
NON_BROWSER_USER_AGENTS, NON_BROWSER_USER_AGENTS_DEFAULT)
.split("\\W*,\\W*");
for (int i = 0; i < nonBrowserUserAgents.length; i++) {
nonBrowserUserAgents[i] = nonBrowserUserAgents[i].toLowerCase();
}
}
/**
* It enforces the the Kerberos SPNEGO authentication sequence returning an
* {@link AuthenticationToken} only after the Kerberos SPNEGO sequence has
* completed successfully (in the case of Java access) and only after the
* custom authentication implemented by the subclass in alternateAuthenticate
* has completed successfully (in the case of browser access).
*
* @param request the HTTP client request.
* @param response the HTTP client response.
*
* @return an authentication token if the request is authorized or null
*
* @throws IOException thrown if an IO error occurred
* @throws AuthenticationException thrown if an authentication error occurred
*/
@Override
public AuthenticationToken authenticate(HttpServletRequest request,
HttpServletResponse response)
throws IOException, AuthenticationException {
AuthenticationToken token;
if (isBrowser(request.getHeader("User-Agent"))) {
token = alternateAuthenticate(request, response);
}
else {
token = super.authenticate(request, response);
}
return token;
}
/**
* This method parses the User-Agent String and returns whether or not it
* refers to a browser. If its not a browser, then Kerberos authentication
* will be used; if it is a browser, alternateAuthenticate from the subclass
* will be used.
* <p>
* A User-Agent String is considered to be a browser if it does not contain
* any of the values from alt-kerberos.non-browser.user-agents; the default
* behavior is to consider everything a browser unless it contains one of:
* "java", "curl", "wget", or "perl". Subclasses can optionally override
* this method to use different behavior.
*
* @param userAgent The User-Agent String, or null if there isn't one
* @return true if the User-Agent String refers to a browser, false if not
*/
protected boolean isBrowser(String userAgent) {
if (userAgent == null) {
return false;
}
userAgent = userAgent.toLowerCase();
boolean isBrowser = true;
for (String nonBrowserUserAgent : nonBrowserUserAgents) {
if (userAgent.contains(nonBrowserUserAgent)) {
isBrowser = false;
break;
}
}
return isBrowser;
}
/**
* Subclasses should implement this method to provide the custom
* authentication to be used for browsers.
*
* @param request the HTTP client request.
* @param response the HTTP client response.
* @return an authentication token if the request is authorized, or null
* @throws IOException thrown if an IO error occurs
* @throws AuthenticationException thrown if an authentication error occurs
*/
public abstract AuthenticationToken alternateAuthenticate(
HttpServletRequest request, HttpServletResponse response)
throws IOException, AuthenticationException;
}