UiPath製品群をプロキシ環境で使用するための環境設定手順(認証ありプロキシのケース)

UiPath製品でプロキシを越える件の最後の記事。ようやく**認証ありプロキシを越えます**。


## イントロ

ここ最近 UiPath 製品で「認証プロキシを越える」件を絶賛整理中です。その備忘。
先に、「認証なし」のプロキシを越える件は

- [UiPath製品群をプロキシ環境で使用するための環境設定(UiPath Enterprise版/認証なしプロキシのケース)](https://qiita.com/masatomix/items/43e691e7d47e54638984)
- [UiPath製品群をプロキシ環境で使用するための環境設定(UiPath Community版/認証なしプロキシのケース)](https://qiita.com/masatomix/items/5be2a61a594307f5979a)

に整理することができました。さて本丸の**「認証あり」プロキシを越える件**ですが、

https://docs.microsoft.com/ja-jp/dotnet/framework/configure-apps/file-schema/network/defaultproxy-element-network-settings

このへんを見ながら**「IEのプロキシ設定」を参照できれば認証もろとも解決かな？**と思ってたんですが、なかなかうまくいきません。どうしてもID/Passをうまく渡せなくて、HTTPステータスコードが407(Proxy Authentication Required) になってしまいます。

![error.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/5f6e6bb9-6d3c-1cbb-050c-130b6d0df827.png)

図的にはこんなかんじ。

![Proxy_NG.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/ce439f55-9e1d-63f2-0a22-744fd573c449.png)

というわけで、もう少し調査してみたところ **認証情報を付加するDLLを作成するやり方**があるようで、やってみました。

## 前提

- Enterprise版は、UiPath Studio 2019.10.2 Enterprise 版/Orchestrator 2019.10.15 で確認を行いました。
- Community版は、UiPath Studio 2019.10.2 Community 版/Orchestrator Community版 2019.12.6 で確認を行いました。


## UiPathのプログラムたち

先ほどの記事でも書きましたが、UiPath製品はおおむね下記のプログラムたちで構成されています。

- **UiPath.Service.Host.exe** :(サイトより引用)すべての操作の頭脳です。(Enterprise版で、Windowsサービス)
- **UiPath.Service.UserHost.exe** :(サイトより引用)すべての操作の頭脳です。(Community版で、ユーザモードで起動)
- **NuGetのプログラム**: アクティビティパッケージのダウンロードを行います
- **UiPath.Executor.exe**: (サイトより引用)プロセスの実行を直接担当するコンポーネントです。
- **UiPath.Agent.exe**: (サイトより引用)Robot の実際のユーザーインターフェースです。
- **UiPath Studio**: 開発ツールです
- **Regutil.exe**: (サイトより引用)マシンをオンラインまたはオフラインでアクティベーションできる簡易コマンドラインツールです。→ OCに繋ぐばあいは不要なので、今回は調査対象外としました。

これらをざっくりと 

- ``*.exe`` 系
    - ``UiPath.Service.Host.exe``
    - ``UiPath.Service.UserHost.exe``
    - ``UiPath.Executor.exe``
    - ``UiPath.Agent.exe``
- NuGet系(含むUiPath Studio)[^1]

と分類しておきます。

[^1]: UiPath Studioは、nupkgのダウンロードをするときに NuGetの設定ファイルを見ているっていう点でこちらに含まれる

## TL;DR

それぞれの設定方法を整理すると、以下の通りとなりました。

- ``*.exe`` 系は、**認証情報を保持するプログラム(DLL)を作って、それぞれの exe の設定ファイル(``*.exe.config``) でそのDLLを指定**する
- NuGet系は いくつかの設定ファイル **``NuGet.Config``にコマンドを使って認証情報を追記**する
- ただし **UiPathのEnterprise版だけ**はどうしても ``NuGet.Config``で「認証ありプロキシ」を越えられなかったので、**Enterprise版でかつ ``NuGet.Config`` をみるモノは代替案**で問題を回避する

という結果となりました。


## ``*.exe`` 系

ではひとつずつみていきます。まずは ``*.exe`` 系。
認証情報を保持するC#のプログラムを書いてコンパイルしてDLL化し、それをUiPath製品群に登録します。どうもこのやり方は、UiPathのようなクライアントアプリが「認証ありプロキシ」を越える際の正攻法っぽいですね。

![Proxy_DLL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/6aa2f79a-2eaf-fbec-c14b-de84a8d98039.png)


以下、作業手順。

### コードを書く

本来C#のプログラムは Visual Studio 上でプロジェクトを作成して、その中でコードを書いていくのですが、説明も面倒なので今回はプロジェクトは作成しないやり方で。
ただ Visual Studioはコンパイラとして使用するので、**Visual Studioのインストール**だけはしておいてください(手順は割愛します、、、)。

さて、下記のようなコードを書きます。

```c#:MyWebProxy.cs
using System;
using System.Net;

namespace ProxyLib
{
    public class MyWebProxy : IWebProxy
    {
        private IWebProxy proxy = new WebProxy("http://192.168.xx.xx:3128") // ProxyのURL
        {
            Credentials = new NetworkCredential("user01", "user01") // ID/Pass
        };

        public ICredentials Credentials
        {
            get => proxy.Credentials;
            set { }
        }

        public Uri GetProxy(Uri destination)
        {
            return proxy.GetProxy(destination);
        }

        public bool IsBypassed(Uri host)
        {
            return proxy.IsBypassed(host);
        }
    }
}
```

DLLとして登録するプログラムは``IWebProxy``インタフェースを実装しないといけないので、そのルールに従ってプロキシのURLや認証プロキシの ID/Pass を記述しておきました。[^2]

[^2]: コード上に埋め込んでイイの？とか、実際の運用のことは考慮していません。ご了承ください :-)


### コンパイルする

当方の環境は Visual Studio 2017 がインストールされていますが、Visual Studioが入ってるとスタートメニューに **「開発者コマンド プロンプト for VS 2017」 などがある**と思いますので、それを起動します。コマンドプロンプトが起動するので、ソースコードがあるディレクトリに移動して

```console
**********************************************************************
** Visual Studio 2017 Developer Command Prompt v15.9.17
** Copyright (c) 2017 Microsoft Corporation
**********************************************************************

C:\Program Files (x86)\Microsoft Visual Studio\2017\Community>
cd .......
T:\> 
T:\> dir MyWebProxy.cs
2020/01/12  01:44               663 MyWebProxy.cs

T:\> csc /target:library MyWebProxy.cs
Microsoft (R) Visual C# Compiler バージョン 2.10.0.0 (b9fb1610)
Copyright (C) Microsoft Corporation. All rights reserved.

T:\> dir MyWebProxy.dll
2020/01/12  01:46             3,584 MyWebProxy.dll
```

などと実行してください。コードがコンパイルされ``MyWebProxy.dll``が作成されたと思います。

### 設定ファイルを変更する

さて、``*.exe``系の設定ファイルは、それぞれ ``*.exe.config`` でした。ファイルの**置き場所は Enterprise/Community 版で異なりますので、設定ファイルの場所は前回の記事を適宜ご確認**ください。


> あ、おなじみですがEnterprise版の「更新に管理者権限が必要なファイル群」は、該当ファイルを直接ひらいて修正・保存すると、WindowsのVirtualStoreという仕組みにより他のパス``C:\Users\[ユーザ名]\AppData\Local\VirtualStore\...`` に保存されたりしてよけいなトラブルに巻き込まれますので、別のフォルダで編集・保存した後エクスプローラでコピー・上書きするようにしてください。

さて認証なしプロキシのときは ``*.exe.config``に

```xml:*.exe.config
<system.net>
  <defaultProxy>
    <proxy
      usesystemdefault="true"
      proxyaddress="http://127.0.0.1:8888"
      bypassonlocal="true"
    />
  </defaultProxy>
</system.net>
```

などと記述していましたが、その箇所を以下のように記述して、作成したDLLを登録します。

```xml:*.exe.config
<system.net>
  <defaultProxy useDefaultCredentials="true" enabled="true">
    <module type="ProxyLib.MyWebProxy, MyWebProxy" />
  </defaultProxy>
</system.net>
```

``ProxyLib.MyWebProxy`` は名前空間付きのクラス名、``MyWebProxy``は DLLのファイル名です。
最後に先ほど作成した **``MyWebProxy.dll`` を、これらconfigファイルがある場所に配置すればOK**です。

サービスの再起動をして設定を反映させたいところですが、**NuGet系の修正を行ってから**にしましょう。

## NuGet系

一方、NuGet系はDLLを用いるのではなく、**設定ファイルに認証プロキシの情報を記述する**ことが可能です。
記述の手順は、設定ファイルに**直接書き込むのではなく、下記のコマンドを実行**します(パスワードなどが暗号化(？)されて書き込まれます)。

```console
C:\Users\xxx> nuget config -set http_proxy=http://192.168.xx.xx:3128
C:\Users\xxx> nuget config -set http_proxy.user=user01
C:\Users\xxx> nuget config -set http_proxy.password=user01
```

> nuget コマンドが存在しない場合は、 
> https://dist.nuget.org/win-x86-commandline/latest/nuget.exe
> をダウンロードして、パスを通すか、ダウンロードした場所を絶対パス指定して実行してください。
> ``C:\Users\xxx> C:\Users\xxx\Downloads\nuget config -set http_proxy.user=user01``
> みたいな感じで。


これらを実行すると``%appdata%\NuGet\NuGet.Config (C:\Users\xxx\AppData\Roaming\NuGet\NuGet.Config )`` に値が書き込まれます。

```xml
<config>
  <add key="http_proxy" value="http://192.168.xx.xx:3128" />
  <add key="http_proxy.user" value="user01" />
  <add key="http_proxy.password" value="AQAAANCM...3sAefg=" />
</config>
```

Community版はこのファイルを参照しているのでこれでOKなんですが、**Enterprise版は``C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config`` も参照しているので、そちらにも転記**しておきます。

各種設定ファイルの記述が終わったので、参照しているプロセスたちを再起動しましょう。
**Enterprise版はWindowsサービスの再起動**、**Community版はプロセスの再起動**を行ってください(具体的な手順は、前記事をご参照ください)。


## 稼働確認

さっそく Community版/Enterprise版それぞれで稼働確認をしていきましょう。

### Community版

接続切断です。
![OK01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/d741ca19-3b14-5754-245c-75e434c2518a.png)

OKそうですね。その他、タスクトレイからnupkgダウンロード、Studioでの操作など一通りやってみてください。

![OK02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/2e08ed86-8a58-9992-e98a-2d4a90b670a2.png)

Community版は以上です。お疲れさまでした。


### Enterprise版

さてEnterprise版ですが、、、接続切断は問題なさそうですが、タスクトレイからnupkgダウンロードをしてみると、、

![NG01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/9367c085-a641-61b6-58a2-2b4badc1825c.png)

うーん、この[エラーが再発](https://qiita.com/masatomix/items/43e691e7d47e54638984#uipathservicehostexeconfig-%E3%81%A0%E3%81%91%E3%82%92%E3%83%97%E3%83%AD%E3%82%AD%E3%82%B7%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B%E3%81%A8%E3%83%88%E3%83%A9%E3%83%96%E3%81%A3%E3%81%9F)しました。いろいろと調べてみたのですが原因不明です。。。

ということで、**Community版ではDLL追加と``NuGet.Config`` への設定追加で認証ありプロキシを越えることができました**が、**Enterprise版はさらにもうひと手間必要**になります。


## 他のツールに認証ありプロキシを越えてもらう

さてさてEnterprise版のこの問題ですが、下図のようにプロキシを中継するツール「[HttpProxyAuth](https://www.vector.co.jp/soft/winnt/net/se499627.html)」を導入して、**UiPath製品のうちNuGet系だけは認証なしプロキシ「HttpProxyAuth」を指定して、認証ありプロキシをHttpProxyAuth にかわりに越えてもらう**という方式をとってみます。

![Proxy_HttpProxyAuth.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/6d8279d4-3a7f-d5e5-982c-e4efee3a7646.png)


### ダウンロード・起動

https://www.vector.co.jp/soft/winnt/net/se499627.html よりダウンロードして、適当なディレクトリ(ここでは``t:\Tools\HttpProxyAuth``にしました)に解凍しておきましょう。

プロンプトからHttpProxyAuthを起動してみます。

```console
C:\Windows\System32> t:
T:\> cd T:\Tools\HttpProxyAuth
T:\Tools\HttpProxyAuth>dir

2013/04/25  16:44            32,768 HttpProxyAuth.exe
2016/03/08  10:14             3,835 ReadMe.txt

T:\Tools\HttpProxyAuth> HttpProxyAuth.exe "user01:user01@192.168.xx.xx:3128" 8889
認証プロキシサーバ = 192.168.xx.xx:3128
ユーザ:パスワード  = user01:user01
ローカルポート     = 8889
コンソール表示有無 = 0
認証プロキシとの中継を開始しました。
```

引数の意味は

```
HttpProxyAuth.exe "[ID]:[Pass]@[ProxyのURL]:[Port]" 認証なしプロキシ(HttpProxyAuth)自体のPort番号
```

です。**「引数で指定した認証ありプロキシに処理を転送する」認証なしプロキシを``http://localhost:8889`` で起動させる**って意味です。
HttpProxyAuthは、**この認証なしプロキシにアクセスすれば、引数のID/Passを使ってかわりに認証ありプロキシを越えてくれる**とても便利なツールです。


### NuGet.Configを認証なしプロキシに設定変更する

Enterprise版が参照する ``NuGet.Config``は、

- ``%appdata%\NuGet\NuGet.Config`` 
- ``C:\Windows\SysWOW64\config\systemprofile\AppData\Roaming\NuGet\NuGet.Config`` 

でした。さきほど書いた認証ありプロキシの設定が書かれているはずですので、いま**作成した ``http://localhost:8889``という認証なしプロキシを使用するように設定を変更**します。

変更前:

```xml:NuGet.Config(抜粋)
<config>
  <add key="http_proxy" value="http://192.168.xx.xx:3128" />
  <add key="http_proxy.user" value="user01" />
  <add key="http_proxy.password" value="AQAAANCM...3sAefg=" />
</config>
```

変更後:

```xml:NuGet.Config(抜粋)
<config>
  <add key="http_proxy" value="http://localhost:8889" />
</config>
```

さあ、**Windowsサービスをまた再起動して、先ほどNGだったnupkgのダウンロードで疎通確認**してみましょう。

![OK03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/b66a8225-83f0-2189-c42a-185825d1249a.png)

![OK04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/db6b6160-ec5f-4168-7773-148106a5ebe0.png)

ダウンロード出来ました！他の処理も試してみて、DLLをつかったり HttpProxyAuth を使ったりして、どの処理も認証ありプロキシを越えられることを確認しておきましょう。

### バッチファイルにしておく

先ほど実行したコマンドは、後のためにバッチファイルにしておきます。

```console
T:\tools\HttpProxyAuth> dir
 T:\tools\HttpProxyAuth のディレクトリ

2013/04/25  16:44            32,768 HttpProxyAuth.exe
2016/03/08  10:14             3,835 ReadMe.txt
2020/01/12  14:07                57 run_proxy.bat   ← コレをエディタなどで作成しておく。

T:\tools\HttpProxyAuth> type run_proxy.bat   ← ファイルの中身を確認するコマンド
HttpProxyAuth.exe "user01:user01@192.168.xx.xx:3128" 8889

-- 起動してみる -- 

T:\tools\HttpProxyAuth> run_proxy.bat

T:\Tools\HttpProxyAuth> HttpProxyAuth.exe "user01:user01@192.168.xx.xx:3128" 8889
認証プロキシサーバ = 192.168.xx.xx:3128
ユーザ:パスワード  = user01:user01
ローカルポート     = 8889
コンソール表示有無 = 0
認証プロキシとの中継を開始しました。
```

バッチファイルからも起動はOKそうです。


## HttpProxyAuth をWindowsサービス化する

バッチファイルを作成し、そこから HttpProxyAuth を起動できるようになりましたが、このままだとHttpProxyAuthを常時起動しておこうとスタートアップに登録したとしても、Windowsアカウントでログインしたときだけ起動する**「ユーザモードでの起動」**となり、**Enterprise版 の「Windowsが起動していればログインしていなくてもUnattended ロボをリモート実行可能」って機構と相性が悪い**ですね。

なので**バッチファイルをWindowsサービス化するツール「[NSSM](http://nssm.cc/)」を使って**、WindowsサービスとしてHttpProxyAuthを起動できるようにします。[^3]

[^3]: ちなみにこのNSSMは、UiPath社が提供してくれている [Orchestrator導入ステップバイステップガイド](https://www.uipath.com/ja/resources/knowledge-base/orchestrator-installation-guide) にも登場するツールです(KibanaをWindowsサービス化するときに、使用する手順になってます)。




### ダウンロード

http://nssm.cc/download から「nssm 2.24」をダウンロードして解凍します。解凍すると ``nssm.exe`` の32ビット版と64ビット版が別々に入っているので、自分のWindowsにあったモノを選んで、先ほどバッチファイルをおいた場所にコピーしておきましょう。今回の例だとバッチファイルは ``t:\Tools\HttpProxyAuth`` に置きましたので、こんな感じになりました。


```console
T:\tools\HttpProxyAuth> dir
 T:\tools\HttpProxyAuth のディレクトリ

2013/04/25  16:44            32,768 HttpProxyAuth.exe
2014/09/01  00:34           331,264 nssm.exe
2016/03/08  10:14             3,835 ReadMe.txt
2020/01/12  14:07                57 run_proxy.bat

T:\tools\HttpProxyAuth>
```

### バッチファイルをWindowsサービス化する

以下のようにコマンドプロントを使って、バッチファイルをWindowsサービスとして登録します。

```console
T:\tools\HttpProxyAuth> nssm install "UiPath Robot HTTP Proxy" "T:\tools\HttpProxyAuth\run_proxy.bat"
Administrator access is needed to install a service.

確認画面がでるのでOKを押すと、、

T:\tools\HttpProxyAuth>
```

登録できたようですね。Windowsのサービス(Win+R で ``services.msc`` で起動できる)を開いて確認してみると、、
![S01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/288c67dc-3a4d-672d-83a3-5a9f37da5120.png)
登録されてますね！初回は自動起動していないようなので、開始しておきます。


![S02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/73777/316fe23f-00a7-d110-7883-c03d295d1da8.png)


セットアップは以上です。

再度 nupkgのダウンロードなどができることを確認しておきましょう。


Enterprise/Community版、どちらも認証ありプロキシを越えることができました。


## まとめ

TL;DR にも書きましたが、

- ``*.exe`` 系は、**認証情報を保持するプログラム(DLL)を作って、それぞれの exe の設定ファイル(``*.exe.config``) でそのプログラムを指定**する
- NuGet系は 参照しているいくつかの**``NuGet.Config``に、コマンドを使って認証情報を追記**する(Community版の場合)
- Enterprise版のばあいは``NuGet.Config``で HttpProxyAuth などの認証なしプロキシを指定し、**HttpProxyAuth に認証プロキシを越えてもらう**
- HttpProxyAuthをWindowsサービス化することで、Enterprise版のUnattendedの利点を損なうこともない

となりました。Enterprise版の場合はどのみちHttpProxyAuthが必要なので、``*.exe`` 系も全部、HttpProxyAuthにまかせるってのもアリかもしれません。

## 参考

整理のきっかけは前にもご紹介した https://github.com/RisaMizushina/UPProxyEnablementKit/releases このツールでした。

このツールは、今回手動で作成したDLLを自動でビルド・生成してくれたり、プロキシの情報を反映した設定ファイル群を出力してくれたりといろいろ便利な機能を持っています。認証プロキシ環境でUiPathを使う際、とても便利です。


以上、おつかれさまでしたー！


## 関連リンク

- [UiPath製品群をプロキシ環境で使用するための環境設定(UiPath Enterprise版/認証なしプロキシのケース)](https://qiita.com/masatomix/items/43e691e7d47e54638984)
- [UiPath製品群をプロキシ環境で使用するための環境設定(UiPath Community版/認証なしプロキシのケース)](https://qiita.com/masatomix/items/5be2a61a594307f5979a)
- [DockerとSquidを用いて、テスト用の認証プロキシサーバを構築する](https://qiita.com/masatomix/items/456c0c23eabb52cc4796)
- [HttpProxyAuth](https://www.vector.co.jp/soft/winnt/net/se499627.html) プロキシの中継サーバ
- [NSSM](http://nssm.cc/) プロセスをWindowsサービス化するツール
- [UPProxyEnablementKit](https://github.com/RisaMizushina/UPProxyEnablementKit/releases) 設定ファイルやDLLを自動生成してくれる