@@ -62,11 +62,13 @@ public class Redirect30xInterceptor {
6262 private final AsyncHttpClientConfig config ;
6363 private final NettyRequestSender requestSender ;
6464 private final MaxRedirectException maxRedirectException ;
65+ private final boolean stripAuthorizationOnRedirect ;
6566
6667 Redirect30xInterceptor (ChannelManager channelManager , AsyncHttpClientConfig config , NettyRequestSender requestSender ) {
6768 this .channelManager = channelManager ;
6869 this .config = config ;
6970 this .requestSender = requestSender ;
71+ this .stripAuthorizationOnRedirect = config .isStripAuthorizationOnRedirect ();
7072 maxRedirectException = unknownStackTrace (new MaxRedirectException ("Maximum redirect reached: " + config .getMaxRedirects ()), Redirect30xInterceptor .class ,
7173 "exitAfterHandlingRedirect" );
7274 }
@@ -92,15 +94,35 @@ public boolean exitAfterHandlingRedirect(Channel channel,
9294 && !originalMethod .equals (OPTIONS ) && !originalMethod .equals (HEAD ) && (statusCode == MOVED_PERMANENTLY_301 || statusCode == SEE_OTHER_303 || (statusCode == FOUND_302 && !config .isStrict302Handling ()));
9395 boolean keepBody = statusCode == TEMPORARY_REDIRECT_307 || statusCode == PERMANENT_REDIRECT_308 || (statusCode == FOUND_302 && config .isStrict302Handling ());
9496
97+ HttpHeaders responseHeaders = response .headers ();
98+ String location = responseHeaders .get (LOCATION );
99+ Uri newUri = Uri .create (future .getUri (), location );
100+ LOGGER .debug ("Redirecting to {}" , newUri );
101+
102+ boolean sameBase = request .getUri ().isSameBase (newUri );
103+ boolean schemeDowngrade = request .getUri ().isSecured () && !newUri .isSecured ();
104+ boolean stripAuth = !sameBase || schemeDowngrade || stripAuthorizationOnRedirect ;
105+
106+ if (stripAuth && (request .getRealm () != null || request .getHeaders ().contains (AUTHORIZATION ))) {
107+ LOGGER .debug ("Stripping credentials on redirect to {}" , newUri );
108+ }
109+
95110 final RequestBuilder requestBuilder = new RequestBuilder (switchToGet ? GET : originalMethod )
96111 .setChannelPoolPartitioning (request .getChannelPoolPartitioning ())
97112 .setFollowRedirect (true )
98113 .setLocalAddress (request .getLocalAddress ())
99114 .setNameResolver (request .getNameResolver ())
100115 .setProxyServer (request .getProxyServer ())
101- .setRealm (request .getRealm ())
116+ .setRealm (stripAuth ? null : request .getRealm ())
102117 .setRequestTimeout (request .getRequestTimeout ());
103118
119+ if (stripAuth ) {
120+ // Clear both realms on the future so NettyRequestFactory cannot regenerate
121+ // Authorization or Proxy-Authorization headers on the redirected request.
122+ future .setRealm (null );
123+ future .setProxyRealm (null );
124+ }
125+
104126 if (keepBody ) {
105127 requestBuilder .setCharset (request .getCharset ());
106128 if (isNonEmpty (request .getFormParams ()))
@@ -118,18 +140,13 @@ else if (isNonEmpty(request.getBodyParts())) {
118140 }
119141 }
120142
121- requestBuilder .setHeaders (propagatedHeaders (request , realm , keepBody ));
143+ requestBuilder .setHeaders (propagatedHeaders (request , realm , keepBody , stripAuth ));
122144
123145 // in case of a redirect from HTTP to HTTPS, future
124146 // attributes might change
125147 final boolean initialConnectionKeepAlive = future .isKeepAlive ();
126148 final Object initialPartitionKey = future .getPartitionKey ();
127149
128- HttpHeaders responseHeaders = response .headers ();
129- String location = responseHeaders .get (LOCATION );
130- Uri newUri = Uri .create (future .getUri (), location );
131- LOGGER .debug ("Redirecting to {}" , newUri );
132-
133150 CookieStore cookieStore = config .getCookieStore ();
134151 if (cookieStore != null ) {
135152 // Update request's cookies assuming that cookie store is already updated by Interceptors
@@ -140,8 +157,6 @@ else if (isNonEmpty(request.getBodyParts())) {
140157 }
141158 }
142159
143- boolean sameBase = request .getUri ().isSameBase (newUri );
144-
145160 if (sameBase ) {
146161 // we can only assume the virtual host is still valid if the baseUrl is the same
147162 requestBuilder .setVirtualHost (request .getVirtualHost ());
@@ -174,7 +189,7 @@ else if (isNonEmpty(request.getBodyParts())) {
174189 return false ;
175190 }
176191
177- private HttpHeaders propagatedHeaders (Request request , Realm realm , boolean keepBody ) {
192+ private HttpHeaders propagatedHeaders (Request request , Realm realm , boolean keepBody , boolean stripAuthorization ) {
178193
179194 HttpHeaders headers = request .getHeaders ()
180195 .remove (HOST )
@@ -184,7 +199,7 @@ private HttpHeaders propagatedHeaders(Request request, Realm realm, boolean keep
184199 headers .remove (CONTENT_TYPE );
185200 }
186201
187- if (realm != null && realm .getScheme () == AuthScheme .NTLM ) {
202+ if (stripAuthorization || ( realm != null && realm .getScheme () == AuthScheme .NTLM ) ) {
188203 headers .remove (AUTHORIZATION )
189204 .remove (PROXY_AUTHORIZATION );
190205 }
0 commit comments