Skip to content

Commit

Permalink
finish the Code Flow with PKCE.
Browse files Browse the repository at this point in the history
  • Loading branch information
hhorikawa committed Jul 8, 2024
1 parent e8bbd20 commit 6a3f466
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 26 deletions.
33 changes: 20 additions & 13 deletions app/controllers/authorizations_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def new
# ログインしていなければ、または max_age を経過していたら, ログインを求め
# る.
# 本来は, 実際にログインするユーザ.
if logged_in? && (max_age = @request_object.max_age) &&
if logged_in? && (max_age = @request_object.params['max_age']) &&
current_user.last_login_at < max_age.seconds.ago
flash[:alert] = 'Exceeded Max Age, Login Again'
logout() # ここでセッションがリセットされる
Expand All @@ -69,12 +69,15 @@ def new
# POST
# ユーザの approve/deny を受けて、RPにリダイレクトバックする.
def create
req = session[params['_viewstate']][:params]
req = session[params['_viewstate']]['params'] # ここは key が文字列
session.delete(params['_viewstate'])
@request_object = RequestObject.find_or_build_from_params req

@fake_user = FakeUser.find params[:fake_user]
@authorized_scopes = params[:scope] # ● 配列になるか?
raise "check"
# {"openid"=>"1", "email"=>"1", "profile"=>"1"}
@authorized_scopes = params[:scope].keys.map do |n|
Scope.find_by_name(n) || raise
end
approved = params[:approve]

call_authorization_endpoint(@request_object) do |req, res|
Expand Down Expand Up @@ -107,9 +110,10 @@ def create
def call_authorization_endpoint(request_obj, &block)
endpoint = Rack::OAuth2::Server::Authorize.new &block
req = {
Rack::RACK_REQUEST_QUERY_HASH => request_obj,
Rack::RACK_REQUEST_QUERY_HASH => request_obj.params,
Rack::RACK_REQUEST_QUERY_STRING => "X",
Rack::QUERY_STRING => "X",
Rack::RACK_INPUT => "X",
}
# 戻り値 = [ 200, {"Content-Type" => "text/plain"}, ["Hello Rack!\n\n"] ]
status, header, res_body = endpoint.call(req)
Expand Down Expand Up @@ -180,7 +184,8 @@ def request_validation req, res
# 'code id_token', # Hybrid Flow 認可コード + IDトークン #fragment. エラーも fragment で.
def consent_and_redirect_back(req, res)
response_types = Array(req.response_type)
redirect_uri = req.verify_redirect_uri!(@request_object.client.redirect_uris)
res.redirect_uri = redirect_uri =
req.verify_redirect_uri!(@request_object.client.redirect_uris)

if response_types.include? :code
# Authentication Response では code (と state) しか返さない.
Expand All @@ -198,8 +203,9 @@ def consent_and_redirect_back(req, res)
end
authorization.save!
authorization.scopes << @authorized_scopes # ユーザ (fake_user) が認可した scope

res.code = authorization.code
end
res.code = authorization.code
end

# 事前検査済みなので、これでよい.
Expand All @@ -215,8 +221,9 @@ def consent_and_redirect_back(req, res)
end
access_token.save!
access_token.scopes << @authorized_scopes

res.access_token = access_token.to_bearer_token
end
res.access_token = access_token.to_bearer_token
end

if response_types.include? :id_token
Expand All @@ -231,12 +238,12 @@ def consent_and_redirect_back(req, res)
end
end
_id_token_.save!

res.id_token = _id_token_.to_jwt(
code: (res.respond_to?(:code) ? res.code : nil),
access_token: (res.respond_to?(:access_token) ? res.access_token : nil)
)
end

res.id_token = _id_token_.to_jwt(
code: (res.respond_to?(:code) ? res.code : nil),
access_token: (res.respond_to?(:access_token) ? res.access_token : nil)
)
end

res.approve!
Expand Down
8 changes: 5 additions & 3 deletions app/controllers/discovery_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ def webfinger_discovery


def openid_configuration
config = OpenIDConnect::Discovery::Provider::Config::Response.new(
# `OpenIDConnect::Discovery::Provider::Config::Response` はクライアントが
# 使うクラス.
config = {
issuer: IdToken.config[:issuer],
authorization_endpoint: new_authorization_url,
token_endpoint: access_tokens_url,
Expand All @@ -81,8 +83,8 @@ def openid_configuration
claims_supported: ['sub', 'iss',
'name', 'email', 'email_verified', 'address', 'profile', 'locale', 'phone_number'],
# PKCE
code_challenge_methods_supported: ['S256'] ●●これが表示されない
)
code_challenge_methods_supported: ['S256']
}
render json: config
end
end
22 changes: 12 additions & 10 deletions app/models/request_object.rb
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,35 @@ def to_request_object


def self.find_or_build_from_params(params, defaults = {})
client = Client.find_by_identifier(params[:client_id]) ||
raise(Rack::OAuth2::Server::Authorize::BadRequest)
raise TypeError if params.nil?

client = Client.find_by_identifier(params['client_id']) ||
raise(Rack::OAuth2::Server::Authorize::BadRequest.new('client_id'))
# 両方は不可
if !params[:request].blank? && !params[:request_uri].blank?
raise(Rack::OAuth2::Server::Authorize::BadRequest)
if !params['request'].blank? && !params['request_uri'].blank?
raise Rack::OAuth2::Server::Authorize::BadRequest.new("Both of `request` and `request_uri`")
end

if !params[:request].blank?
if !params['request'].blank?
# リクエストオブジェクト外のパラメータは全部無視. JAR section 6.3
# 署名アルゴリズムは `PS256` もしくは `ES256` のどちらか FAPI 1.0 Part 2, Section 8.6
# `OpenIDConnect::RequestObject.decode()` メソッドもよくない。alg を制限できない。
# `params` を差し替え
params = JSON::JWT.decode(params[:request], client.client_public_keys,
params = JSON::JWT.decode(params['request'], client.client_public_keys,
SIGNING_ALG_VALUES_SUPPORTED)
if params.client_id != client.identifier
raise(Rack::OAuth2::Server::Authorize::BadRequest)
end
elsif !params[:request_uri].blank?
elsif !params['request_uri'].blank?
# ここで `OpenIDConnect::RequestObject.fetch()` を呼び出してはいけない
# DDoS 攻撃してしまう.
# -> かならず PAR <https://www.rfc-editor.org/rfc/rfc9126.html> として
# 扱わなければならない.
if params[:request_uri].index(REQUEST_URI_SCHEME) != 0
raise(Rack::OAuth2::Server::Authorize::BadRequest)
if params['request_uri'].index(REQUEST_URI_SCHEME) != 0
raise Rack::OAuth2::Server::Authorize::BadRequest.new('uri scheme')
end
ret = find_by_reference_value(
params[:request_uri][REQUEST_URI_SCHEME.length .. -1] )
params['request_uri'][REQUEST_URI_SCHEME.length .. -1] )
if !ret || ret.client_id != client.identifier
raise(Rack::OAuth2::Server::Authorize::BadRequest)
end
Expand Down

0 comments on commit 6a3f466

Please sign in to comment.