From 321b24d2a0daac52d40fb462431937397de1d58d Mon Sep 17 00:00:00 2001 From: Mac Siri Date: Thu, 14 May 2020 09:55:53 -0400 Subject: [PATCH] [deploy] Create write_articles oauth scope (#7834) --- app/controllers/api/v0/articles_controller.rb | 4 +- config/initializers/doorkeeper.rb | 4 +- config/locales/doorkeeper.en.yml | 1 + spec/requests/api/v0/articles_spec.rb | 57 ++++++++++++------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/app/controllers/api/v0/articles_controller.rb b/app/controllers/api/v0/articles_controller.rb index f9bf5f8e0..5edc13aee 100644 --- a/app/controllers/api/v0/articles_controller.rb +++ b/app/controllers/api/v0/articles_controller.rb @@ -1,9 +1,9 @@ module Api module V0 class ArticlesController < ApiController - before_action :authenticate_with_api_key_or_current_user!, only: %i[create update] - before_action :authenticate!, only: :me + before_action :authenticate!, only: %i[create update me] before_action -> { doorkeeper_authorize! :public }, only: %w[index show], if: -> { doorkeeper_token } + before_action -> { doorkeeper_authorize! :write_articles }, only: %w[create update], if: -> { doorkeeper_token } before_action :validate_article_param_is_hash, only: %w[create update] diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 6c981cda1..aa6c1c005 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -211,7 +211,7 @@ Doorkeeper.configure do # https://doorkeeper.gitbook.io/guides/ruby-on-rails/scopes # default_scopes :public, :read_articles - # optional_scopes :write, :update + optional_scopes :write_articles # Allows to restrict only certain scopes for grant_type. # By default, all the scopes will be available for all the grant types. @@ -226,7 +226,7 @@ Doorkeeper.configure do # not in configuration, i.e. +default_scopes+ or +optional_scopes+. # (disabled by default) # - # enforce_configured_scopes + enforce_configured_scopes # Change the way client credentials are retrieved from the request object. # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml index 039359e23..e7139ef56 100644 --- a/config/locales/doorkeeper.en.yml +++ b/config/locales/doorkeeper.en.yml @@ -22,6 +22,7 @@ en: scopes: public: 'Access public profile data and published articles' read_articles: 'Access all articles including drafts' + write_articles: 'Access to creating and updating articles' applications: confirmations: diff --git a/spec/requests/api/v0/articles_spec.rb b/spec/requests/api/v0/articles_spec.rb index abbefc29b..56f70e0df 100644 --- a/spec/requests/api/v0/articles_spec.rb +++ b/spec/requests/api/v0/articles_spec.rb @@ -462,14 +462,6 @@ RSpec.describe "Api::V0::Articles", type: :request do post api_articles_path, headers: { "api-key" => api_secret.secret, "content-type" => "application/json" } expect(response).to have_http_status(:unauthorized) end - - it "fails when oauth's access_token" do - access_token = create(:doorkeeper_access_token, resource_owner_id: user.id) - headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } - - post api_articles_path, params: { article: { title: Faker::Book.title } }.to_json, headers: headers - expect(response).to have_http_status(:unauthorized) - end end describe "when authorized" do @@ -481,6 +473,22 @@ RSpec.describe "Api::V0::Articles", type: :request do post api_articles_path, params: { article: params }.to_json, headers: headers end + it "returns a 403 if :write_articles scope is missing (oauth)" do + access_token = create(:doorkeeper_access_token, resource_owner_id: user.id, scopes: "public") + headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } + + post api_articles_path, params: { article: { title: Faker::Book.title } }.to_json, headers: headers + expect(response).to have_http_status(:forbidden) + end + + it "returns a 201 if :write_articles scope is provided (oauth)" do + access_token = create(:doorkeeper_access_token, resource_owner_id: user.id, scopes: "write_articles") + headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } + + post api_articles_path, params: { article: { title: Faker::Book.title, body_markdown: "" } }.to_json, headers: headers + expect(response).to have_http_status(:created) + end + it "returns a 429 status code if the rate limit is reached" do rate_limit_checker = instance_double(RateLimitChecker) retry_after_val = RateLimitChecker::ACTION_LIMITERS.dig(:published_article_creation, :retry_after) @@ -765,17 +773,6 @@ RSpec.describe "Api::V0::Articles", type: :request do put path, headers: { "api-key" => api_secret.secret, "content-type" => "application/json" } expect(response).to have_http_status(:unauthorized) end - - it "fails with oauth's access_token" do - access_token = create(:doorkeeper_access_token, resource_owner_id: user.id) - headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } - - title = Faker::Book.title - body_markdown = "foobar" - params = { title: title, body_markdown: body_markdown } - put path, params: { article: params }.to_json, headers: headers - expect(response).to have_http_status(:unauthorized) - end end describe "when authorized" do @@ -786,6 +783,28 @@ RSpec.describe "Api::V0::Articles", type: :request do put path, params: { article: params }.to_json, headers: headers end + it "returns a 403 if :write_articles scope is missing (oauth)" do + access_token = create(:doorkeeper_access_token, resource_owner_id: user.id) + headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } + + title = Faker::Book.title + body_markdown = "foobar" + params = { title: title, body_markdown: body_markdown } + put path, params: { article: params }.to_json, headers: headers + expect(response).to have_http_status(:forbidden) + end + + it "returns a 200 if :write_articles scope is provided (oauth)" do + access_token = create(:doorkeeper_access_token, resource_owner_id: user.id, scopes: "write_articles") + headers = { "authorization" => "Bearer #{access_token.token}", "content-type" => "application/json" } + + title = Faker::Book.title + body_markdown = "foobar" + params = { title: title, body_markdown: body_markdown } + put path, params: { article: params }.to_json, headers: headers + expect(response).to have_http_status(:ok) + end + it "returns a 429 status code if the rate limit is reached" do rate_limit_checker = instance_double(RateLimitChecker) retry_after_val = RateLimitChecker::ACTION_LIMITERS.dig(:article_update, :retry_after)