From b27894fcfee8a8422ca191ccd87f641eb8befcf0 Mon Sep 17 00:00:00 2001 From: mo khan Date: Sat, 15 Mar 2025 15:20:53 -0600 Subject: refactor: authorize unsigned JWT in requests --- bin/api | 26 ++++++++++++++++++-------- bin/idp | 14 ++++++++++---- bin/ui | 8 +------- 3 files changed, 29 insertions(+), 19 deletions(-) (limited to 'bin') diff --git a/bin/api b/bin/api index 0260cd79..868d5754 100755 --- a/bin/api +++ b/bin/api @@ -55,6 +55,10 @@ class Entity def to_h @attributes end + + def to_gid + ::GlobalID.create(self, app: "example") + end end class Organization < Entity @@ -73,11 +77,11 @@ module HTTPHelpers authorization = Rack::Auth::AbstractRequest.new(request.env) return false unless authorization.provided? - response = rpc.allowed( + response = rpc.allowed({ subject: authorization.params, permission: permission, - resource: ::GlobalID.create(resource, app: "example").to_s - ) + resource: resource.to_gid.to_s, + }, headers: { 'Authorization' => "Bearer #{authorization.params}"}) response.error.nil? && response.data.result end @@ -93,11 +97,11 @@ module HTTPHelpers http_response(code: 201, body: JSON.pretty_generate(body.to_h)) end - def json_unauthorized(permission) + def json_unauthorized(permission, resource) http_response(code: 401, body: JSON.pretty_generate({ error: { code: 401, - message: "`#{permission}` is required", + message: "`#{permission}` is required on `#{resource.to_gid}`", } })) end @@ -128,15 +132,21 @@ class API when "/organizations", "/organizations.json" return json_ok(Organization.all.map(&:to_h)) when "/projects", "/projects.json" - return json_ok(Project.all.map(&:to_h)) + resource = Organization.default + if authorized?(request, :read_project, resource) + return json_ok(Project.all.map(&:to_h)) + else + return json_unauthorized(:read_project, resource) + end end when Rack::POST case request.path when "/projects", "/projects.json" - if authorized?(request, :create_project, Organization.default) + resource = Organization.default + if authorized?(request, :create_project, resource) return json_created(Project.create!(JSON.parse(request.body.read, symbolize_names: true))) else - return json_unauthorized(:create_project) + return json_unauthorized(:create_project, resource) end end end diff --git a/bin/idp b/bin/idp index 3aeeb079..81e5ffe0 100755 --- a/bin/idp +++ b/bin/idp @@ -322,6 +322,7 @@ module Authz class OrganizationPolicy < DeclarativePolicy::Base condition(:owner) { true } + rule { owner }.enable :read_project rule { owner }.enable :create_project end @@ -334,9 +335,9 @@ module Authz def to_jwt [ - Base64.strict_encode64(JSON.generate({alg: "RS256", typ: "JWT"})), + Base64.strict_encode64(JSON.generate(alg: "none")), Base64.strict_encode64(JSON.generate(claims)), - Base64.strict_encode64(JSON.generate({})), + "" ].join(".") end end @@ -354,8 +355,13 @@ module Authz def can?(request) subject = subject_of(request.subject) resource = resource_from(request.resource) + permission = request.permission.to_sym + policy = DeclarativePolicy.policy_for(subject, resource) - policy.can?(request.permission.to_sym) + policy.can?(permission) + rescue StandardError => error + puts error.inspect + false end def subject_of(token) @@ -371,7 +377,7 @@ module Authz def from_jwt(token) token .split('.', 3) - .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) } + .map { |x| JSON.parse(Base64.strict_decode64(x), symbolize_names: true) rescue {} } end end end diff --git a/bin/ui b/bin/ui index 04ad01a1..997a151a 100755 --- a/bin/ui +++ b/bin/ui @@ -108,13 +108,7 @@ class UI } ) end - if response.code.to_i == 200 - [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate( - request.params.merge(JSON.parse(response.body)) - )]] - else - [response.code, response.header, [response.body]] - end + [response.code, response.header, [response.body]] end def saml_post_to_idp(request) -- cgit v1.2.3