-
Notifications
You must be signed in to change notification settings - Fork 538
/
AuthenticationFilter.java
142 lines (118 loc) · 5.57 KB
/
AuthenticationFilter.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
package io.hawt.web.auth;
import java.io.IOException;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import javax.security.auth.Subject;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import io.hawt.system.AuthenticateResult;
import io.hawt.system.Authenticator;
import io.hawt.web.ServletHelpers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Filter for authentication. If the filter is enabled, then the login screen is shown.
* <p>
* This filter is used to provide authentication for direct access to Jolokia endpoint.
*/
public class AuthenticationFilter implements Filter {
private static final Logger LOG = LoggerFactory.getLogger(AuthenticationFilter.class);
protected int timeout;
protected AuthenticationConfiguration authConfiguration;
private int pathIndex;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
authConfiguration = AuthenticationConfiguration.getConfiguration(filterConfig.getServletContext());
timeout = AuthSessionHelpers.getSessionTimeout(filterConfig.getServletContext());
this.pathIndex = ServletHelpers.hawtioPathIndex(filterConfig.getServletContext());
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
LOG.trace("Applying {}", getClass().getSimpleName());
HttpServletRequest httpRequest = (HttpServletRequest) request;
// CORS preflight requests should be ignored
if ("OPTIONS".equals(httpRequest.getMethod())) {
chain.doFilter(request, response);
return;
}
String path = httpRequest.getServletPath();
LOG.debug("Handling request for path: {}", path);
if (authConfiguration.getRealm() == null || authConfiguration.getRealm().isEmpty() || !authConfiguration.isEnabled()) {
LOG.debug("No authentication needed for path: {}", path);
chain.doFilter(request, response);
return;
}
boolean proxyMode = false;
RelativeRequestUri uri = new RelativeRequestUri(httpRequest, pathIndex);
if (uri.getComponents().length > 0 && "proxy".equals(uri.getComponents()[0])) {
// https://github.com/hawtio/hawtio/issues/3178
// /proxy/* requests are now authenticated by this filter, but we have to do it differently, because
// "Authorization" header carries credentials for target Jolokia agent
proxyMode = !uri.getUri().equals("proxy/enabled");
}
HttpSession session = httpRequest.getSession(false);
if (session != null) {
Subject subject = (Subject) session.getAttribute("subject");
// For Spring Security
if (AuthenticationConfiguration.isSpringSecurityEnabled()) {
if (subject == null && httpRequest.getRemoteUser() != null) {
AuthSessionHelpers.setup(
session, new Subject(), httpRequest.getRemoteUser(), timeout);
}
chain.doFilter(request, response);
return;
}
// Connecting from another Hawtio may have a different user authentication, so
// let's check if the session user is the same as in the authorization header here
if (AuthSessionHelpers.validate(httpRequest, session, subject)) {
executeAs(request, response, chain, subject);
return;
}
}
LOG.debug("Doing authentication and authorization for path: {}", path);
AuthenticateResult result = new Authenticator(httpRequest, authConfiguration).authenticate(
subject -> executeAs(request, response, chain, subject));
HttpServletResponse httpResponse = (HttpServletResponse) response;
switch (result.getType()) {
case AUTHORIZED:
// request was executed using the authenticated subject, nothing more to do
break;
case NOT_AUTHORIZED:
ServletHelpers.doForbidden(httpResponse);
break;
case NO_CREDENTIALS:
if (authConfiguration.isNoCredentials401()) {
// return auth prompt 401
ServletHelpers.doAuthPrompt(httpResponse, authConfiguration.getRealm());
} else {
// return forbidden 403 so the browser login does not popup
ServletHelpers.doForbidden(httpResponse);
}
break;
case THROTTLED:
ServletHelpers.doTooManyRequests(httpResponse, result.getRetryAfter());
break;
}
}
private static void executeAs(final ServletRequest request, final ServletResponse response, final FilterChain chain, Subject subject) {
try {
Subject.doAs(subject, (PrivilegedExceptionAction<Object>) () -> {
chain.doFilter(request, response);
return null;
});
} catch (PrivilegedActionException e) {
LOG.info("Failed to invoke action " + ((HttpServletRequest) request).getPathInfo() + " due to:", e);
}
}
@Override
public void destroy() {
LOG.info("Destroying hawtio authentication filter");
}
}