From 0e5426ad0026d52a44dd7c0e76a894860022bb34 Mon Sep 17 00:00:00 2001 From: mo khan Date: Mon, 17 Mar 2025 20:36:48 -0600 Subject: feat: exchange an authorization grant for a token --- bin/idp | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 6 deletions(-) (limited to 'bin') diff --git a/bin/idp b/bin/idp index 622faa1..23510bd 100755 --- a/bin/idp +++ b/bin/idp @@ -378,6 +378,50 @@ module Authz end end + class AuthorizationGrant + class << self + def all + @all ||= [] + end + + # TODO:: Look up saml_assertion + def find_by(params) + case params[:grant_type] + when "authorization_code" + # TODO:: implement `code_verifier` param + all.find do |grant| + grant.code == params[:code] + end + end + end + + def create!(user) + new(user).tap do |grant| + all << grant + end + end + end + + attr_reader :code, :user + + def initialize(user) + @user = user + @code = SecureRandom.uuid + @exchanged_at = nil + end + + def used? + @exchanged_at + end + + def create_access_token + raise "Invalid code" if used? + + @exchanged_at = Time.now + user.create_access_token + end + end + class OAuthController include ::HTTPHelpers @@ -407,10 +451,13 @@ module Authz when "/oauth/authorize" # RFC-6749 return post_authorize(request) when "/oauth/token" # RFC-6749 - # TODO:: Look up authorization grant by (code, saml_assertion) - user = Authn::User.new(id: SecureRandom.uuid) - return [200, { 'Content-Type' => "application/json" }, [JSON.pretty_generate({ - access_token: user.create_access_token.to_jwt, + params = request.content_type == "application/json" ? JSON.parse(request.body.read, symbolize_names: true) : Hash[URI.decode_www_form(request.body.read)].transform_keys(&:to_sym) + puts params.inspect + grant = AuthorizationGrant.find_by(params) + + return [404, { "Content-Type" => "application/json" }, [JSON.pretty_generate({ error: 404, message: "Not Found" })]] if grant.nil? || grant.used? + return [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate({ + access_token: grant.create_access_token.to_jwt, token_type: "Bearer", issued_token_type: "urn:ietf:params:oauth:token-type:access_token", expires_in: 3600, @@ -453,13 +500,15 @@ module Authz def post_authorize(request) params = request.params.slice('client_id', 'redirect_uri', 'response_type', 'response_mode', 'state', 'code_challenge_method', 'code_challenge', 'scope') + + grant = AuthorizationGrant.create!(current_user(request)) case params['response_type'] when 'code' case params['response_mode'] when 'fragment' - return [302, { 'Location' => "#{params['redirect_uri']}#code=#{SecureRandom.uuid}&state=#{params['state']}" }, []] + return [302, { 'Location' => "#{params['redirect_uri']}#code=#{grant.code}&state=#{params['state']}" }, []] when 'query' - return [302, { 'Location' => "#{params['redirect_uri']}?code=#{SecureRandom.uuid}&state=#{params['state']}" }, []] + return [302, { 'Location' => "#{params['redirect_uri']}?code=#{grant.code}&state=#{params['state']}" }, []] else # TODO:: form post end -- cgit v1.2.3