はじめに
複数のWEBサービスをシングルサインオン(SSO)でというのは
最近は普通になってきてますね。googleしかり。facebookしかり。
この認証というのが実はとっても複雑なんですね。
知らない人が取り組もうとするとまず用語がわけわからんくてやめます。
さらに認証といってもいろいろな方式があって、さらに流行り廃りもあり
1年前の情報ページが古くて使えないなんてザラ。
完全に初心者キラーな無理ゲー状態です。
今回は認証?なにそれ?なエンジニアでも
とっても苦労しながらなんとかSSO作れたぞ、という記録を公開したいと思います。
なお、2014年10月に試してますから!
上述したとおり、認証絡みはすっぐ情報古くなるんでそこんとこ踏まえて
読んでいただければと思います。
なお、認証関連のワードがどんどん出てきますがあまり説明しません。
なぜなら私もよくわかってないので。
やること
- Webアプリケーション(Java)の認証処理を認証サーバに任せる
- 自分で認証サーバを立てちゃう(OpenAMを使う)
- 自前のデータベースにあるユーザー情報テーブルを使って認証する
- 認証サーバとのやりとりは流行りのOpenID Connectでやる
- 各WEBの方に認証処理を組み込む方式で実施
- リバースプロキシで認証かけちゃう方法もあるけど今回はパス
- リバースプロキシ方法の場合、負荷がどうなるか心配で。
- 各WEBは認証sessionがない場合のみ認証サーバ問い合わせをして
認証sessionがあればそのまま通すようにすれば
認証サーバへのアクセス減らせるんじゃないかと。
試した環境
- サーバはさくらVPSを利用。今回はWEBサーバ、認証サーバ兼任
- 通常は認証サーバとアプリケーションサーバは別にしたほうがよい
- 負荷の関係とあとホスト名が同じはダメなので。
- 私はインスタンス1つしか持ってないので
DNSにSSO用のホスト名を追加しました。
- サーバは独自ドメインとDNSで名前解決しています。
openAMではホスト名が非常に重要なのでhostsとかでもいいので
事前に名前解決できるようにしておいてください。
- 通常は認証サーバとアプリケーションサーバは別にしたほうがよい
- 認証サーバはOpenAMを利用。
今回さくらVPSのtomcatにデプロイします- OpenAMはとにかくほとんどの方式で認証を実装できる認証の鬼みたいなやつ。
実態はtomcatにデプロイするただのサーブレットです。
OSSで認証とったらOpenAM使っとけば間違いなさそうです。 - なお、OpenAMをデプロイするtomcatはwebアプリをデプロイしてる
tomcatと別にしたほうがよいらしいので
今回 OpenAM用のtomcatを新しく立てます。
- OpenAMはとにかくほとんどの方式で認証を実装できる認証の鬼みたいなやつ。
- WEB側はseasar2系のJava Webアプリケーションです
- もちろん特にjavaでなければいけない理由はありません
- OpenAMに接続するモジュール部分は各言語で異なりますが
その辺は雰囲気を掴んでもらえればなんとかなるかも
- OpenAMに接続するモジュール部分は各言語で異なりますが
- もちろん特にjavaでなければいけない理由はありません
やってみた
SSO用のフォルダ
今回は/opt/openamとしました。
別にどこでもよいです。
以下、すべて/opt/openamがカレントとして記載します。
またサーバ上は全てrootで作業してます。
tomcatインストール
まずopenAM用のtomcatをインストールします。
サーバにrootで接続しーの以下発行
wget http://ftp.jaist.ac.jp/pub/apache/tomcat/tomcat-7/v7.0.56/bin/apache-tomcat-7.0.56.tar.gz tar zxvf apache-tomcat-7.0.56.tar.gz mv apache-tomcat-7.0.56 apache-tomcat rm -f apache-tomcat-7.0.56.tar.gz
次にopenAM用tomcatのportを変更します。
だってwebサーバが8080使っちゃってるからね。
インスタンスとか筐体がwebとopenamで別ならこの作業は不要です。
vi apache-tomcat/conf/server.xml
8080を検索して変更→8081に
次にopenAM起動用スクリプトを作ります。
この辺はいろいろなサイトの丸パクリ
openAMで気をつけるべきなのは
JAVA_OPTSのところとCATALINA_OPTSのとこらしいです。
vi /etc/init.d/openam
で以下をコピー!JAVA_HOMEとかは環境に合わせてください。
#!/bin/sh # # openam # # chkconfig: 35 84 16 # description: Manage OpenAM SSO Server CATALINA_HOME=/opt/openam/apache-tomcat export CATALINA_HOME JAVA_HOME=/usr/java/default/ export JAVA_HOME JAVA_OPTS="-server -Xmx1024m -XX:MaxPermSize=256m" export JAVA_OPTS CATALINA_OPTS="-Dcom.iplanet.am.cookie.c66Encode=true" export CATALINA_OPTS case "${1}" in start) "${CATALINA_HOME}/bin/startup.sh" exit ${?} ;; stop) "${CATALINA_HOME}/bin/shutdown.sh" exit ${?} ;; *) echo "Usage: $0 { start | stop }" exit 1 ;; esac
起動用スクリプトの権限追加と自動起動もセットしておきましょう
chmod +x /etc/rc.d/init.d/openam chkconfig --add openam chkconfig openam on
んでtomcatを起動しときます
service openam start
OpenAMインストール
次に本体のインストールです。といっても簡単でwarをデプロってやればOK
wget http://download.forgerock.org/downloads/openam/OpenAM-12.0.0-SNAPSHOT_20141025.war mv OpenAM-12.0.0-SNAPSHOT_20141025.war apache-tomcat/webapps/openam.war
これであとはtomcatが勝手に展開してます。
はじめてのOpenAM
さて準備ができました。ここまではサクッと来れるでしょう。多分。
ではブラウザで接続します。
ここで注意なのは
- ホスト名をIPアドレス指定はダメ
- ホスト名をlocalhost指定はダメ
- ホスト名はxxxx.xxxx.xxxxのように3区切り以上であること
- ホスト名:8081とか直port指定にすること
ajpとかでport80につないで内部でproxyしてはダメ
1.と2. はよく他のサイトにも書いてあります。
OpenAMの初期設定時にアクセスしてきたURLのホスト名を使うらしく
ちゃんとしたホスト名が必要になります。
3. は一度失敗しました。tryerror.net:8081 で接続してたらなんだかわかりませんが
初期設定がエラーになりました。今回sso.tryerror.net:8081で接続するよう
DNSにsso.tryerror.netを追加してます。
4. にもハマりました。初期設定中に「監視がなんとかかんとか」のところで
そのまま時間が停止します。どうもport80で入っていくとまずいみたいです。
(もしかしたら初期設定時にホスト名表示されるところのport変えればいけるかも)
今回はtutorialにもあるように8080とか8081とかで入るようにしました。
(iptablesで8081を開けました。この辺も環境に合わせてやってください)
先にいろいろ書きましたがでは初期設定しましょう。
ブラウザで以下のようにアクセスします。
http://ホスト名:8081/openam
私の場合はhttp://sso.tryerror.net:8081/openam になりました。
初期設定方法が2つ表示されています。
デフォルト設定とカスタム設定。
おもむろに右のカスタム設定を選びます。
左のデフォルト設定は選んではいけません。なんだか設定にバグがあって
認証cookieがうまくなくちゃんと動かないらしいです。
完全に初見殺しですね。たけしの挑戦状レベルのクソゲーです。
どんどん設定していきます。
- ライセンスに同意してcontinue
- adminユーザのパスワードを設定
- サーバー設定
- サーバーURL:http://sso.tryerror.net:8081(そのまま)
- -> 上述したとおりここがport80とかだとダメよん
- Cookieドメイン:.tryerror.net(そのまま)
- ホスト名がxxx.xxx.xxxのように3区切りでないと表示されない
- プラットフォームロケール:en_US(そのまま)
- 設定ディレクトリ:/root/openam(そのまま)
- 設定ストア
- 全部そのまま
- サーバーURL:http://sso.tryerror.net:8081(そのまま)
- ユーザデータストア
- OpenAM のユーザーデータストアを選択
- サイト設定
- このインスタンスは、サイト設定の一部としてロードバランサの背後に配備されますか ?
- いいえを選択
- デフォルトのポリシーエージェントユーザー
- パスワードを入力(adminユーザのパスワードとは別のものを求められます)
- このインスタンスは、サイト設定の一部としてロードバランサの背後に配備されますか ?
- 設定の作成をclick
なお、いくつかportが出てきますが8081以外はfirewall開けなくても大丈夫でした。
設定の作成を押すといろいろ自動設定されます。
そつなくこなせて「いれば」ログイン画面に移動します。
残念ながらエラー出ちゃった人は
(私はなんども失敗したり途中で止まったり。20回くらいやったはず)
以下のコマンド発行後、やり直しできます。
service openam stop rm -fR /root/openam rm -fR /opt/openam/apache-tomcat/webapps/openam service openam start
全然関係ないけどなんどもやり直している間に
やり直しコマンドの貼り付けミスして/root配下を全部消して泣きました
OpenAMにOAuth2.0 provider設定をする
ここまできたらあと少しです。
OpenAMのログイン画面から管理者ログインします。
管理者IDはamadminです。
初期設定時にコッソリ書いてあったので覚えてますよね!?
大事なことでも2回は言わないopenAMくんです。
まずおもむろにOAuth2の設定を選びます
- リフレッシュトークンの有効期間(秒):60 →86400に伸ばす
- アクセストークンの有効期間(秒):60 →86400に伸ばす
- 右上の作成を押す
レルムとかなんとかよく分からない単語が書いてますが
意味不明なので無視していきます
次にOAuthでいうところのRPというものを作っていきます。
まぁ認証のアクセスポイントみたいなものです。
- アクセス制御を選択
- 最上位のレルムを選択
- エージェントを選択
- OAuth2.0クライアントを選択
- 上段のエージェントの段の新規を選択
まぁいろいろと気になる部分はあるでしょうが
どんどんいきましょう
設定画面には以下のように入力しましょう
- 名前:任意の名前(アルファベット推奨)
- ここで指定した名前がClient IDというものになります。
webアプリから認証する際にOpenAMに渡すパラメタの1つになります
- ここで指定した名前がClient IDというものになります。
- パスワード:任意のパスワード
- とっても大事なパスワード。ランダムな32桁くらいを用意しましょう。
- このパスワードがClient Seacretというものになります。
サーバアプリからOpenAMに認証かける場合などは
OAuthのコードフローという方式でやったりするのですが
その際、アプリからOpenAMにこのClient Seacretを渡す必要が出てきます。
できたら作成を押します。
そうするとエージェントの一覧のところに作ったものが出てくるので選ぶと設定画面が出ます。
こんな感じで設定します
- リダイレクトURI: OpenAMで認証OKになった後、呼び出されるwebアプリのURL
- 例えばhttps://tryerror.net/someservice/oAuth2CallBack
のような感じです。ちなみにローカル環境でデバッグしている場合でも
リダイレクトURLにhttp://localhost:8080/someservice/oAuth2CallBack
のように登録しておくとローカルにリダイレクトしてくれます
- 例えばhttps://tryerror.net/someservice/oAuth2CallBack
- スコープ:openid email profile …のように設定します
- OAuthでは認証+ユーザ情報どこまで取得できるかをスコープという名前で
定義しておきます。認証するにはopenidが必須です。
email を指定するとユーザ情報としてemailを取得できるようになります。
profile を指定すると名前を取得できるようになります。
その他、ユーザテーブルにある項目名をscopeに入れておけば公開できます。
(社員番号や部署とかといった独自項目でもOK)
- OAuthでは認証+ユーザ情報どこまで取得できるかをスコープという名前で
- 表示する名称:ログイン後、スコープ許可画面でユーザに表示される名前です。
- システム名とかを設定しておくとよいでしょう
- 表示する説明:ログイン後、スコープ許可画面でユーザに表示される説明です。
- 全く怪しいサイトではありません。さぁまずはOKボタンを押しましょう。
と書いておけばユーザは安心してOKボタンを押してくれることでしょう。
- 全く怪しいサイトではありません。さぁまずはOKボタンを押しましょう。
- ID トークン署名応答アルゴリズム:何も考えずにHS256と設定しておきます
あとの項目は何もしなくてとりあえずよいです。
これでOAuth2.0サーバができてます。
ユーザ情報を設定する
ユーザ情報はOpenAM上ではデータストアという呼び名になります。
デフォルトではopenDJというOpenAMに一緒に入ってくるLDAPサーバに
登録されています(amadminもここに登録されます)
すでにLDAPサーバがある人はそれを指定すればよいのでしょうが
LDAPなんてねーよ、とかLDAPって何?っていう人は
自前のデータベースにあるユーザ情報をデータストアとして使いたいことでしょう。
ということでデータストアの登録を行います。
今回はpostgresにuserinfoというテーブルを作っておいて接続すると仮定します。
まずopenAMからpostgresを利用できるようにjarを配置します。
今回の例では/opt/openam/apache-tomcat/webapps/openam/WEB-INF/lib/に配置です。
jarを配置したらtomcatを再起動しておきます。
次にpostgresにテーブルを作成します。
今回はopenAM標準に合わせたtableを作成します。table名は任意ですがauth_usersにしました。
create table auth_users( uid varchar(50), cn varchar(50), inetuserstatus varchar(20), userpassword varchar(50), ChangePassword varchar(50), mail varchar(50), sunIdentityMSISDNNumber varchar(50), sn varchar(50), manager varchar(50), preferredlocale varchar(10), iplanet_am_user_password_reset_force_reset varchar(50), givenname varchar(50), iplanet_am_user_alias_list varchar(50), iplanet_am_user_account_life varchar(50), telephonenumber varchar(50), employeenumber varchar(50), iplanet_am_user_auth_config varchar(50), postaladdress varchar(50), iplanet_am_user_password_resetoptions varchar(50), iplanet_am_user_password_reset_question_answer varchar(50), iplanet_am_user_success_url varchar(50), iplanet_am_user_failure_url varchar(50) );
openAMにamadminでログインし
アクセス制御- 最上位のレルム – データストア – 新規を選択します
- 名前:postgresのuserinfo とでもしておきましょう
- タイプ:データベースリポジトリ(アーリーアクセス) アーリーアクセスって何?
を設定します。
次にJDBCの設定を行います。
- JDBCドライバURL:jdbc:postgresql://ホスト名:5432/DB名 のように指定
- JDBCドライバクラス:org.postgresql.Driver
- データベースに接続するユーザ:ユーザ名
- データベースに接続するためのパスワード:パスワード
- データベースのユーザーテーブル名:テーブル名を指定(今回はauth_users)
これでうまくいっていれば対象から新規ユーザ登録をすると
postgresのテーブルに書き込まれることが確認できます。
エラーになる場合、/opt/openam/apache-tomcat/logs/catalina.outにログが出てます
次に追加したデータストアを認証に使ってもらうように設定します。
アクセス制御- 最上位のレルム – 認証 – 認証連鎖のところの新規を選択します
- 名前:任意の名前をセットしましょう postgresAuthとか
つぎに認証連鎖の詳細の設定です
- 追加を選択、Datastoreを選択、必要を選択します
そして認証連鎖のところのembeddを削除します
アクセス制御- 最上位のレルム – 認証に戻り
- 組織認証設定
- 管理者認証設定
がpostgresAuthになっていることを確認します。
これで認証サーバ側の設定は完了です。
長い…
次回はwebアプリケーション側(java)の実装をしていきます。