DispatcherAccessHealthCheck.java
9.32 KB
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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
* Decompiled with CFR 0_118.
*
* Could not load the following classes:
* org.apache.felix.scr.annotations.Activate
* org.apache.felix.scr.annotations.Component
* org.apache.felix.scr.annotations.Modified
* org.apache.felix.scr.annotations.Properties
* org.apache.felix.scr.annotations.Property
* org.apache.felix.scr.annotations.PropertyUnbounded
* org.apache.felix.scr.annotations.Service
* org.apache.http.HttpEntity
* org.apache.http.StatusLine
* org.apache.http.client.methods.CloseableHttpResponse
* org.apache.http.client.methods.HttpGet
* org.apache.http.client.methods.HttpUriRequest
* org.apache.http.impl.client.CloseableHttpClient
* org.apache.http.impl.client.HttpClients
* org.apache.sling.commons.osgi.PropertiesUtil
* org.apache.sling.hc.api.HealthCheck
* org.apache.sling.hc.api.Result
* org.apache.sling.hc.api.ResultLog
* org.apache.sling.hc.util.FormattingResultLog
* org.osgi.service.component.ComponentContext
*/
package com.adobe.cq.security.hc.dispatcher.impl;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Dictionary;
import java.util.List;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Modified;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.PropertyUnbounded;
import org.apache.felix.scr.annotations.Service;
import org.apache.http.HttpEntity;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.sling.commons.osgi.PropertiesUtil;
import org.apache.sling.hc.api.HealthCheck;
import org.apache.sling.hc.api.Result;
import org.apache.sling.hc.api.ResultLog;
import org.apache.sling.hc.util.FormattingResultLog;
import org.osgi.service.component.ComponentContext;
@Component(metatype=1, label="Adobe CQ Dispatcher Configuration Health Check", description="This checks the basic configuration of the Dispatcher component.")
@Properties(value={@Property(name="hc.name", value={"CQ Dispatcher Configuration"}, label="Name", description="Name of the health check."), @Property(name="hc.tags", unbounded=PropertyUnbounded.ARRAY, value={"dispatcher", "production", "security"}, label="Tags", description="Tags for the health check."), @Property(name="hc.mbean.name", value={"dispatcherConfig"}, label="MBean Name", description="Name of the JMX mbean to register for this check.")})
@Service(value={HealthCheck.class})
public class DispatcherAccessHealthCheck
implements HealthCheck {
@Property(value={""}, label="Dispatcher Address", description="The address where the dispatcher is installed.")
private static final String DISPATCHER_URL = "dispatcher.address";
@Property(value={"/content", "/libs/cq/personalization/", "/etc/designs/", "/etc/clientlibs/", "/etc/segmentation.segment.js", "/libs/cq/personalization/components/clickstreamcloud/content/config.json", "/libs/wcm/stats/tracker.js", "/libs/cq/personalization/", "/libs/cq/security/userinfo.json", "/libs/cq/i18n/"}, label="Unrestricted paths", unbounded=PropertyUnbounded.ARRAY, description="The paths which should not be restricted by the dispatcher.")
private static final String ALLOWED_PATHS = "dispatcher.filter.allowed";
@Property(value={"/", "/content/", "/etc/", "/libs/", "/etc/replication.xml", "/etc/replication.infinity.xml", "/content.inifinity.json", "/content.tidy.json", "/content.sysview.xml", "/content.docview.json", "/content.docview.xml", "/content.0.json", "/content.1.json", "/content.2.json", "/content.feed.xml"}, label="Restricted paths", unbounded=PropertyUnbounded.ARRAY, description="The paths which should be restricted by the dispatcher.")
private static final String NOT_ALLOWED_PATHS = "dispatcher.filter.blocked";
private String dispatcherAddress;
private List<String> allowedPaths;
private List<String> blockedPaths;
@Activate
protected void activate(ComponentContext ctx) {
this.dispatcherAddress = PropertiesUtil.toString(ctx.getProperties().get("dispatcher.address"), (String)"");
this.allowedPaths = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get("dispatcher.filter.allowed"), (String[])new String[0]));
this.blockedPaths = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get("dispatcher.filter.blocked"), (String[])new String[0]));
}
@Modified
protected void update(ComponentContext ctx) {
this.dispatcherAddress = PropertiesUtil.toString(ctx.getProperties().get("dispatcher.address"), (String)"");
this.allowedPaths = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get("dispatcher.filter.allowed"), (String[])new String[0]));
this.blockedPaths = Arrays.asList(PropertiesUtil.toStringArray(ctx.getProperties().get("dispatcher.filter.blocked"), (String[])new String[0]));
}
public Result execute() {
FormattingResultLog resultLog = new FormattingResultLog();
int successes = 0;
int failures = 0;
if ("".equals(this.dispatcherAddress.trim())) {
resultLog.warn("Unable to check the dispatcher's basic configuration because its address is not specified.", new Object[0]);
resultLog.debug("[The address can be specified via the 'Dispatcher Address' property of this health check.]( )", new Object[0]);
return new Result((ResultLog)resultLog);
}
CloseableHttpClient client = HttpClients.createDefault();
for (String path2 : this.allowedPaths) {
if (this.checkPath(client, path2, true, resultLog)) {
++successes;
continue;
}
++failures;
}
for (String path2 : this.blockedPaths) {
if (this.checkPath(client, path2, false, resultLog)) {
++successes;
continue;
}
++failures;
}
if (failures != 0) {
String errorMsg = failures > 1 ? "{} path access configurations failed during testing. " : "{} path access configuration failed during testing. ";
resultLog.warn("[" + errorMsg + "When configuring the dispatcher, you should restrict external access as much as possible.]( )", new Object[]{failures});
resultLog.debug("[Check the 'Restrict Access via the Dispatcher' section in the security guidelines](https://www.adobe.com/go/aem6_2_docs_security_access_en)", new Object[0]);
resultLog.debug("[Check the 'Configuring the Dispatcher to prevent DoS' section in the security guidelines](https://www.adobe.com/go/aem6_2_docs_security_dos_en)", new Object[0]);
} else {
resultLog.info("[All {} paths checked meet the configuration access guidelines.]( )", new Object[]{successes});
}
if (client != null) {
try {
client.close();
}
catch (IOException e) {
resultLog.warn("Could not close HTTP client due to an IOException.", new Object[0]);
}
}
return new Result((ResultLog)resultLog);
}
/*
* WARNING - Removed try catching itself - possible behaviour change.
*/
private boolean checkPath(CloseableHttpClient client, String path, boolean shouldWork, FormattingResultLog resultLog) {
boolean success;
block17 : {
success = true;
HttpGet httpget = new HttpGet(this.dispatcherAddress + path);
CloseableHttpResponse httpResponse = null;
try {
boolean validRequest;
httpResponse = client.execute((HttpUriRequest)httpget);
int code = httpResponse.getStatusLine().getStatusCode();
boolean bl = validRequest = code == 200 || code == 401 || code == 403;
if (shouldWork == validRequest) {
if (shouldWork) {
resultLog.debug("Request to [{}] worked, as expected.", new Object[]{path});
} else {
resultLog.debug("Request to [{}] did not work, as expected.", new Object[]{path});
}
break block17;
}
if (shouldWork) {
resultLog.warn("Request to [{}] did not work. It was expected to work.", new Object[]{path});
} else {
resultLog.warn("Request to [{}] worked. It was expected to fail.", new Object[]{path});
}
success = false;
}
catch (Exception e) {
resultLog.warn("Could not check path [{}].", new Object[]{path});
success = false;
}
finally {
if (httpResponse != null && httpResponse.getEntity() != null) {
try {
httpResponse.getEntity().getContent().close();
}
catch (Exception e) {
resultLog.warn("Could not close the HTTP response due to an IOException.", new Object[0]);
}
}
}
}
return success;
}
}