diff --git a/app/controllers/concerns/authentication.rb b/app/controllers/concerns/authentication.rb index 510cac074..5dc3fb866 100644 --- a/app/controllers/concerns/authentication.rb +++ b/app/controllers/concerns/authentication.rb @@ -59,8 +59,10 @@ module Authentication authorization_scheme, bearer_token = request.authorization.to_s.split(" ", 2) if authorization_scheme == "Bearer" && bearer_token.present? - if identity = Identity.find_by_access_token(bearer_token) - Current.identity = identity + access_token = Identity::AccessToken.find_by(token: bearer_token) + + if access_token && access_token.allows?(request.method) + Current.identity = access_token.identity else head :unauthorized end diff --git a/app/models/identity/access_token.rb b/app/models/identity/access_token.rb index a5b719ab9..abdf37eba 100644 --- a/app/models/identity/access_token.rb +++ b/app/models/identity/access_token.rb @@ -3,4 +3,8 @@ class Identity::AccessToken < ApplicationRecord has_secure_token enum :permission, %w[ read write ].index_by(&:itself), default: :read + + def allows?(method) + method.in?(%w[ GET HEAD ]) || write? + end end diff --git a/test/controllers/api_test.rb b/test/controllers/api_test.rb index 7eff2d7bb..f33dfe997 100644 --- a/test/controllers/api_test.rb +++ b/test/controllers/api_test.rb @@ -3,6 +3,7 @@ require "test_helper" class ApiTest < ActionDispatch::IntegrationTest setup do @davids_bearer_token = bearer_token_env(identity_access_tokens(:davids_api_token).token) + @jasons_bearer_token = bearer_token_env(identity_access_tokens(:jasons_api_token).token) end test "authenticate with valid access token" do @@ -15,6 +16,14 @@ class ApiTest < ActionDispatch::IntegrationTest assert_response :unauthorized end + test "changing data requires a write-endowed access token" do + post boards_path(format: :json), params: { board: { name: "My new board" } }, env: @jasons_bearer_token + assert_response :unauthorized + + post boards_path(format: :json), params: { board: { name: "My new board" } }, env: @davids_bearer_token + assert_response :redirect + end + test "boards" do get boards_path(format: :json), env: @davids_bearer_token assert_equal users(:david).boards.count, @response.parsed_body.count