/
RegisteredServiceResponseHeadersEnforcementFilter.java
144 lines (130 loc) · 7.24 KB
/
RegisteredServiceResponseHeadersEnforcementFilter.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
package org.apereo.cas.services.web.support;
import org.apereo.cas.authentication.AuthenticationServiceSelectionPlan;
import org.apereo.cas.authentication.principal.Service;
import org.apereo.cas.authentication.principal.WebApplicationService;
import org.apereo.cas.security.ResponseHeadersEnforcementFilter;
import org.apereo.cas.services.RegisteredService;
import org.apereo.cas.services.RegisteredServiceProperty;
import org.apereo.cas.services.RegisteredServiceProperty.RegisteredServiceProperties;
import org.apereo.cas.services.ServicesManager;
import org.apereo.cas.web.support.ArgumentExtractor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.Optional;
/**
* This is {@link RegisteredServiceResponseHeadersEnforcementFilter}. A filter extension that looks at the properties of a
* registered service to determine if headers should be injected into the response.
*
* @author Misagh Moayyed
* @since 5.3.0
*/
@Slf4j
@RequiredArgsConstructor
public class RegisteredServiceResponseHeadersEnforcementFilter extends ResponseHeadersEnforcementFilter {
private final ServicesManager servicesManager;
private final ArgumentExtractor argumentExtractor;
private final AuthenticationServiceSelectionPlan authenticationRequestServiceSelectionStrategies;
@Override
protected void decideInsertContentSecurityPolicyHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_CONTENT_SECURITY_POLICY)) {
super.insertContentSecurityPolicyHeader(httpServletResponse, httpServletRequest);
} else {
super.decideInsertContentSecurityPolicyHeader(httpServletResponse, httpServletRequest);
}
}
@Override
protected void decideInsertXSSProtectionHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_XSS_PROTECTION)) {
super.insertXSSProtectionHeader(httpServletResponse, httpServletRequest);
} else {
super.decideInsertXSSProtectionHeader(httpServletResponse, httpServletRequest);
}
}
@Override
protected void decideInsertXFrameOptionsHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_XFRAME_OPTIONS)) {
final String xFrameOptions = getStringProperty(httpServletRequest, RegisteredServiceProperties.HTTP_HEADER_XFRAME_OPTIONS);
super.insertXFrameOptionsHeader(httpServletResponse, httpServletRequest, xFrameOptions);
} else {
super.decideInsertXFrameOptionsHeader(httpServletResponse, httpServletRequest);
}
}
@Override
protected void decideInsertXContentTypeOptionsHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_XCONTENT_OPTIONS)) {
super.insertXContentTypeOptionsHeader(httpServletResponse, httpServletRequest);
} else {
super.decideInsertXContentTypeOptionsHeader(httpServletResponse, httpServletRequest);
}
}
@Override
protected void decideInsertCacheControlHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_CACHE_CONTROL)) {
super.insertCacheControlHeader(httpServletResponse, httpServletRequest);
} else {
super.decideInsertCacheControlHeader(httpServletResponse, httpServletRequest);
}
}
@Override
protected void decideInsertStrictTransportSecurityHeader(final HttpServletResponse httpServletResponse, final HttpServletRequest httpServletRequest) {
if (shouldHttpHeaderBeInjectedIntoResponse(httpServletRequest,
RegisteredServiceProperties.HTTP_HEADER_ENABLE_STRICT_TRANSPORT_SECURITY)) {
super.insertStrictTransportSecurityHeader(httpServletResponse, httpServletRequest);
} else {
super.decideInsertStrictTransportSecurityHeader(httpServletResponse, httpServletRequest);
}
}
private String getStringProperty(final HttpServletRequest request,
final RegisteredServiceProperties property) {
final Optional<RegisteredService> result = getRegisteredServiceFromRequest(request);
if (result.isPresent()) {
final Map<String, RegisteredServiceProperty> properties = result.get().getProperties();
if (properties.containsKey(property.getPropertyName())) {
final RegisteredServiceProperty prop = properties.get(property.getPropertyName());
return prop.getValue();
}
}
return null;
}
private boolean shouldHttpHeaderBeInjectedIntoResponse(final HttpServletRequest request,
final RegisteredServiceProperties property) {
final Optional<RegisteredService> result = getRegisteredServiceFromRequest(request);
if (result.isPresent()) {
final Map<String, RegisteredServiceProperty> properties = result.get().getProperties();
if (properties.containsKey(property.getPropertyName())) {
final RegisteredServiceProperty prop = properties.get(property.getPropertyName());
return BooleanUtils.toBoolean(prop.getValue());
}
}
return false;
}
/**
* Gets registered service from request.
* Reading the request body by the argument extractor here may cause the underlying request stream
* to close. If there are any underlying controllers or components that expect to read
* or parse the request body, like those that handle ticket validation, they would fail given the
* {@link HttpServletRequest#getReader()} is consumed by the argument extractor here and not available anymore.
* Therefor, any of the inner components of the extractor might have to cache the request body
* as an attribute, etc so they can re-process and re-extract as needed.
*
* @param request the request
* @return the registered service from request
*/
private Optional<RegisteredService> getRegisteredServiceFromRequest(final HttpServletRequest request) {
final WebApplicationService service = this.argumentExtractor.extractService(request);
if (service != null) {
final Service resolved = authenticationRequestServiceSelectionStrategies.resolveService(service);
return Optional.ofNullable(this.servicesManager.findServiceBy(resolved));
}
return Optional.empty();
}
}