Commit 66edae4

mo khan <mo@mokhan.ca>
2025-03-18 02:53:09
refactor: add shim to handle other types of authorization grants
1 parent 0e5426a
Changed files (1)
bin
bin/idp
@@ -79,9 +79,9 @@ module Authn
         end
       end
 
-      def find_by_credentials(params = {})
-        user = find_by_username(params["username"])
-        user&.valid_password?(params["password"]) ? user : nil
+      def login(params = {})
+        user = find_by_username(params[:username])
+        user&.valid_password?(params[:password]) ? user : nil
       end
     end
 
@@ -148,7 +148,7 @@ module Authn
       when Rack::POST
         case request.path
         when '/sessions'
-          if (user = User.find_by_credentials(request.params))
+          if (user = User.login(request.params.transform_keys(&:to_sym)))
             request.session[:user_id] = user[:id]
             path = request.params["redirect_back"] ? request.params["redirect_back"] : "/"
             return http_redirect_to(path)
@@ -387,14 +387,48 @@ module Authz
       # 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
+        when 'authorization_code'
+          authorization_code_grant(params[:code], params[:code_verifier])
+        when 'refresh_token'
+          refresh_grant(params[:refresh_token])
+        when 'client_credentials'
+          client_credentials_grant(params)
+        when 'password'
+          password_grant(params[:username], params[:password])
+        when 'urn:ietf:params:oauth:grant-type:saml2-bearer' # RFC7522
+          saml_assertion_grant(params[:assertion])
+        when 'urn:ietf:params:oauth:grant-type:jwt-bearer' # RFC7523
+          jwt_bearer_grant(params)
+        end
+      end
+
+      # TODO:: implement `code_verifier` param
+      def authorization_code_grant(code, code_verifier)
+        all.find do |grant|
+          grant.active? && grant.code == code
         end
       end
 
+      def refresh_grant(refresh_token)
+        raise NotImplementedError
+      end
+
+      def client_credential_grant(params)
+        raise NotImplementedError
+      end
+
+      def password_grant(username, password)
+        raise NotImplementedError
+      end
+
+      def saml_assertion_grant(saml_assertion)
+        raise NotImplementedError
+      end
+
+      def jwt_bearer_grant(params)
+        raise NotImplementedError
+      end
+
       def create!(user)
         new(user).tap do |grant|
           all << grant
@@ -410,15 +444,30 @@ module Authz
       @exchanged_at = nil
     end
 
-    def used?
-      @exchanged_at
+    def active?
+      @exchanged_at.nil?
+    end
+
+    def inactive?
+      !active?
     end
 
     def create_access_token
-      raise "Invalid code" if used?
+      raise "Invalid code" unless active?
 
-      @exchanged_at = Time.now
-      user.create_access_token
+      user.create_access_token.tap do
+        @exchanged_at = Time.now
+      end
+    end
+
+    def exchange
+      {
+        access_token: create_access_token.to_jwt,
+        token_type: "Bearer",
+        issued_token_type: "urn:ietf:params:oauth:token-type:access_token",
+        expires_in: 3600,
+        refresh_token: SecureRandom.hex(32)
+      }
     end
   end
 
@@ -452,17 +501,10 @@ module Authz
           return post_authorize(request)
         when "/oauth/token" # RFC-6749
           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,
-            refresh_token: SecureRandom.hex(32)
-          })]]
+          return [404, { "Content-Type" => "application/json" }, [JSON.pretty_generate(error: 404, message: "Not Found")]] if grant.nil? || grant.inactive?
+          return [200, { "Content-Type" => "application/json" }, [JSON.pretty_generate(grant.exchange)]]
         when "/oauth/revoke" # RFC-7009
           # TODO:: Revoke the JWT token and make it ineligible for usage
           return http_not_found