예제 #1
0
  private void updateAuthState(
      final AuthState authState, final HttpHost host, final CredentialsProvider credsProvider) {

    if (!authState.isValid()) {
      return;
    }

    String hostname = host.getHostName();
    int port = host.getPort();
    if (port < 0) {
      Scheme scheme = connManager.getSchemeRegistry().getScheme(host);
      port = scheme.getDefaultPort();
    }

    AuthScheme authScheme = authState.getAuthScheme();
    AuthScope authScope =
        new AuthScope(hostname, port, authScheme.getRealm(), authScheme.getSchemeName());

    if (this.log.isDebugEnabled()) {
      this.log.debug("Authentication scope: " + authScope);
    }
    Credentials creds = authState.getCredentials();
    if (creds == null) {
      creds = credsProvider.getCredentials(authScope);
      if (this.log.isDebugEnabled()) {
        if (creds != null) {
          this.log.debug("Found credentials");
        } else {
          this.log.debug("Credentials not found");
        }
      }
    } else {
      if (authScheme.isComplete()) {
        this.log.debug("Authentication failed");
        creds = null;
      }
    }
    authState.setAuthScope(authScope);
    authState.setCredentials(creds);
  }
예제 #2
0
  private void processChallenges(
      final Map<String, Header> challenges,
      final AuthState authState,
      final AuthenticationHandler authHandler,
      final HttpResponse response,
      final HttpContext context)
      throws MalformedChallengeException, AuthenticationException {

    AuthScheme authScheme = authState.getAuthScheme();
    if (authScheme == null) {
      // Authentication not attempted before
      authScheme = authHandler.selectScheme(challenges, response, context);
      authState.setAuthScheme(authScheme);
    }
    String id = authScheme.getSchemeName();

    Header challenge = challenges.get(id.toLowerCase(Locale.ENGLISH));
    if (challenge == null) {
      throw new AuthenticationException(id + " authorization challenge expected, but not found");
    }
    authScheme.processChallenge(challenge);
    this.log.debug("Authorization challenge processed");
  }
예제 #3
0
  /**
   * Creates a tunnel to the target server. The connection must be established to the (last) proxy.
   * A CONNECT request for tunnelling through the proxy will be created and sent, the response
   * received and checked. This method does <i>not</i> update the connection with information about
   * the tunnel, that is left to the caller.
   *
   * @param route the route to establish
   * @param context the context for request execution
   * @return <code>true</code> if the tunnelled route is secure, <code>false</code> otherwise. The
   *     implementation here always returns <code>false</code>, but derived classes may override.
   * @throws HttpException in case of a problem
   * @throws IOException in case of an IO problem
   */
  protected boolean createTunnelToTarget(HttpRoute route, HttpContext context)
      throws HttpException, IOException {

    HttpHost proxy = route.getProxyHost();
    HttpHost target = route.getTargetHost();
    HttpResponse response = null;

    boolean done = false;
    while (!done) {

      done = true;

      if (!this.managedConn.isOpen()) {
        this.managedConn.open(route, context, this.params);
      }

      HttpRequest connect = createConnectRequest(route, context);

      String agent = HttpProtocolParams.getUserAgent(params);
      if (agent != null) {
        connect.addHeader(HTTP.USER_AGENT, agent);
      }
      connect.addHeader(HTTP.TARGET_HOST, target.toHostString());

      AuthScheme authScheme = this.proxyAuthState.getAuthScheme();
      AuthScope authScope = this.proxyAuthState.getAuthScope();
      Credentials creds = this.proxyAuthState.getCredentials();
      if (creds != null) {
        if (authScope != null || !authScheme.isConnectionBased()) {
          try {
            connect.addHeader(authScheme.authenticate(creds, connect));
          } catch (AuthenticationException ex) {
            if (this.log.isErrorEnabled()) {
              this.log.error("Proxy authentication error: " + ex.getMessage());
            }
          }
        }
      }

      response = requestExec.execute(connect, this.managedConn, context);

      int status = response.getStatusLine().getStatusCode();
      if (status < 200) {
        throw new HttpException(
            "Unexpected response to CONNECT request: " + response.getStatusLine());
      }

      CredentialsProvider credsProvider =
          (CredentialsProvider) context.getAttribute(ClientContext.CREDS_PROVIDER);

      if (credsProvider != null && HttpClientParams.isAuthenticating(params)) {
        if (this.proxyAuthHandler.isAuthenticationRequested(response, context)) {

          this.log.debug("Proxy requested authentication");
          Map<String, Header> challenges = this.proxyAuthHandler.getChallenges(response, context);
          try {
            processChallenges(
                challenges, this.proxyAuthState, this.proxyAuthHandler, response, context);
          } catch (AuthenticationException ex) {
            if (this.log.isWarnEnabled()) {
              this.log.warn("Authentication error: " + ex.getMessage());
              break;
            }
          }
          updateAuthState(this.proxyAuthState, proxy, credsProvider);

          if (this.proxyAuthState.getCredentials() != null) {
            done = false;

            // Retry request
            if (this.reuseStrategy.keepAlive(response, context)) {
              this.log.debug("Connection kept alive");
              // Consume response content
              HttpEntity entity = response.getEntity();
              if (entity != null) {
                entity.consumeContent();
              }
            } else {
              this.managedConn.close();
            }
          }

        } else {
          // Reset proxy auth scope
          this.proxyAuthState.setAuthScope(null);
        }
      }
    }

    int status = response.getStatusLine().getStatusCode();

    if (status > 299) {

      // Buffer response content
      HttpEntity entity = response.getEntity();
      if (entity != null) {
        response.setEntity(new BufferedHttpEntity(entity));
      }

      this.managedConn.close();
      throw new TunnelRefusedException(
          "CONNECT refused by proxy: " + response.getStatusLine(), response);
    }

    this.managedConn.markReusable();

    // How to decide on security of the tunnelled connection?
    // The socket factory knows only about the segment to the proxy.
    // Even if that is secure, the hop to the target may be insecure.
    // Leave it to derived classes, consider insecure by default here.
    return false;
  } // createTunnelToTarget