会社のイントラサービスがNTLM認証とやらで守られていて、いろいろ調べたところのメモ
NTLMとは
この辺参照。ちと難しい
https://www.innovation.ch/personal/ronald/ntlm.html
Windowsにログインしているユーザ情報で、Webのアクセスの認可・認証をする感じでしょうか。Windowsにログインしている端末からだとユーザ認証を求められず(何も意識せずに)ブラウザでアクセスできるけど、プログラムから接続すると拒否されるような場合は、この環境かもしれません。
ちなみにProxyとは別の話です。外に通信するために特殊な認証をクリアしないといけない場合は、Cntlmを使ってNTLMv2認証Proxy環境をやっつけるを参照。
結論
Guzzile なら簡単だった(ちゃんとマニュアルを読めば解決)
https://guzzle3.readthedocs.io/http-client/client.html#auth
検証
とりあえず普通につなげてみる
$guzzile = new \GuzzleHttp\Client();
$option = ['verify' => false,];
$option['debug']=true;
$option['http_errors']=false;
$url = 'http://local-service...';
$response = $guzzile->get($url, $option);
$body = $response->getBody();
$data = (String)$body;
echo $data;
通信ログ(の一部)
* Trying x.x.x.x...
* TCP_NODELAY set
* Connected to xx.xx.com (x.x.x.x) port 80 (#0)
> GET / HTTP/1.1
Host: xx.xx.com
User-Agent: GuzzleHttp/6.2.1 curl/7.54.1 PHP/7.0.21
< HTTP/1.1 401 Unauthorized
< Content-Type: text/plain; charset=utf-8
< Server: Microsoft-IIS/8.5
< SPRequestGuid:
< request-id:
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 2
< SPIisLatency: 0
< WWW-Authenticate: NTLM
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices:
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Sun, 02 Jun 2019 06:15:15 GMT
< Content-Length: 16
<
* Connection #0 to host xx.xx.com left intact
401 UNAUTHORIZED
結果は、401 UNAUTHORIZED
が返ってくる。認証が必要だということですね。残念。この通信にWWW-Authenticate: NTLM
が入っているのがヒントですね。NTLM認証下で動いているということですね。
オプションを追加する
Guzzileのauthをオプションを追加します。コードの修正は1行追加するだけなので簡単です。authオプションの3番目のオプションがあるのですね。
$guzzile = new \GuzzleHttp\Client();
$option = ['verify' => false,];
$option['debug']=true;
$option['http_errors']=false;
//↓ココ追加
$option['auth'] = ['user', 'password','ntlm'];
$url = 'http://local-service...';
$response = $guzzile->get($url, $option);
$body = $response->getBody();
$data = (String)$body;
echo $data;
通信ログ
* Trying x.x.x.x...
* TCP_NODELAY set
* Connected to xx.xx.com (x.x.x.x) port 80 (#0)
* Server auth using NTLM with user '<USER>'
> GET /index.html HTTP/1.1
Host: xx.xx.com
Authorization: NTLM TlRMTVNTUAAxxx==
User-Agent: GuzzleHttp/6.2.1 curl/7.54.1 PHP/7.0.21
< HTTP/1.1 401 Unauthorized
< Server: Microsoft-IIS/8.5
< WWW-Authenticate: NTLM TlRMTVNTUAAxxxxxxxxxx=
< SPRequestGuid:
< request-id:
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 1
< SPIisLatency: 0
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 15.0.0.4569
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Sun, 02 Jun 2019 11:30:03 GMT
< Content-Length: 0
<
* Connection #0 to host xx.xx.com left intact
* Issue another request to this URL: 'http://xx.xx.com/'
* Found bundle for host xx.xx.com: 0x15025758 [can pipeline]
* Re-using existing connection! (#0) with host xx.xx.com
* Connected to xx.xx.com (x.x.x.x) port 80 (#0)
* Server auth using NTLM with user '<USER>'
> GET /index.html HTTP/1.1
Host: xx.xx.com
Authorization: NTLM TlRMTVNTUAAxxxxxxxxxx=
User-Agent: GuzzleHttp/6.2.1 curl/7.54.1 PHP/7.0.21
< HTTP/1.1 200 OK
< Cache-Control: private, max-age=0
< Content-Type: text/html; charset=utf-8
< Expires: Sat, 18 May 2019 11:30:03 GMT
< Last-Modified: Sun, 02 Jun 2019 11:30:03 GMT
< Server: Microsoft-IIS/8.5
< X-SharePointHealthScore: 0
< X-AspNet-Version: 4.0.30319
< Set-Cookie:
< Set-Cookie:
< Set-Cookie:
< SPRequestGuid: 0fa2e29e-1880-7002-7a3b-08c82a909236
< request-id: 0fa2e29e-1880-7002-7a3b-08c82a909236
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 453
< SPIisLatency: 0
< Persistent-Auth: true
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 15.0.0.4569
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Sun, 02 Jun 2019 11:30:03 GMT
< Content-Length: 95613
<
* Connection #0 to host xx.xx.com left intact
<!DOCTYPE html >
以下、HTMLなので省略
無事にHTMLが取れました。
もうちょっと細かく見てみる
IDとパスワードを渡して通信すると、Guzzileによって自動的に2回の通信が行われます。
1回目の通信で、Authorization
ヘッダーがGuzzileによって付与されます。
> GET /index.html HTTP/1.1
Host: xx.xx.com
Authorization: NTLM TlRMTVNTUAAxxx==
そうすると、サーバーからWWW-Authenticate
ヘッダーが返ってきます。
< HTTP/1.1 401 Unauthorized
< Server: Microsoft-IIS/8.5
< WWW-Authenticate: NTLM TlRMTVNTUAAxxxxxxxxxx=
2回目の通信は、1回目の通信のレスポンスヘッダーの値をAuthorization
としてに渡します。
> GET /index.html HTTP/1.1
Host: xx.xx.com
Authorization: NTLM TlRMTVNTUAAxxxxxxxxxx=
そうすると、無事、欲しかったコンテンツが返ってきます。