【UiPath】OrchestratorのAPIを使ってみる③～Javaから認証APIを叩いてみる～

# はじめに

前回まででOrchestrator APIの叩き方はわかったので、Javaから実行してみます。

## 余談

UiPath Orchestratorで月間スケジュールのようなものを出力したかったのですが、そういう機能がないんですよね。
（トリガーの画面で確認はできるが、レポート的に出力する機能がない）

かゆいところに手が届かないので、それを補完するためにJavaからAPI叩いて整形してレポート出力してみよう！というのが発端でした。

# 認証APIを叩いてみる

今回は認証APIを叩いて、Bearerトークンを取得するところまでを説明します。
JSONデータを作って、HttpClientでPOSTして、Bearerトークンを取得する、という流れになります。

## まずは投げるところまで

```java:App.java
package jp.co.pmtech.iwata;

import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;

public final class App {
    private App() {
    }

    public static void main(String[] args) {

        try {
            // 認証APIに投げるJSONを作る
            String tenant = "テナント名";
            String username = "ユーザー名";
            String password = "パスワード";
            String sendJson = "{" +
                    "\"tenancyName\" : \"" + tenant + "\"," +
                    "\"usernameOrEmailAddress\" : \"" + username + "\"," +
                    "\"password\" : \"" + password + "\"," +
            "}";
    
            // POSTデータを作る
            HttpPost request = new HttpPost("https://Orchestratorのホスト名/api/account/authenticate");
            StringEntity entity = new StringEntity(sendJson, ContentType.APPLICATION_JSON);
            request.setEntity(entity);
            request.setHeader("content-type", "application/json");
    
            // 実行する
            HttpClient client = HttpClients.createDefault();
            HttpResponse response = client.execute(request);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

ユーザー名とかホスト名とかは、環境に合わせて変えてくださいね。

## エラーになった！

では、上記のコードを実行してみます。

```
javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
        at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
        at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1964)
・・・以下省略
```

なんかエラーになりますね。

## 自己署名（オレオレ証明書）対応させる

このエラーは、HTTPS通信を行おうとしたときに、相手先サーバー（＝Orchestrator）の認証局証明書が登録されていない場合に発生します。
つまり、いわゆるオレオレ証明書の場合に発生します。

HttpClient生成の箇所を、以下のように変更します。

```java
    HttpClient client = HttpClients.custom().setSSLSocketFactory(
        new SSLConnectionSocketFactory(SSLContexts.custom()
            .loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()
        )).build();
```

この状態で実行すると、エラーがでなくなりました。

## 実行結果のBearerトークンを取得する

以下のコードを追加します。

``` java
    // 実行結果の取得
    HttpEntity httpEntity = response.getEntity();
    String resultJson = IOUtils.toString(httpEntity.getContent(), "UTF-8");
            
    // HTTPステータスが200 OKであること
    if (response.getStatusLine().getStatusCode() != 200) {
        throw new Exception("認証に失敗しました。" + response.getStatusLine().getReasonPhrase() + ":" + resultJson);
    }
            
    // 認証テキストを取得
    ObjectMapper mapper = new ObjectMapper();
    JsonNode node = mapper.readTree(resultJson);
    String bearer = node.get("result").asText();
    System.out.println(bearer);
```

まず、認証APIが成功した場合は必ずHTTPステータス200が返ってきます。
それ以外のステータスはエラーとみなし、例外としています。

また、認証結果はJSONで返ってくるため、ここではJacksonを使って中身を取り出しています。

## ここまでの完成系がこちら

認証APIを実行して、Bearerトークンを取得するまでです。

```java:App.java
package jp.cp.pmtech.iwata;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;

public final class App {
    private App() {
    }

    public static void main(String[] args) {

        try {
            // 認証APIに投げるJSONを作る
            String tenant = "Default";
            String username = "admin";
            String password = "1qaz2wsx";
            String sendJson = "{" +
                    "\"tenancyName\" : \"" + tenant + "\"," +
                    "\"usernameOrEmailAddress\" : \"" + username + "\"," +
                    "\"password\" : \"" + password + "\"," +
            "}";
    
            // POSTデータを作る
            HttpPost request = new HttpPost("https://laptop-dubq7uhj/api/account/authenticate");
            StringEntity entity = new StringEntity(sendJson, ContentType.APPLICATION_JSON);
            request.setEntity(entity);
            request.setHeader("content-type", "application/json");
    
            // 実行する
            HttpClient client = HttpClients.custom().setSSLSocketFactory(
                new SSLConnectionSocketFactory(SSLContexts.custom()
                    .loadTrustMaterial(null, new TrustSelfSignedStrategy()).build()
                )).build();

            HttpResponse response = client.execute(request);

            // 実行結果の取得
            HttpEntity httpEntity = response.getEntity();
            String resultJson = IOUtils.toString(httpEntity.getContent(), "UTF-8");
            
            // HTTPステータスが200 OKであること
            if (response.getStatusLine().getStatusCode() != 200) {
                throw new Exception("認証に失敗しました。" + response.getStatusLine().getReasonPhrase() + ":" + resultJson);
            }
            
            // 認証テキストを取得
            ObjectMapper mapper = new ObjectMapper();
            JsonNode node = mapper.readTree(resultJson);
            String bearer = node.get("result").asText();
            System.out.println(bearer);
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
}
```

# 次回

トリガーの登録内容を一覧化してみます。