認証Proxy経由でのChocolateyの利用

# 概要

Windows環境でのパッケージ管理システム[Chocolatey](https://chocolatey.org/)を認証つきProxy経由で導入、使用するために多少の試行錯誤をした。

* 導入は、インストールスクリプトの取得、修正、実行の3ステップが必要になった。
* `clist`の実行には、環境変数を`set HTTP_PROXY=http://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORTNUMBER>`のように設定が必要になった。
* `cinst`の実行には、ヘルパーファイル`Get-WebFile.ps1`と`Get-WebHeaders.ps1`の修正が必要になった。

# 詳細

『[Windowsアプリをコマンドラインからインストールする「Chocolatey」 | マイナビニュース](http://news.mynavi.jp/articles/2013/08/01/chocolately)』を参考に、Chocolateyの導入と、`clist`コマンドの実行までを、認証つきProxy内の環境で行う。

## Chocolateyパッケージをインストールする。

> 「`iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))`」と実行すれば、パッケージのダウンロードおよびインストールが自動的に実行されます。

もちろん失敗する。以下の2ステップで実施できた。

(1)インストールスクリプトの取得

PowerShellで以下のようにして、まず`install.ps1`を取得する。`ユーザー名`、`パスワード`はそれぞれプロキシ認証で使用するユーザー名とパスワードに置き換える。

    $wc = new-object System.Net.WebClient
    $wc.Proxy = [System.Net.WebRequest]::GetSystemWebProxy()
    $wc.Proxy.Credentials = new-object System.Net.NetworkCredential("ユーザー名","パスワード")
    $wc.DownloadString('https://chocolatey.org/install.ps1') > install.ps1

これでカレントディレクトリに`install.ps1`ファイルが保存される。

(2)インストールスクリプトの修正と実行

`install.ps1`をエディタで開き、35行目の...

    $downloader.Proxy.Credentials=[System.Net.CredentialCache]::DefaultNetworkCredentials;

...を、以下に変更する。`ユーザー名`、`パスワード`はそれぞれプロキシ認証で使用するユーザー名とパスワードに置き換える。

    $downloader.Proxy.Credentials = new-object System.Net.NetworkCredential("ユーザー名","パスワード")

上書き保存し、このファイルを実行する。

    .\install.ps1

## clistコマンドの実行

もちろん失敗する。環境変数`HTTP_PROXY`を以下のように設定すれば、`clist`でパッケージリストが出力された。

    set HTTP_PROXY=http://<USERNAME>:<PASSWORD>@<HOSTNAME>:<PORTNUMBER>

なお、<...>部分は環境に合わせて適宜読み替えること。たとえば、以下のようになる。

    set HTTP_PROXY=http://johndoh:jugemujugemu@proxy.example.com:8080

これに関しては、まずこのコマンドは、`clist /?`をすると分かるとおり、実体は`Nuget`だと思ってよさそう。

    usage: NuGet list [search terms] [options]
    (略)
    options:
    (略)
     -ConfigFile               NuGet 構成ファイル。指定しない場合、構成ファイルとして %AppData%\NuGet\NuGet.config ファイルが使用されます。
    
    詳細については、http://docs.nuget.org/docs/reference/command-line-reference を参照してください

NuGetのドキュメントのうち、[NuGet Config Settings](https://docs.nuget.org/consume/nuget-config-settings)を確認したところ、プロキシサーバおよびプロキシ認証情報を、`NuGet.exe Config -Set`コマンドか、または環境変数`HTTP_PROXY`で指定できそうだった。以下抜粋（和訳は筆者）。

<table>
<tr><td>proxy settings</td><td>"http_proxy" , "http_proxy.user", "http_proxy.password"</td><td>Allows you to set the proxy settings to be used while connecting to your NuGet feed. More details here. 
This key can be added using NuGet.exe Config -Set command. <br/>It can also be set via environment variable "http_proxy". While setting env variable, the value should be specified in the format 'http://[username]:[password]@proxy.com'. Note, the "http_proxy.password" key value is encrypted before storing in the nuget.config file. Hence it can not be added manually by directly updating the config file.</td></tr>
<tr><td>プロキシ設定</td><td>"http_proxy" , "http_proxy.user", "http_proxy.password"</td><td>NuGetフィードへの接続に使用されるプロキシ設定を指定できます。詳細は<a href="http://skolima.blogspot.com/2012/07/nuget-proxy-settings.html">こちら</a>。 
このキーは<a href="https://docs.nuget.org/consume/Command-Line-Reference#Config%20Command"><code>NuGet.exe Config -Set</code></a>コマンドを使用して追加できます。<br/>
環境変数"<code>http_proxy</code>"を使用して指定することもできます。環境変数の設定では、'<code>http://[username]:[password]@proxy.com</code>'の書式で指定します。注意、"<code>http_proxy.password</code>"キーの値は保存に先立って暗号化されます。したがって、configファイルを直接更新して追加することはできません。</td></tr>
</table>

前述のとおり、環境変数設定で`clist`が実行できた。

## cinstコマンドの実行

もちろん失敗する。以下の2ファイルを書き換えることで、`cinst vagrant`が実行できた。

ちなみにこれを行うと、プロキシ経由でのファイル取得時には、必ずプロキシ認証入力を求めるダイアログが表示される。インストールスクリプト`install.ps1`と違い使い捨てではないので、認証情報直書きよりこちらのほうがまだ良いと思うが、もちろんスマートではない。できれば`clist`の認証プロキシ対策とあわせて、環境変数`HTTP_PROXY`から取得するようにしたいところ。

(1)Get-WebFile.ps1の修正

`C:\ProgramData\chocolatey\chocolateyinstall\helpers\functions\Get-WebFile.ps1`の39～52行目を、以下のように修正する。42～43、46行をコメントにした（先頭に`#`を追加した）だけ。

      if (!$webclient.Proxy.IsBypassed($url))
      {
        $creds = [net.CredentialCache]::DefaultCredentials
        #if ($creds -eq $null) {
        #  Write-Debug "Default credentials were null. Attempting backup method"
          $cred = get-credential
          $creds = $cred.GetNetworkCredential();
        #}
        $proxyaddress = $webclient.Proxy.GetProxy($url).Authority
        Write-host "Using this proxyserver: $proxyaddress"
        $proxy = New-Object System.Net.WebProxy($proxyaddress)
        $proxy.credentials = $creds
        $req.proxy = $proxy
      }

(2)Get-WebHeaders.ps1の修正

`C:\ProgramData\chocolatey\chocolateyinstall\helpers\functions\Get-WebHeaders.ps1`の22～35行目を、以下のように修正する。25～26、29行をコメントにした（先頭に`#`を追加した）だけ。

      if (!$client.Proxy.IsBypassed($url))
      {
        $creds = [Net.CredentialCache]::DefaultCredentials
        #if ($creds -eq $null) {
        #  Write-Debug "Default credentials were null. Attempting backup method"
          $cred = Get-Credential
          $creds = $cred.GetNetworkCredential();
        #}
        $proxyAddress = $client.Proxy.GetProxy($url).Authority
        Write-Host "Using this proxyserver: $proxyAddress"
        $proxy = New-Object System.Net.WebProxy($proxyAddress)
        $proxy.credentials = $creds
        $request.proxy = $proxy
      }

## 0.9.83より後の版について

上述の対応策は、以下の更新日付のファイルで機能するはず。現行版でこれらのファイルが変更されているかどうかは、GitHubで更新履歴を見て、まずはこの日付より後に更新されているか確認すればいいと思う。

<table>
<tr><th>ファイル</th><th>0.9.83版の更新日</th><th>GitHubの更新履歴</th></tr>
<tr><td><code>Get-WebFile.ps1</code></td><td>2014年11月3日</td><td><a href="https://github.com/chocolatey/chocolatey/commits/master/src/helpers/functions/Get-WebFile.ps1">更新履歴</a></td></tr>
<tr><td><code>Get-WebHeaders.ps1</code></td><td>2014年11月3日</td><td><a href="https://github.com/chocolatey/chocolatey/commits/master/src/helpers/functions/Get-WebHeaders.ps1">更新履歴</a></td></tr>
</table>

# 参考

* [Windowsアプリをコマンドラインからインストールする「Chocolatey」 | マイナビニュース](http://news.mynavi.jp/articles/2013/08/01/chocolately)
* [NuGet Config Settings](https://docs.nuget.org/consume/nuget-config-settings)