Skip to content

Commit

Permalink
Add read-only configuration
Browse files Browse the repository at this point in the history
- When read-only mode is enabled via rails config, controller endpoints that are explicitly enrolled into a `read_safe` list return a HTTP 405 Method Not Allowed when invoked, also throwing Conjur error code: `CONJ00153E`
- Implemented using module prepending
  • Loading branch information
codihuston committed Aug 8, 2023
1 parent 0c6c4b2 commit f32a4d3
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 0 deletions.
1 change: 1 addition & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class UnprocessableEntity < RuntimeError
rescue_from GatewayTimeout, with: :gateway_timeout
rescue_from BadGateway, with: :bad_gateway
rescue_from Exceptions::NotImplemented, with: :not_implemented
rescue_from Errors::Conjur::ReadOnlyModeMethodNotAllowed, with: :method_not_allowed
rescue_from Sequel::ValidationFailed, with: :validation_failed
rescue_from Sequel::NoMatchingRow, with: :no_matching_row
rescue_from Sequel::ForeignKeyConstraintViolation, with: :foreign_key_constraint_violation
Expand Down
14 changes: 14 additions & 0 deletions app/controllers/concerns/prepend.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module ReadOnlyPrepender
# Given a list of method symbols, preempt calls to them using a proxy that raises an error if read_only_api is enabled.
def read_safe(*method_names)
method_names.each do |m|
proxy = Module.new do
define_method(m) do |*args|
raise Errors::Conjur::ReadOnlyModeMethodNotAllowed.new() unless !Rails.configuration.read_only_api
super *args
end
end
self.prepend proxy
end
end
end
3 changes: 3 additions & 0 deletions app/controllers/policies_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
class PoliciesController < RestController
include FindResource
include AuthorizeResource
extend ReadOnlyPrepender

before_action :current_user
before_action :find_or_create_root_policy
read_safe :put, :patch, :post
after_action :publish_event, if: -> { response.successful? }

rescue_from Sequel::UniqueConstraintViolation, with: :concurrent_load
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/secrets_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
class SecretsController < RestController
include FindResource
include AuthorizeResource
extend ReadOnlyPrepender

before_action :current_user
read_safe :create, :expire # TODO: should we disable the expire endpoint?

def create
authorize(:update)
Expand Down
5 changes: 5 additions & 0 deletions app/domain/errors.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ module Conjur
msg: "Resource '{0-resource}' requested by role '{1-role}' not found",
code: "CONJ00123E"
)

ReadOnlyModeMethodNotAllowed = ::Util::TrackableErrorClass.new(
msg: "This action is not permitted when the server is in read-only mode",
code: "CONJ00153E"
)
end

module Authorization
Expand Down
15 changes: 15 additions & 0 deletions config/initializers/read_only_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Rails.application.configure do
# Determines whether or not writable API endpoints are enabled.
#
# The `read_only_api` arguement is a boolean. By default, `read_only_api` is "Off".
# This means that any of the writable API endpoints will function as intended.
#
# A writable API endpoint is one whose controller method is decorated with the
# `@read_safe` decorator. When `read_only_api` is "On", such endpoints will return
# an HTTP 405 Method Not Allowed response code.
#
# TODO:
read_only_api = true
config.read_only_api = read_only_api # def enabled?() read_only_api end
end

0 comments on commit f32a4d3

Please sign in to comment.