Skip to content

Commit 2e5b184

Browse files
author
Corneil du Plessis
committed
Replace RedirectExec with modified chain handler.
Fixes spring-attic#5989
1 parent efd1708 commit 2e5b184

File tree

3 files changed

+304
-96
lines changed

3 files changed

+304
-96
lines changed

spring-cloud-dataflow-container-registry/src/main/java/org/springframework/cloud/dataflow/container/registry/ContainerImageRestTemplateFactory.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@
3131

3232
import org.apache.hc.client5.http.config.RequestConfig;
3333
import org.apache.hc.client5.http.cookie.StandardCookieSpec;
34+
import org.apache.hc.client5.http.impl.ChainElement;
35+
import org.apache.hc.client5.http.impl.DefaultSchemePortResolver;
3436
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
3537
import org.apache.hc.client5.http.impl.classic.HttpClients;
3638
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
39+
import org.apache.hc.client5.http.impl.routing.DefaultProxyRoutePlanner;
40+
import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
3741
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
3842
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
3943
import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
@@ -44,12 +48,12 @@
4448

4549
import org.springframework.boot.web.client.RestTemplateBuilder;
4650
import org.springframework.cloud.dataflow.container.registry.authorization.DropAuthorizationHeaderRequestRedirectStrategy;
51+
import org.springframework.cloud.dataflow.container.registry.authorization.SpecialRedirectExec;
4752
import org.springframework.http.MediaType;
4853
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
4954
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
5055
import org.springframework.web.client.RestTemplate;
5156

52-
5357
/**
5458
* On demand creates a cacheable {@link RestTemplate} instances for the purpose of the Container Registry access.
5559
* Created RestTemplates can be configured to use Http Proxy and/or bypassing the SSL verification.
@@ -197,23 +201,30 @@ private HttpClientBuilder httpClientBuilder(SSLContext sslContext) {
197201
private RestTemplate initRestTemplate(HttpClientBuilder clientBuilder, boolean withHttpProxy, Map<String, String> extra) {
198202

199203
clientBuilder.setDefaultRequestConfig(RequestConfig.custom().setCookieSpec(StandardCookieSpec.RELAXED).build());
200-
204+
DefaultRoutePlanner routePlanner;
201205
// Set the HTTP proxy if configured.
202206
if (withHttpProxy) {
203207
if (!properties.getHttpProxy().isEnabled()) {
204208
throw new ContainerRegistryException("Registry Configuration uses a HttpProxy but non is configured!");
205209
}
206210
HttpHost proxy = new HttpHost(properties.getHttpProxy().getHost(), properties.getHttpProxy().getPort());
207211
clientBuilder.setProxy(proxy);
212+
routePlanner = new DefaultProxyRoutePlanner(proxy, DefaultSchemePortResolver.INSTANCE);
213+
}
214+
else {
215+
routePlanner = new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE);
208216
}
209217

210-
HttpComponentsClientHttpRequestFactory customRequestFactory =
211-
new HttpComponentsClientHttpRequestFactory(
212-
clientBuilder
213-
.setRedirectStrategy(new DropAuthorizationHeaderRequestRedirectStrategy(extra))
214-
// Azure redirects may contain double slashes and on default those are normilised
215-
.setDefaultRequestConfig(RequestConfig.custom().build())
216-
.build());
218+
DropAuthorizationHeaderRequestRedirectStrategy redirectStrategy = new DropAuthorizationHeaderRequestRedirectStrategy(
219+
extra);
220+
HttpComponentsClientHttpRequestFactory customRequestFactory = new HttpComponentsClientHttpRequestFactory(
221+
clientBuilder.setRedirectStrategy(redirectStrategy)
222+
.replaceExecInterceptor(ChainElement.REDIRECT.name(),
223+
new SpecialRedirectExec(routePlanner, redirectStrategy))
224+
// Azure redirects may contain double slashes and on default those are
225+
// normilised
226+
.setDefaultRequestConfig(RequestConfig.custom().build())
227+
.build());
217228

218229
// DockerHub response's media-type is application/octet-stream although the content is in JSON.
219230
// Similarly the Github CR response's media-type is always text/plain although the content is in JSON.

spring-cloud-dataflow-container-registry/src/main/java/org/springframework/cloud/dataflow/container/registry/authorization/DropAuthorizationHeaderRequestRedirectStrategy.java

Lines changed: 58 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@
1818

1919
import java.net.URI;
2020
import java.net.URISyntaxException;
21-
import java.util.Arrays;
2221
import java.util.Map;
2322

2423
import org.apache.hc.client5.http.classic.methods.HttpGet;
2524
import org.apache.hc.client5.http.classic.methods.HttpHead;
26-
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
2725
import org.apache.hc.client5.http.impl.DefaultRedirectStrategy;
2826
import org.apache.hc.core5.http.Header;
2927
import org.apache.hc.core5.http.HttpException;
@@ -92,109 +90,82 @@ public URI getLocationURI(final HttpRequest request, final HttpResponse response
9290
URI httpUriRequest = super.getLocationURI(request, response, context);
9391
String query = httpUriRequest.getQuery();
9492
String method = request.getMethod();
95-
9693
// Handle Amazon requests
9794
if (StringUtils.hasText(query) && query.contains(AMZ_CREDENTIAL)) {
9895
if (isHeadOrGetMethod(method)) {
99-
try {
100-
return new DropAuthorizationHeaderHttpRequestBase(httpUriRequest, method).getUri();
101-
} catch (URISyntaxException e) {
102-
throw new HttpException("Unable to get location URI", e);
103-
}
104-
}
96+
removeAuthorizationHeader(request, response, false);
97+
try {
98+
if (isHeadMethod(method)) {
99+
return new HttpHead(httpUriRequest).getUri();
100+
}
101+
else {
102+
return new HttpGet(httpUriRequest).getUri();
103+
}
104+
}
105+
catch (URISyntaxException e) {
106+
throw new HttpException("Unable to get location URI", e);
107+
}
108+
}
105109
}
106110

107111
// Handle Azure requests
108-
try {
109-
if (request.getUri().getRawPath().contains(AZURECR_URI_SUFFIX)) {
110-
if (isHeadOrGetMethod(method)) {
111-
return (new DropAuthorizationHeaderHttpRequestBase(httpUriRequest, method) {
112-
// Drop headers only for the Basic Auth and leave unchanged for OAuth2
113-
@Override
114-
protected boolean isDropHeader(String name, Object value) {
115-
return name.equalsIgnoreCase(AUTHORIZATION_HEADER) && StringUtils.hasText((String) value) && ((String)value).contains(BASIC_AUTH);
116-
}
117-
}).getUri();
118-
}
119-
}
120-
121-
122-
// Handle Custom requests
123-
if (extra.containsKey(CUSTOM_REGISTRY) && request.getUri().getRawPath().contains(extra.get(CUSTOM_REGISTRY))) {
124-
if (isHeadOrGetMethod(method)) {
125-
return new DropAuthorizationHeaderHttpRequestBase(httpUriRequest, method).getUri();
112+
try {
113+
if (request.getUri().getRawPath().contains(AZURECR_URI_SUFFIX)) {
114+
if (isHeadOrGetMethod(method)) {
115+
removeAuthorizationHeader(request, response, true);
116+
if (isHeadMethod(method)) {
117+
return new HttpHead(httpUriRequest).getUri();
118+
}
119+
else {
120+
return new HttpGet(httpUriRequest).getUri();
121+
}
122+
}
123+
}
124+
125+
// Handle Custom requests
126+
if (extra.containsKey(CUSTOM_REGISTRY)
127+
&& request.getUri().getRawPath().contains(extra.get(CUSTOM_REGISTRY))) {
128+
if (isHeadOrGetMethod(method)) {
129+
removeAuthorizationHeader(request, response, false);
130+
if (isHeadMethod(method)) {
131+
return new HttpHead(httpUriRequest).getUri();
132+
}
133+
else {
134+
return new HttpGet(httpUriRequest).getUri();
135+
}
136+
}
126137
}
127138
}
128-
} catch (URISyntaxException e) {
139+
catch (URISyntaxException e) {
129140
throw new HttpException("Unable to get Locaction URI", e);
130141
}
131142
return httpUriRequest;
132143
}
133144

134-
private boolean isHeadOrGetMethod(String method) {
135-
return StringUtils.hasText(method)
136-
&& (method.equalsIgnoreCase(HttpHead.METHOD_NAME) || method.equalsIgnoreCase(HttpGet.METHOD_NAME));
137-
}
138-
139-
/**
140-
* Overrides all header setter methods to filter out the Authorization headers.
141-
*/
142-
static class DropAuthorizationHeaderHttpRequestBase extends HttpUriRequestBase {
143-
144-
private final String method;
145-
146-
DropAuthorizationHeaderHttpRequestBase(URI uri, String method) {
147-
super(method, uri);
148-
this.method = method;
149-
}
150-
151-
@Override
152-
public String getMethod() {
153-
return this.method;
154-
}
155-
156-
@Override
157-
public void addHeader(Header header) {
158-
if (!isDropHeader(header)) {
159-
super.addHeader(header);
145+
private static void removeAuthorizationHeader(HttpRequest request, HttpResponse response, boolean onlyBasicAuth) {
146+
for (Header header : response.getHeaders()) {
147+
if (header.getName().equalsIgnoreCase(AUTHORIZATION_HEADER)
148+
&& (!onlyBasicAuth || (onlyBasicAuth && header.getValue().contains(BASIC_AUTH)))) {
149+
response.removeHeaders(header.getName());
150+
break;
160151
}
161152
}
162-
163-
@Override
164-
public void addHeader(String name, Object value) {
165-
if (!isDropHeader(name, value)) {
166-
super.addHeader(name, value);
153+
for (Header header : request.getHeaders()) {
154+
if (header.getName().equalsIgnoreCase(AUTHORIZATION_HEADER)
155+
&& (!onlyBasicAuth || (onlyBasicAuth && header.getValue().contains(BASIC_AUTH)))) {
156+
request.removeHeaders(header.getName());
157+
break;
167158
}
168159
}
160+
}
169161

170-
@Override
171-
public void setHeader(Header header) {
172-
if (!isDropHeader(header)) {
173-
super.setHeader(header);
174-
}
175-
}
176-
177-
@Override
178-
public void setHeader(String name, Object value) {
179-
if (!isDropHeader(name, value)) {
180-
super.setHeader(name, value);
181-
}
182-
}
183-
184-
@Override
185-
public void setHeaders(Header[] headers) {
186-
Header[] filteredHeaders = Arrays.stream(headers)
187-
.filter(header -> !isDropHeader(header))
188-
.toArray(Header[]::new);
189-
super.setHeaders(filteredHeaders);
190-
}
191-
192-
protected boolean isDropHeader(Header header) {
193-
return isDropHeader(header.getName(), header.getValue());
194-
}
162+
private boolean isHeadOrGetMethod(String method) {
163+
return StringUtils.hasText(method)
164+
&& (method.equalsIgnoreCase(HttpHead.METHOD_NAME) || method.equalsIgnoreCase(HttpGet.METHOD_NAME));
165+
}
195166

196-
protected boolean isDropHeader(String name, Object value) {
197-
return name.equalsIgnoreCase(AUTHORIZATION_HEADER);
198-
}
167+
private boolean isHeadMethod(String method) {
168+
return StringUtils.hasText(method) && method.equalsIgnoreCase(HttpHead.METHOD_NAME);
199169
}
170+
200171
}

0 commit comments

Comments
 (0)