Skip to content

Commit

Permalink
fix.
Browse files Browse the repository at this point in the history
  • Loading branch information
hhorikawa committed Jul 10, 2024
1 parent 6a3f466 commit b05c796
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 118 deletions.
182 changes: 65 additions & 117 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@
- `"refresh_token"` grant type. トークン有効期限の延長.


# OpenIDConnect OP (IdP) Sample

# Rails OpenID Connect IdP AS

## What's this?

A sample OpenID Connect provider (OP or IdP) using the `openid_connect` gem. The Authorization Code Flow and the Implicit Flow.
A sample authorization server acting as an OpenID Connect identity provider (OP or IdP) using the `openid_connect` gem. The Authorization Code Flow with PKCE, the Implicit Flow and the Hybrid Flow are supported.

クライアントの開発のため、複数のユーザを切り替えて払い出す。デバッグのため、正常なレスポンスだけでなく、異常なレスポンスも返す。

Expand All @@ -20,106 +21,16 @@ Ruby on Rails 6.1.



## サポートする仕様

### OpenID Connect Discovery 1.0 ✓

- Issuer discovery ユーザ識別子のドメインパートのホストに対して、次のような `GET` リクエストを投げると、issuer を返す.
```
GET /.well-known/webfinger?resource=acct:[email protected]&
rel=http://openid.net/specs/connect/1.0/issuer
```
ユーザ識別子のドメインパートが IdP ホストとは限らない。現在ではほとんど用いられない

- OpenID Provider Configuration
`<issuer>/.well-known/openid-configuration``GET` する


<a href="https://qiita.com/TakahikoKawasaki/items/83c47c9830097dba2744">実装者による Financial-grade API (FAPI) 解説</a> を踏まえて、現代的な挙動へのアップデートを行うこと。Part 1: Baseline だけでよい。


- No.4 クライアント認証
```json
"token_endpoint_auth_methods_supported": [
"client_secret_post",
"private_key_jwt", ●●未了. このサポートが必須. マジか. Entra ID (旧 AzureAD) ぐらいしかサポートする IdP はないようだが.
"client_secret_basic"
],
```

No.5 `"private_key_jwt"` で RSA を用いる場合、キーサイズは 2048bit 以上。

- No.7 PKCE (RFC 7636) with `S256`: ●●未了. このサポートが必須.
認可リクエストは明示的に `code_challenge_method=S256` を含めなければならない。
discovery に `code_challenge_methods_supported` がある。(RFC 8414)
+ Yahoo! discovery あり. リクエストは任意
+ Azure AD -- 推奨, SPAの場合は必須. https://learn.microsoft.com/ja-jp/entra/identity-platform/v2-oauth2-auth-code-flow
+ Google Identity -- discovery あり. モバイル/デスクトップアプリのみ? https://developers.google.com/identity/protocols/oauth2/native-app?hl=ja
+ LINE -- discovery あり.

●● rack-oauth2 パッケージにサーバ側の PKCE サポートがある。これを使うか

- No.12 過去に認可された scope よりもリクエストされた scope が多ければ、再度ユーザに認可を求める。
Fake Users 画面から、認可した scope を削除できるようにする。●●未了

- クライアントが `openid` スコープを要求した場合, `nonce` パラメータが必須。
レスポンスの ID Token 内に `nonce` を埋め込む.
The Authorization Code Flow では OPTIONAL, The Implicit Flow では REQUIRED だが、前者でもリクエストに含めるべき。
●●未了。わざとレスポンスから `nonce` を抜いて、きちんとクライアントが確認しているかを見れるようにする。

- クライアントが `openid` スコープを要求しなかった場合, `state` パラメータが必須。ブラウザ cookie に埋め込むことで、CSRF/XSRF 緩和。
仕様では RECOMMENDED となっている。
●●未了。同様にレスポンスを不正にして、クライアントの様子を確認。




## OpenSSL v3.0 (Fedora 36, CentOS Stream 9)

`openid_connect` gem が依存する `json-jwt` 1.13.0 で次のエラーが発生. <code>OpenSSL::PKey::PKeyError</code> 型.

<pre>
rsa#set_key= is incompatible with OpenSSL 3.0
</pre>

OpenSSL の仕様変更により ruby/openssl v3.0 のいくつかのメソッドが取り除かれた。とはいえ、Ruby v2.x のときからそれらのメソッドは非推奨 deprecated になっており、しかも OpenSSL v3.0 との組み合わせでは動かない。

関連 issue: <a href="https://github.com/nov/json-jwt/issues/100">Add OpenSSL 3 support · Issue #100 · nov/json-jwt</a>

修正待つしかなさそう。




## Resources

For this sample:
* View source on GitHub: https://github.com/netsphere-labs/openid_connect_sample/

For more information, see readme and wiki for `openid_connect` gem:
* https://github.com/nov/openid_connect/

OAuth 2.0 server library:
* https://github.com/nov/rack-oauth2/


Also of interest, the corresponding sample RP:
* [OmniAuth2, OpenID Connect RP sample](https://gitlab.com/netsphere/rails-examples/-/tree/main/omniauth-oidc-rp-sample/) the Authorization Code Flow, the Implicit Flow. And, Single Logout (SLO) based on OpenID Connect RP-Initiated Logout 1.0.

* [OpenID Connect - Implicit Flow Relying Party (RP) sample](https://github.com/netsphere-labs/openid-connect-implicit-flow-rp-sample/)



## How to Run This Example on Your Machine
## How to Run

### Requirements

- Ruby on Rails v6.1
- fb_graph2
- sorcery
- sorcery ※認証フレームワークは何でもよい。
- openid_connect

This sample application does not use "omniauth-openid-connect" gem.
This IdP does not use "omniauth-openid-connect" or "doorkeeper-openid_connect" gem.


### Localhost
Expand All @@ -136,14 +47,12 @@ To run this in development mode on your local machine:

<pre>
# su postgres
$ createdb --owner rails --encoding utf-8 openid-connect-sample_dev
$ createdb --owner DBユーザ名 --encoding utf-8 openid-connect-sample_dev
</pre>

<p><kbd>rake db:migrate</kbd>, <kbd>rake db:seed</kbd> でもよい。

<pre>
$ rails db:migrate
$ rails db:seed
$ bin/rails db:migrate
$ bin/rails db:seed
</pre>

5. Copy `config/connect/facebook.yml.sample` to `facebook.yml`. And Google's.
Expand All @@ -152,16 +61,16 @@ Set `client_id` and `client_secret`
Sorcery による OpenID Connect Login, Facebook Login のサンプルを兼ねている。


6. Modify `config/connect/id_token/issuer.yml` -- change `issuer` value to `http://localhost:3000`
6. Modify `config/connect/id_token/issuer.yml` -- change `issuer` value to `http://localhost:4000`

7. Run!

```
$ bin/yarn
$ bin/rails assets:precompile
$ bundle exec rails server -p 3000
```

production 環境の場合は, まず、次のようにしてコンパイルする。
production 環境の場合は, 次のようにしてコンパイルする。

```
$ RAILS_ENV=production bin/rails assets:precompile
Expand All @@ -176,28 +85,72 @@ RAILS_ENV=production passenger start
```


### 使い方


## 使い方

1. Facebook または Google でログインする

Admin user としてログインする。
Admin user としてログインする。払い出すユーザは "Fake Users" から確認できる。


2. [Register New Client...] から, RPを登録する。

redirect_uri は複数登録可能。
`redirect_uri` は複数登録可能。

3. RP側で, `client_id`, `client_secret` を登録する。

4. RP 側からログイン可能か確認する。
この IdP では、払い出すユーザを都度選択するようになっている。

3. RP側で, client_id, client_secret を登録する。


To see it in action right now:

* press "Discover"
* the RP will use the OP to authenticate
## Copyright

Copyright (c) 2011 nov matake. See LICENSE for details.

Copyright (c) 2020-2021,2024 Hisashi Horikawa.





Point your browser at http://localhost:3000
## Resources

This IdP:
* View source on GitHub: https://github.com/netsphere-labs/rails-openid-connect-idp-as/

For more information, see readme and wiki for `openid_connect` gem:
* https://github.com/nov/openid_connect/

OAuth 2.0 server library:
* https://github.com/nov/rack-oauth2/

Also of interest, the corresponding sample RP:
* [Rails OpenID Connect RP Sample](https://github.com/netsphere-labs/rails-openid-connect-rp-sample/) the Authorization Code Flow, the Implicit Flow. And, Single Logout (SLO) based on OpenID Connect RP-Initiated Logout 1.0.





## Topic: OpenSSL v3.0 (Fedora 36, CentOS Stream 9)

`openid_connect` gem が依存する `json-jwt` 1.13.0 で次のエラーが発生. <code>OpenSSL::PKey::PKeyError</code> 型.

<pre>
rsa#set_key= is incompatible with OpenSSL 3.0
</pre>

OpenSSL の仕様変更により ruby/openssl v3.0 のいくつかのメソッドが取り除かれた。とはいえ、Ruby v2.x のときからそれらのメソッドは非推奨 deprecated になっており、しかも OpenSSL v3.0 との組み合わせでは動かない。

関連 issue: <a href="https://github.com/nov/json-jwt/issues/100">Add OpenSSL 3 support · Issue #100 · nov/json-jwt</a>






####


Obviously, external servers will not be able to connect to an OP that is running on localhost.
Expand Down Expand Up @@ -230,8 +183,3 @@ This problem is beyond the scope of this README, but
may be of help.


## Copyright

Copyright (c) 2011 nov matake. See LICENSE for details.

Copyright (c) 2020-2021,2024 Hisashi Horikawa.
2 changes: 1 addition & 1 deletion app/controllers/authorizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ def request_validation req, res
# FAPI: `openid` scope を要求した場合は `nonce` 必須.
if (res.protocol_params_location == :fragment || Scope.ary_find(@scopes, 'openid')) &&
req.nonce.blank?
req.invalid_request! 'nonce required'
req.invalid_request! "`nonce` required"
end

if !Scope.ary_find(@scopes, 'openid')
Expand Down
98 changes: 98 additions & 0 deletions doc/supported-specifications.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

# Supported Specifications

<a href="https://qiita.com/TakahikoKawasaki/items/83c47c9830097dba2744">実装者による Financial-grade API (FAPI) 解説</a> を踏まえて、現代的な挙動へのアップデートを行う。

<s>Part 1: Baseline だけでよい。</s> よくない。Baseline は採用されず、英国オープンバンキングでは FAPI 1.0 Part 2: Advanced だけが採用された。技術的にも両者は差が大きく、わざわざ両方を参照せず, Part 2 のみを参照すればよい。

<blockquote cite="https://openid.net/certification/certification-fapi_op_testing/">
<p>FAPI 1.0 Advanced Final is an evolution of the FAPI RW draft. The ‘read write’ part was removed from the specification name to avoid confusion, due to many ecosystems choosing to use the more secure ‘read write’ profile for read-only operations.
</blockquote>




## OpenID Connect Discovery 1.0 ✓

- Issuer discovery ユーザ識別子のドメインパートのホストに対して、次のような `GET` リクエストを投げると、issuer を返す.
```
GET /.well-known/webfinger?resource=acct:[email protected]&
rel=http://openid.net/specs/connect/1.0/issuer
```
ユーザ識別子のドメインパートが IdP ホストとは限らない。現在ではほとんど用いられない

- OpenID Provider Configuration 必須✓
`<issuer>/.well-known/openid-configuration``GET` する




## OpenID Connect Core 1.0

- No.4 Token Endpoint におけるクライアント認証
+ "client_secret_basic" ✓
+ "client_secret_post" ✓
+ "private_key_jwt", ●●未了. FAPI はこのサポートが必須. マジか. Entra ID (旧 AzureAD) ぐらいしかサポートする IdP はない.

- No.5 `"private_key_jwt"` で RSA を用いる場合、キーサイズは 2048bit 以上。

- No.12 過去に認可された scope よりもリクエストされた scope が多ければ、再度ユーザに認可を求める。

テストのため, Fake Users 画面から、認可した scope を削除できるようにする。●●未了

- クライアントが `openid` スコープを要求した場合, `nonce` パラメータが必須。
レスポンスの ID Token 内に `nonce` を埋め込む. ✓

The Authorization Code Flow では OPTIONAL, The Implicit Flow, Hybrid Flow では REQUIRED だが、前者でもリクエストに含めるべき。

- クライアントが `openid` スコープを要求しなかった場合, `state` パラメータが必須。ブラウザ cookie に埋め込むことで、CSRF/XSRF 緩和。
仕様では RECOMMENDED となっている。
●●テスト未了。同様にレスポンスを不正にして、クライアントの様子を確認。




## Proof Key for Code Exchange by OAuth Public Clients (PKCE, RFC 7636) ✓

- No.7 PKCE (RFC 7636) with `S256` 実装すみ✓

- 認可リクエストは明示的に `code_challenge_method=S256` を含めなければならない。

- discovery に `code_challenge_methods_supported` がある。(RFC 8414) ✓

ほかの IdP:
+ Yahoo! discovery あり. リクエストは任意
+ Azure AD -- 推奨, SPAの場合は必須. https://learn.microsoft.com/ja-jp/entra/identity-platform/v2-oauth2-auth-code-flow
+ Google Identity -- discovery あり. モバイル/デスクトップアプリのみ? https://developers.google.com/identity/protocols/oauth2/native-app?hl=ja
+ LINE -- discovery あり.




### The OAuth 2.0 Authorization Framework: JWT-Secured Authorization Request (JAR, RFC 9101)

- クライアントは, `request` パラメータで署名付きの request object を送付。OpenID Connect Core 1.0 で要求されるパラメータであっても、request object の外側のものは無視。✓

- AS 側でクライアントの公開鍵を使って署名の検証 ●未了

- `request_uri` パラメータで request object 参照を送付。これは非常に筋が悪い。次の PAR のみをサポート。




### OAuth 2.0 Pushed Authorization Requests (PAR, RFC 9126)

2021年9月に発行された仕様。

まずクライアントが直接認可サーバ (AS) にリクエストを POST, AS がトークンを発行し, リダイレクトを介したリクエスト時は, `request_uri` パラメータにそのトークンを set.

長い長い年月を経て, OAuth 1.0 (2010年) に還ってきた。Temporary Credentials (Request Token and Secret) の取得からの Resource Owner Authorization URI.

<a href="https://web.archive.org/web/20161004175011/https://hueniverse.com/2012/07/26/oauth-2-0-and-the-road-to-hell/">OAuth 2.0 and the Road to Hell</a>
コメントの一つ: https://alexbilbie.github.io/2012/07/oauth-2-0-and-the-road-to-hell/

OAuth 1.0 は "confidential" client type しかサポートしない。Yes, FAPI も同様に "confidential" client type しかサポートしない。

フロー図がある; https://oauth.jp/blog/2014/06/23/csrf-on-twitter-login/ OAuth 1.0 であっても当然, 実装が下手打つと穴ができる。他方、仕様のとおりに実装したら巨大な穴があく OAuth 2.0 は、仕様に穴がある。


0 comments on commit b05c796

Please sign in to comment.