0

로드 균형 조정기에 대한 SharePoint REST 호출 문제가 발생했습니다. REST 호출을 웹 서버에 직접 보내면 모든 것이 제대로 작동하는 것 같습니다. 그러나 REST 호출이로드 균형 조정기로 보내지면 첫 번째 호출 만 HTTP 200 OK 상태가되고 나머지는 HTTP 401 Unauthorized가 반환됩니다. 몇 가지 연구를 한 후 this article이라는 메시지를 발견했습니다 :Apache HttpClient로 SharePoint REST 호출 및로드 균형 조정이 처음 실패한 후 발생합니다.

이것은 버그가 아닙니다. 해당 컴퓨터 이름이 NETBIOS 이름과 일치하지 않으면 루프백 주소로 확인되는 컴퓨터 이름이 연결을 수락하지 못하도록하는 Windows 네트워킹 스택에 보안 픽스가 내장되어 있습니다.

유일한 조항은 서버의 구성을 변경하는 것입니다. 이는 우리 부서가 기꺼이 수행 할 작업이 아닙니다.

목표는 Java 응용 프로그램에서 SharePoint REST 호출을 수행 할 수 있다는 것입니다.

예를 들어 버튼을 누르면 SharePoint REST API에 GET 요청을 보내도록 작은 테스트 프로그램을 만들었습니다.

//first button click 
Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1 
[principal: domain.com\<username>] [workstation: <LBSERVER>] 
---------------------------------------- 
HTTP/1.1 200 OK 

//second button click 
Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1 
[principal: domain.com\<username>] [workstation: <LBSERVER>] 
---------------------------------------- 
HTTP/1.1 200 OK 

그러나, 같이

내가 내 윈도우 (로드 밸런서에서) 우리의 웹 서버 중 하나의 IP 주소에 대한 부하 분산 URL을 매핑 할 파일을 호스트 조정하는 경우, 모든 것이 잘 작동하는 것 같다 곧 매핑을 주석 처리하고 요청이로드 밸런서로 이동하면 문제가 발생하기 시작합니다.

//first button click 
Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1') HTTP/1.1 
[principal: domain.com\<username>] [workstation: <LBSERVER>] 
---------------------------------------- 
HTTP/1.1 200 OK 

//second button click 
Executing request GET https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('2') HTTP/1.1 
[principal: domain.com\<username>] [workstation: <LBSERVER>] 
---------------------------------------- 
HTTP/1.1 401 Unauthorized 

첫 번째 GET 요청은 정상적으로 실행됩니다. 그 후 HTTP 401 Unauthorized 오류가 발생합니다.

HttpClient가 인증/세션을 잃어 버리는 이유는 (첫 번째 요청이 잘 돌아 갔음) 인증 데이터가 HttpContext 내부에 있더라도? 이 문제를 해결하기 위해 클라이언트 코드에 누락 된 것이 있습니까?


업데이트 :

의 OpenClient()와 가져 오기() 메소드 내부 된, closeClient()를 호출 할 때, 두 요청이 잘 작동 GET. 하지만 내가 생각하는 httpClient를 다시 만들 필요는 없습니다.


다음은 전체의 코드입니다 :

CloseableHttpClient httpClient; 
CredentialsProvider credsProvider; 
HttpClientContext context; 
HttpHost targetHost; 

Account account; 

private void handleButtonAction(ActionEvent event) throws IOException { 
    get("https://lbserver.domain.com/sites/my_site/_api/web/Lists/getByTitle('Registratielijst')/Items('1')"); 
} 

private void get(String uri) throws IOException { 
    HttpGet httpget = new HttpGet(uri); 

    System.out.println("\nExecuting request " + httpget.getRequestLine()); 

    CloseableHttpResponse response = httpClient.execute(targetHost, httpget, context); 
    System.out.println("----------------------------------------"); 
    System.out.println(response.getStatusLine()); 

    response.close(); 
} 

private void openClient() throws IOException { 
    System.out.println("Open client"); 

    httpClient = HttpClients.createDefault(); 
    targetHost = new HttpHost("lbserver.domain.com", 443, "https"); 
    context = HttpClientContext.create(); 

    credsProvider = new BasicCredentialsProvider(); 
    credsProvider.setCredentials(
      new AuthScope(targetHost, AuthScope.ANY_REALM, "ntlm"), 
      new NTCredentials(account.getUsername(), account.getPassword(), "lbserver", "domain.com")); 

    context.setCredentialsProvider(credsProvider); 

    CookieStore cookieStore = new BasicCookieStore(); 
    context.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore); 
} 

private void closeClient() throws IOException { 
    System.out.println("Close client"); 
    if (httpClient != null) { 
     httpClient.close(); 
    } 
} 

public void initialize(URL url, ResourceBundle rb) { 
    account = new Account(); 

    try { 
     openClient(); 
    } catch (IOException ex) { 
     Logger.getLogger(FXMLController.class.getName()).log(Level.SEVERE, null, ex); 
    } 

    Runtime.getRuntime().addShutdownHook(new Thread(new Task() { 
     @Override 
     protected Object call() throws Exception { 
      closeClient(); 
      return null; 
     } 
    })); 
} 

답변

0

좀 더 연구 후에, 나는 문제가 잘못된 쿠키 처리에 의해 발생했다 발견. 원인은 CookieSpecs.DEFAULT (RFC2109)을 사용하는 Apache HTTP 클라이언트입니다. 이 값을 CookieSpecs.STANDARD (RFC6265)으로 변경하면 제대로 작동합니다.

RequestConfig localConfig = RequestConfig.custom() 
      .setCookieSpec(CookieSpecs.STANDARD) 
      .setTargetPreferredAuthSchemes(Arrays.asList(AuthSchemes.NTLM)) 
      .build(); 

httpClient = HttpClients.custom() 
      .setDefaultCookieStore(new BasicCookieStore()) 
      .setDefaultCredentialsProvider(credsProvider) 
      .setDefaultRequestConfig(localConfig) 
      .build(); 
관련 문제