Secure Gatewayを利用してLiberty for JavaのアプリケーションにLDAP認証を追加する


# はじめに
Bluemixには、オンプレや他クラウドの環境と接続するためのサービスとして、以下の4つが提供されています。

  * Cloud Integration
  * Connect & Compose
  * Secure Gateway
  * Rocket Mainframe Data

今回は、Bluemixと他環境との間でセキュアなトンネリングを確立し、様々な種類の通信を流せるSecure Gatewayを利用します。
以下の図のように、Liberty for Javaのユーザー認証として、Secure Gateway経由でBluemix外のLDAPサーバーから認証情報を取得するアプリケーションを作成してみます。

![SecureGateway-01.png](https://qiita-image-store.s3.amazonaws.com/0/73397/c3f451cf-5cb6-4fe8-63e5-a407ad4efc02.png "SecureGateway-01.png")


## 検証環境

LDAPを稼働させる環境として、Parallels上に以下の2つのサーバーを作成しました。

 * Secure Gateway Clientを稼働させるためのCentOS 7サーバー
  * CentOS 7.1
  * Docker 1.8.2
 * LDAPを稼働させるためのCentOS 6サーバー
  * CentOS 6.7
  * IBM Security Directory Server 6.4

LDAPには、以下の3つのユーザーを作成しています。

 * Liberty for JavaからLDAPに対して認証情報を取得するための場Bindユーザー
  * uid=binduser,ou=management,o=example.dc=com
 * アプリケーション用ユーザー
  * uid=test01,ou=user,o=example,dc=com
  * uid=test02,ou=user,o=example,dc=com


# Secure Gateway
## 概要
Secure Gatewayは、Bluemixと他環境との間をセキュアなトンネリングにより接続するサービスです。
Secure Gatewayを設定すると、クラウド・ホストとポートが割り当てられますので、その情報を利用して、Bluemixアプリケーションは他環境に接続します。

Secure Gatewayで使用される用語をまとめました。

 * Secure Gatewayサービス
  * Bluemixと他環境との接続を構成するためのサービスのことです。
 * Secure Gateway Client
  * 他環境に導入され、クラウド・ホストとの間でセキュアなトンネルを確立します。クラウド・ホストからの通信を宛先に割り振ります。
  * Dockerクライアント、Linux/Mac用クライアント、DataPowerの3種類から環境に応じたクライアントを選択します。
 * クラウド・ホスト/ポート
  * Bluemix側にあるSecure Gatewayのエンドポイントです。Secure Gateway Clientとの間でセキュアなトンネルを確立します。
  * 宛先ごとにクラウド・ホストとポートが割り当てられます。
 * 宛先
  * データベースやLDAP、MQなど、接続先環境にあるミドルウェアやアプリケーションとなります。Bluemixアプリケーションが接続したい相手のことです。

![SecureGateway-02.png](https://qiita-image-store.s3.amazonaws.com/0/73397/1e620266-f29e-67f7-8f95-327544234f23.png "SecureGateway-02.png")

## 設定手順
カタログから、「統合（Integration）」カテゴリーにある「Secure Gateway」を作成します。
なお、Secure Gatewayは、1つのスペースにつき1つのサービスしか作成できません。すでにサービスを作成している場合は、そのサービスを利用してください。

作成されたSecure Gatewayのサービスを選択すると、設定用の画面が表示されます。
初めての設定のため、「ゲートウェイの追加」をクリックし、ゲートウェイを作成します。
![SecureGateway-03.png](https://qiita-image-store.s3.amazonaws.com/0/73397/0f69f5ce-70d0-3fbd-5b6d-d2a9ad21da77.png "SecureGateway-03.png")

ゲートウェイの名前は任意です。ここでは「Sample」と入力し、「接続」をクリックします。
![SecureGateway-04.png](https://qiita-image-store.s3.amazonaws.com/0/73397/1da04f53-4e33-db6e-2952-04167d53de77.png "SecureGateway-04.png")

続いて、Secure Gateway Clientの導入画面が表示されます。
今回はDockerクライアントを利用しますので、表示されているDockerコマンドをコピーし、Dockerが稼働しているサーバーで実行します。
![SecureGateway-05.png](https://qiita-image-store.s3.amazonaws.com/0/73397/1e24cb35-8dd3-6075-0ac2-73037fa3cb6f.png "SecureGateway-05.png")

以下のとおり、「The Secure Gateway tunnel is connected」と表示されれば、正常に起動できています。

```
IBM Bluemix Secure Gateway Client Version 1.3.0
************************************************************************************************
You  are running the  IBM Secure  Gateway Client for Bluemix. When you enter the provided docker
command the IBM Secure Gateway Client  for Bluemix automatically downloads as a Docker image and
is executed on your system/device. This is released under an IBM license. The  license agreement
for IBM  Secure Gateway Client for Bluemix is available at the following location:

http://www.ibm.com/software/sla/sladb.nsf/lilookup/986C7686F22D4D3585257E13004EA6CB?OpenDocument

Your use of the components of the package and  dependencies constitutes your acceptance  of this
license agreement. If you do  not want to accept the license, immediately quit  the container by
closing the  terminal  window or by  entering 'quit' followed by the ENTER key. Then, delete any
pulled Docker image from your device.  
************************************************************************************************


<press enter for the command line>
[2015-12-06 10:35:54.515] [INFO] Setting log level to INFO
[2015-12-06 10:36:06.281] [INFO] The Secure Gateway tunnel is connected
```

Dockerの起動が完了したら、「宛先の追加」をクリックし、接続先となるLDAPの情報を入力します。
任意の名前（ここではLDAP）とIPアドレス、ポート番号を入力し、プラスマークをクリックします。
IPアドレスとポート番号は、Secure Gateway ClientからLDAPサーバーにアクセスするためのアドレスとポート番号を入力します。
![SecureGateway-06.png](https://qiita-image-store.s3.amazonaws.com/0/73397/e68625f2-55c6-3f8b-b99f-024795278a9f.png "SecureGateway-06.png")

宛先が登録されました。インフォメーションマークをクリックすることで、クラウド・ホストとクラウド・ポートの情報を確認できます。
![SecureGateway-07.png](https://qiita-image-store.s3.amazonaws.com/0/73397/3fdf83e0-0797-8f79-8b24-3799a6697f68.png "SecureGateway-07.png")

![SecureGateway-08.png](https://qiita-image-store.s3.amazonaws.com/0/73397/9d641c7d-f316-2ae8-b047-32430e23d3d2.png "SecureGateway-08.png")

### Secure Gateway ClientのACL
Secure Gateway ClientにはACLを設定する機能があり、Secure Gateway Clientから通信可能な宛先のサーバーを制限できます。
デフォルトでは、Deny ALLとなっており、すべての接続が拒否される設定となっているため、このままではLDAPサーバーと通信することができません。

Secure Gateway Clientを起動するためのDockerコマンドを実行した後に、Enterキーを押すとコマンドを入力できるようになります。
「show acl」を実行してみましょう。「ACL Deny All flag is set to true」と表示され、Deny Allが有効になっていることがわかります。

```
cli> show acl
[2015-12-06 10:59:35.914] [INFO] There are no Access Control List entries, the ACL Deny All flag is set to: true
```

LDAPサーバーとの通信を許可するようにします。

```
cli> acl allow 10.37.129.130:389
cli> show acl
--------------------------------------------------------------------------------
                 -- Secure Gateway Client Access Control List --                
                                                                                
 hostname                                       port                      value 
 10.37.129.130                                   389                      Allow 
--------------------------------------------------------------------------------
```

# サンプル・アプリケーション
## アプリケーションの内容
アプリケーションアクセス時にベーシック認証を要求し、その認証で使用されたユーザー名を表示するという単純なアプリケーションを利用します。

``` SampleService.java
package com.example;

import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Context;

@Path("/user")
public class SampeService {
	@Context
	 public HttpServletRequest request;
	
	@GET
	public String getUserName() {
		return request.getRemoteUser();
	}
}
```

## web.xml
ユーザー認証を要求するようにweb.xmlを以下のとおり記述します。

``` web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="BasicAuthSample" version="3.1"
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
   
   <display-name>BasicAuthSample</display-name>
   <servlet>
      <servlet-name>javax.ws.rs.core.Application</servlet-name>
   </servlet>
   <servlet-mapping>
      <servlet-name>javax.ws.rs.core.Application</servlet-name>
      <url-pattern>/*</url-pattern>
   </servlet-mapping>
   
   <security-constraint>
      <web-resource-collection>
         <web-resource-name>index</web-resource-name>
         <url-pattern>/*</url-pattern>
      </web-resource-collection>
      <auth-constraint>
         <role-name>all</role-name>
      </auth-constraint>
      <user-data-constraint>
         <transport-guarantee>CONFIDENTIAL</transport-guarantee>
      </user-data-constraint>
   </security-constraint>
   <security-role>
      <role-name>all</role-name>
   </security-role>
</web-app>
```

## Bluemixへのデプロイ方法
Liberty for JavaがLDAPを利用するためには、Libertyの設定ファイルである「server.xml」を編集する必要があります。
通常、Libertyを利用する場合は、warファイルをデプロイし、Bluemixが自動で構成するserver.xmlを利用することが多いかと思います。今回は、server.xmlを独自に編集するため、warファイルに加え、server.xmlもBluemixにデプロイする必要があります。Bluemixのマニュアルで[「サーバー・ディレクトリーをプッシュする」](https://www.ng.bluemix.net/docs/starters/liberty/index.html#optionsforpushinglibertyapplications)と記載された方法を利用します。

### ディレクトリの作成とファイルの配置
サーバー・ディレクトリーをプッシュする方法では、作業用ディレクトリの下に、以下の階層のディレクトリを作成し、ファイルを配置します。
準備するものはserver.xmlとアプリケーションのwarファイルの2種類のみです。

```
defaultServer/
  │
  ├─ server.xml
  │
  └─ apps/
       │
       └─ BasicAuthSample.war
```

### server.xmlの内容

使用したserver.xmlは以下のとおりです。
LDAP認証は、「ldapRegistry-3.0」と呼ばれるフィーチャーを有効にし、「ldapRegistry」タグに設定を記述します。
今回はIBM Security Directory Serverを利用しているため、ldapTypeとして「IBM Tivoli Directory Server」を選択していますが、Microsoft Active Directoryなどの他のディレクトリ・サーバーもldapTypeとして指定可能です。
**Secure Gatewayの設定で確認したクラウド・ホストの情報を「host」に、クラウド・ポートの情報を「port」に記載してください。**


``` server.xml
<server description="new server">
  <featureManager>
    <feature>webProfile-7.0</feature>
    <feature>ldapRegistry-3.0</feature>
  </featureManager>
  
  <ldapRegistry baseDN="ou=user,o=example,dc=com"
                bindDN="uid=binduser,ou=management,o=example,dc=com" bindPassword="{xor}JT4ubm0oLCc="
                host="xxxx" port="xxxx" ldapType="IBM Tivoli Directory Server">
    <idsFilters userFilter="(&amp;(uid=%v)(objectclass=eAccount))"/>
  </ldapRegistry>
  
  <httpEndpoint host="*" httpPort="9080" httpsPort="9443" id="defaultHttpEndpoint"/>
  
  <webApplication id="BasicAuthSample" location="BasicAuthSample.war" name="BasicAuthSample" contextRoot="/">
    <application-bnd>
      <security-role name="all">
        <special-subject type="ALL_AUTHENTICATED_USERS"></special-subject>
      </security-role>
    </application-bnd>
  </webApplication>
</server>
```

### Bluemixへのプッシュ

defaultServerディレクトリがあるディレクトリ（/work/Bluemix/defaultServerというディレクトリ構造であれば、/work/Bluemix）に移動し、以下のコマンドを実行します。
（\<Your_Application_Name>と\<Your_Application_Host_Name>の値は、みなさんの環境でのアプリケーション名とホスト名に合わせて修正してください。）

```
cf push <Your_Application_Name> -n <Your_Application_Host_Name> -m 512m -p defaultServer
```

# 動作確認
https://\<Your_Application_Host_Name>.mybluemix.net/user にアクセスします。
ベーシック認証のポップアップが表示されますので、LDAPに登録しているユーザー名とパスワードを入力します。
![SecureGateway-10.png](https://qiita-image-store.s3.amazonaws.com/0/73397/cbee3b9f-99c9-5c71-b322-4a8c96426182.png "SecureGateway-10.png")

認証に成功し、ユーザー名が表示されました。
![SecureGateway-09.png](https://qiita-image-store.s3.amazonaws.com/0/73397/dc35ce70-5d37-1a4b-7b42-432987e25e1f.png "SecureGateway-09.png")

# 最後に
Secure Gatewayを利用し、LDAP認証があるアプリケーションを作成しました。
WebSphere Libertyの設定に関する知識が少し必要となりますが、Secure Gatewayを構成し、web.xmlとserver.xmlの設定だけで認証を有効にするできます。
認証が必要なアプリケーションを構成する場合は、Single Sign Onサービスの利用だけでなく、Secure Gatewayを利用したLDAP認証も選択肢の1つとなるのではないでしょうか。
今回は、LDAPサーバーをParallels上に構築していますが、BluemixのOpenStack VMを利用すれば、クラウド上で環境が完結します。

Secure Gatewayには、通信をよりセキュアにするための設定がいくつかあります。
今回の構成では、クラウド・ホストとクラウド・ポートを知ってしまえば、Bluemix外のアプリケーションからも接続できてしまいます。
[マニュアル](https://www.ng.bluemix.net/docs/services/SecureGateway/sg_023.html#sg_033)を読むと、アクセス元も制限できるようにみえますので、次回はこの機能を試してみたいと思います。