随感録 2017年8月

2017-08-11 (Fri)

シングルサインオン (SSO) のために, OpenID Connect について調べた。

OpenID Connect は, OAuth 2.0仕様の上に構築された認証 (authentication) 手順。認可 (authorization) とは異なる。

ただの OAuth 2.0 を「認証」に使おうとすると、セキュリティ上よくない。例えば, 単なる OAuth 2.0 を認証に使うと、車が通れるほどのどでかいセキュリティー・ホールができる | @_Nat Zone

各社が OAuth 2.0 の上に独自に認証の仕組みを作っていたのを標準化したものが OpenID Connect. 'OpenID 2.0' (OpenID Authentication 2.0) からの技術的な連続性はない。名前だけ。紛らわしい。

OpenID Connect に対応した認証サービス (OpenID Provider; OP) は、例えば、次がある;

組織 サービス
Google Google Federated Identity
Microsoft ADFS on Windows Server 2016
Microsoft Azure Active Directory
PayPal Login with PayPal ※下コメント参照.
Salesforce Summer 2015 Release
Yahoo! Japan Yahoo! ID Federation v2

リストはこちら; OpenID Certification. Facebook がないのがつらい。引き続き独自の方法で対応が必要。

(2017.9.23) このほか, gitlab.com も OpenID Provider のつもりだが、jwks_uri で得られるRSA公開鍵が不味く, 適合していない。

omniauth-openid-connect

Ruby on Rails での Googleへの対応では, omniauth-google-oauth2 を使っていたところ。今回, これを omniauth-openid-connect gem を使い、Google Identity Platform に OpenID Connect でログインできるようになった。まだ、プロフィールの更新は実現できていない。

'omniauth-openid-connect' gemパッケージは, 正直, あまり完成度が高くない。開発も2015年12月のが最新バージョンで, 最近の openid_connect パッケージに付いて行ってない。forkされまくりで, はて, 誰のforkがまともなのか? かなり困る。

(2017.9.23) 各所に散らばったパッチや修正を取り込んで、統合したバージョンを作りました。omniauth-openid-connect again

設定例

一応, gemパッケージを使うとすると, オプションが特定の値でなければならないところが多い。罠か。

次のような設定ファイルで、何とかなる。

# -*- coding:utf-8; mode:ruby -*-

# omniauth を使う.
# See https://github.com/omniauth/omniauth

Rails.application.configure do |config|
  config.middleware.use OmniAuth::Builder do
    if !Rails.env.production?
      provider :developer 

      provider :openid_connect, {
        # /auth/<name> が認証開始のURLになる.       
        name: :nov_op_sample,

        # これがないと, エラー
        # 末尾の '/' は付けてはいけない.
        # <issuer>/.well-known/openid-configuration
        issuer: 'http://localhost:4000',
        
        # 'openid' で OpenID Connect
        scope: ["openid","profile","email","address","phone"],
        
        # 'code' is Basic flow. 'token id_token' is Implicit flow.
        response_type: :code,

        # 有効にしないと, public_key() 内で config.jwks が使われない.
        # 必ず true にすること。(デフォルトはfalse)
        discovery: true, 

        # rack-oauth2 パッケージ, Rack::OAuth2::Client.new() に渡される.
        # 初期値は, omniauth-openid-connect パッケージ内,
        # omniauth/strategies/openid_connect.rb
        client_options: {
          # omniauth-openid-connect パッケージ内,
          # omniauth/strategies/openid_connect.rb:issuer() 内で,
          # 上の issuer オプションは使わず, 次の3要素から issuer を作っている.
          scheme: "http",
          host: "localhost",
          port: 4000,  # 80番でも省略できない.

          # OP側と厳密に合わせる
          identifier: クライアントID,
          secret:     クライアントsecret,
          redirect_uri: "http://localhost:3000/auth/nov_op_sample/callback",
        },
      }
    end # !Rails.env.production?
    
    # google OpenID Connect
    provider :openid_connect, {
        name: :google_oauth2,
        issuer: 'https://accounts.google.com',
        scope: [:openid, :email, :profile],
        response_type: :code,
        discovery: true, 
        client_options: {
          scheme: "https",
          host: "accounts.google.com",
          port: 443,  # 省略不可.

          identifier: クライアントID,
          secret:     クライアントsecret,
          redirect_uri: "http://localhost:3000/auth/google_oauth2/callback",
        },
    }
  end 
end

# See http://qiita.com/nekogeruge_987/items/8bd307f9ae31f27c248a
#     http://stackoverflow.com/questions/10963286/callback-denied-with-omniauth
OmniAuth.config.on_failure = Proc.new do |env|
  OmniAuth::FailureEndpoint.new(env).redirect_to_failure
end

コメントに書いているが, discovery オプションは必ず true でなければならない。issuer と, client_options の (scheme, host, port) は必ず同じもの。

openid_connect_sample

テストのために, nov/openid_connect_sample を Ruby on Rails 4.2対応にしたものを用意した。horiq / openid_connect_sample · GitLab

'openid_connect' パッケージのバグ修正を含む。

PayPal

(2017.8.20 追記)

上のリストで PayPal も OpenID Connect に対応していることになっているが、実装を確認する限り、OpenID Connect には適合していない。

amazon web services - Using Login with Paypal and using OpenID with AWS Cognito - Stack Overflow

oauth 2.0 - PayPal id_token verification - Stack Overflow

いろいろ試してみたが、access_token と別に id_token を取得することができなかった。