oneloginのSAML認証機能を使ってSAML認証対応サービスへのログイン

OneloginのSAML認証を利用しサービスへのログインを行う手順です。

以下では AWS へSAML認証でログインさせるまでの手順です。

はじめに、Administrator権限を持った Onelogin アカウント、IAM権限を持った AWS アカウントを準備していることを前提としています。

また、Administrator以外にユーザでログインする場合は個別にユーザを作成しておいてください。

## Onelogin / AWS の設定

SAML認証を使ったログインでは、個別のユーザに対してログインするわけではなく、Oneloginのユーザに対して付与されたAWSのRoleを持ってログインします。
設定はおおよそ以下のような流れです。

- OneloginでAWSのコネクタ作成
- AWSでIDプロバイダの設定
- AWSでIAM Roleの作成
- Oneloginで作成した、AWSコネクタに Parameters を設定

設定は **[OneLoginを利用してAWSにSAMLでログインする](http://blog.serverworks.co.jp/tech/2018/06/22/onelogin-aws-saml/)** が参考になります。

## ログイン

設定がすんだら、さっそくOneloginのSAML認証を使いAWSへログインしてみます。

#### Oneloginポータル画面からAWSへログイン

Oneloginへ**[ログイン](https://app.onelogin.com/login)**し、表示されるポータル画面からAWSへログインする方法です。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/297616/cbe4e7f0-7aa0-5cad-8432-30e90c9c6458.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/297616/f940ae0a-417d-70aa-db02-9067bfaef4ad.png)

権限を持ったユーザであれば、ポータル画面にはAdministratorが設定したAPP一覧が表示されています。

![Oneloginポータル画面](https://qiita-image-store.s3.amazonaws.com/0/297616/0736ce16-d855-cdb0-9e55-310160eb9e5a.png)

この画面からAWSのアイコンをクリックすることでAWSへログインすることができます。

#### Oneloginのポータル画面を手動でログイン作業を行わずに開く

例えば以下のような要件の場合

- 社内でアカウント管理を行っている。
- 複数のSAML認証に対応したサービスと連携している。
- Oneloginを利用し、SSOをサービスで利用したい。
- 但し、社内でアカウント管理をしているので、Oneloginへのログインは冗長となるので、Oneloginへのログインは省略したい。

この場合社内で以下のような手順で行えば可能です。

- アクセストークンの発行
- セッショントークンの発行
- 発行したセッショントークンでログイン

はじめに、アクセストークンを発行する前に、Administraotr でログインし、OneloginでAPIのCredentialsを発行します。

- `DEVELOPERS` > `API Credentials` > `NEW CREDENTIAL`
- 名前と権限を設定

<img src="https://qiita-image-store.s3.amazonaws.com/0/297616/d7b6e815-4b8e-ba97-b1ef-dc03841e599e.png" width=50%>

アクセストークンの発行には、この時発行された `Client Secret` と `Client ID` を利用します。

**アクセストークンの発行**

```sh
CLIENT_ID=<Client ID>
CLIENT_SECRET=<Client Secret>

ACCESS_TOKEN=$(curl -s 'https://api.us.onelogin.com/auth/oauth2/token' \
  -X POST \
  -H "Authorization: client_id:${CLIENT_ID}, client_secret:${CLIENT_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{ "grant_type":"client_credentials" }' | jq -r '.data[].access_token')
echo ${ACCESS_TOKEN}
  #
```

**セッショントークンの発行**

```sh
LOGIN_USER=<Onlogin User>
LOGIN_PASSWORD=<Onlogin Password>
export LOGIN_SUBDOMAIN=<Onlogin SubDomain>

export SESSION_TOKEN=$(curl -s 'https://api.us.onelogin.com/api/1/login/auth' \
  -X POST \
  -H "Authorization: bearer: ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{ \"username_or_email\":\"${LOGIN_USER}\", \"password\":\"${LOGIN_PASSWORD}\", \"subdomain\":\"${LOGIN_SUBDOMAIN}\" }" | jq -r '.data[].session_token')
echo ${SESSION_TOKEN}
  #
```

**セッショントークンをPOSTしてブラウザ経由で開く**

```sh
cat << 'EOT' | envsubst > onelogin-demo.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <p>Auth API Test</p>
        <form action=
         "https://${LOGIN_SUBDOMAIN}.onelogin.com/session_via_api_token" method="POST">
            <input type="hidden" name="session_token" value="${SESSION_TOKEN}">
            <input type="submit" placeholder="GO">
            <input id="auth_token" type="hidden">
        </form>
    </body>
</html>
EOT
```

これで生成されたhtmlファイルをブラウザで表示し、`送信` をクリックすることでOneloginのポータル画面を開けます。

#### ユーザがAWSへ直接ログイン

Oneloginを使っていることをユーザに意識させずにシームレスにSAML認証に対応したサービス（AWS）にログインした場合

- アクセストークンの発行
- SAMLアサーションを取得
- 取得したSAMLアサーションログイン

**アクセストークンの発行**

アクセストークンの取得は、「Oneloginのポータル画面を手動でログイン作業を行わずに開く」に同じです。

```sh
CLIENT_ID=<Client ID>
CLIENT_SECRET=<Client Secret>

ACCESS_TOKEN=$(curl -s 'https://api.us.onelogin.com/auth/oauth2/token' \
  -X POST \
  -H "Authorization: client_id:${CLIENT_ID}, client_secret:${CLIENT_SECRET}" \
  -H "Content-Type: application/json" \
  -d '{ "grant_type":"client_credentials" }' | jq -r '.data[].access_token')
echo ${ACCESS_TOKEN}
  #
```

**SAMLアサーションを取得**

セッショントークンの取得時と同様に、Oneloginのユーザ、パスワード、サブドメインのほか、SAML認証でログインするサービスのAPP IDを使います。

APP IDは、Administraotrでログインし、`APPS` > `Company Apps` で対象のアプリを開いた場合のURLから確認できます。（`https://${subdomain}.onelogin.com/apps/${APP_ID}/edit`）

```sh
LOGIN_USER=<Onlogin User>
LOGIN_PASSWORD=<Onlogin Password>
LOGIN_SUBDOMAIN=<Onlogin SubDomain>
APP_ID=<App ID>

export SAML_RESPONSE=$(curl -s "https://api.us.onelogin.com/api/1/saml_assertion" \
  -X POST \
  -H "Authorization: bearer: ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "{ \"username_or_email\":\"${LOGIN_USER}\", \"password\":\"${LOGIN_PASSWORD}\", \"app_id\":\"${APP_ID}\", \"subdomain\":\"${LOGIN_SUBDOMAIN}\" }" | jq -r '.data')
echo ${SAML_RESPONSE}
  #
```

**SAMLアサーションをPOSTしてブラウザ経由で開く**

```sh
cat << 'EOT' | envsubst > onelogin-demo.html
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
    </head>
    <body>
        <p>Auth API Test</p>
        <form action="https://signin.aws.amazon.com/saml" method="POST">
            <input type="hidden" name="SAMLResponse" value="${SAML_RESPONSE}">
            <input type="submit" placeholder="GO">
            <input id="auth_token" type="hidden">
        </form>
    </body>
</html>
EOT
```

※*POST先の `https://signin.aws.amazon.com/saml` はAWSでOneloginユーザへ割り当てるために作成したRoleの信頼関係の条件で確認できます。*

この方法でAWSへSAML認証を利用したログインをした場合、Oneloginのポータルを経由していないので、仮に他のユーザでログインしていた場合に、そのユーザのセッションを奪うことはありません。
またユーザはOneloginをまったく意識することがなくSAML認証にログインすることが可能です。

---

いくつかの用途にあったSAML認証を使ったログインの手順を試してみましたが、ご自身の要件によって使い分けみてください。

また、Oneloginでは**[デモアプリ](https://github.com/onelogin/python-saml)**も提供しています。

そちらを抜粋し、上記の手順をデモアプリ対しての検証も行ってみましたので、気になった方はご覧ください。**[GitHub](https://github.com/ot-nemoto/OneloginSamlDemo)**