private void ntlmProxyChallenge( String authenticateHeader, // Request request, // Realm proxyRealm, // HttpHeaders headers, // NettyResponseFuture<?> future) { if (authenticateHeader.equals("NTLM")) { // server replied bare NTLM => we didn't preemptively sent Type1Msg String challengeHeader = NtlmEngine.INSTANCE.generateType1Msg(); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); future.getInProxyAuth().set(false); } else { String serverChallenge = authenticateHeader.substring("NTLM ".length()).trim(); String challengeHeader = NtlmEngine.INSTANCE.generateType3Msg( proxyRealm.getPrincipal(), proxyRealm.getPassword(), proxyRealm.getNtlmDomain(), proxyRealm.getNtlmHost(), serverChallenge); // FIXME we might want to filter current NTLM and add (leave other // Authorization headers untouched) headers.set(HttpHeaders.Names.PROXY_AUTHORIZATION, "NTLM " + challengeHeader); } }
private boolean exitAfterHandling407( // Channel channel, // NettyResponseFuture<?> future, // HttpResponse response, // Request request, // int statusCode, // ProxyServer proxyServer, // HttpRequest httpRequest) { if (future.getInProxyAuth().getAndSet(true)) { logger.info("Can't handle 407 as auth was already performed"); return false; } Realm proxyRealm = future.getProxyRealm(); if (proxyRealm == null) { logger.info("Can't handle 407 as there's no proxyRealm"); return false; } List<String> proxyAuthHeaders = response.headers().getAll(HttpHeaders.Names.PROXY_AUTHENTICATE); if (proxyAuthHeaders.isEmpty()) { logger.info("Can't handle 407 as response doesn't contain Proxy-Authenticate headers"); return false; } // FIXME what's this??? future.setChannelState(ChannelState.NEW); HttpHeaders requestHeaders = new DefaultHttpHeaders(false).add(request.getHeaders()); switch (proxyRealm.getScheme()) { case BASIC: if (getHeaderWithPrefix(proxyAuthHeaders, "Basic") == null) { logger.info( "Can't handle 407 with Basic realm as Proxy-Authenticate headers don't match"); return false; } if (proxyRealm.isUsePreemptiveAuth()) { // FIXME do we need this, as future.getAndSetAuth // was tested above? // auth was already performed, most likely auth // failed logger.info( "Can't handle 407 with Basic realm as auth was preemptive and already performed"); return false; } // FIXME do we want to update the realm, or directly // set the header? Realm newBasicRealm = realm(proxyRealm) // .setUsePreemptiveAuth(true) // .build(); future.setProxyRealm(newBasicRealm); break; case DIGEST: String digestHeader = getHeaderWithPrefix(proxyAuthHeaders, "Digest"); if (digestHeader == null) { logger.info( "Can't handle 407 with Digest realm as Proxy-Authenticate headers don't match"); return false; } Realm newDigestRealm = realm(proxyRealm) // .setUri(request.getUri()) // .setMethodName(request.getMethod()) // .setUsePreemptiveAuth(true) // .parseProxyAuthenticateHeader(digestHeader) // .build(); future.setProxyRealm(newDigestRealm); break; case NTLM: String ntlmHeader = getHeaderWithPrefix(proxyAuthHeaders, "NTLM"); if (ntlmHeader == null) { logger.info("Can't handle 407 with NTLM realm as Proxy-Authenticate headers don't match"); return false; } ntlmProxyChallenge(ntlmHeader, request, proxyRealm, requestHeaders, future); Realm newNtlmRealm = realm(proxyRealm) // .setUsePreemptiveAuth(true) // .build(); future.setProxyRealm(newNtlmRealm); break; case KERBEROS: case SPNEGO: if (getHeaderWithPrefix(proxyAuthHeaders, "Negociate") == null) { logger.info( "Can't handle 407 with Kerberos or Spnego realm as Proxy-Authenticate headers don't match"); return false; } try { kerberosProxyChallenge( channel, proxyAuthHeaders, request, proxyServer, proxyRealm, requestHeaders, future); } catch (SpnegoEngineException e) { // FIXME String ntlmHeader2 = getHeaderWithPrefix(proxyAuthHeaders, "NTLM"); if (ntlmHeader2 != null) { logger.warn("Kerberos/Spnego proxy auth failed, proceeding with NTLM"); ntlmChallenge(ntlmHeader2, request, requestHeaders, proxyRealm, future); Realm newNtlmRealm2 = realm(proxyRealm) // .setScheme(AuthScheme.NTLM) // .setUsePreemptiveAuth(true) // .build(); future.setProxyRealm(newNtlmRealm2); } else { requestSender.abort(channel, future, e); return false; } } break; default: throw new IllegalStateException("Invalid Authentication scheme " + proxyRealm.getScheme()); } RequestBuilder nextRequestBuilder = new RequestBuilder(future.getCurrentRequest()).setHeaders(requestHeaders); if (future.getCurrentRequest().getUri().isSecured()) { nextRequestBuilder.setMethod(CONNECT); } final Request nextRequest = nextRequestBuilder.build(); logger.debug("Sending proxy authentication to {}", request.getUri()); if (future.isKeepAlive() // && HttpHeaders.isKeepAlive(httpRequest) // && HttpHeaders.isKeepAlive(response) // // support broken Proxy-Connection && !response.headers().contains("Proxy-Connection", HttpHeaders.Values.CLOSE, true) // && !HttpHeaders.isTransferEncodingChunked(httpRequest) // && !HttpHeaders.isTransferEncodingChunked(response)) { future.setConnectAllowed(true); future.setReuseChannel(true); requestSender.drainChannelAndExecuteNextRequest(channel, future, nextRequest); } else { channelManager.closeChannel(channel); requestSender.sendNextRequest(nextRequest, future); } return true; }