diff --git a/app/controllers/authorizations_controller.rb b/app/controllers/authorizations_controller.rb index b91699b..93d14ac 100644 --- a/app/controllers/authorizations_controller.rb +++ b/app/controllers/authorizations_controller.rb @@ -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() # ここでセッションがリセットされる @@ -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| @@ -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) @@ -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) しか返さない. @@ -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 # 事前検査済みなので、これでよい. @@ -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 @@ -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! diff --git a/app/controllers/discovery_controller.rb b/app/controllers/discovery_controller.rb index 9ee4742..32b6286 100644 --- a/app/controllers/discovery_controller.rb +++ b/app/controllers/discovery_controller.rb @@ -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, @@ -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 diff --git a/app/models/request_object.rb b/app/models/request_object.rb index 1c02d75..0afbc44 100644 --- a/app/models/request_object.rb +++ b/app/models/request_object.rb @@ -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 として # 扱わなければならない. - 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