-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
6dca425
commit b6899d6
Showing
21 changed files
with
192 additions
and
68 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
class Api::SiteAdmin::BoxesController < Api::SiteAdminController | ||
|
||
def create | ||
@box = @tenant.boxes.new(box_params) | ||
return if @box.save | ||
|
||
render :error, status: :unprocessable_entity | ||
log_api_call(:create_tenant_box_api_called) | ||
end | ||
|
||
private | ||
|
||
def box_params | ||
params.require(:box).permit(:id, :name, :short_name, :uri, :color, :api_connection_id) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class Api::SiteAdminController < ApiController | ||
private | ||
|
||
def authenticate_user | ||
ApiEnvironment.site_admin_token_authenticator.verify_token(authenticity_token) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
class Api::Tenant::EmptyController < Api::TenantController | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class Api::TenantController < ApiController | ||
private | ||
|
||
def authenticate_user | ||
ApiEnvironment.tenant_token_authenticator.verify_token(authenticity_token) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
class ApiController < ActionController::API | ||
include AuditableApiEvents | ||
|
||
before_action :authenticate_user | ||
around_action :wrap_in_request_logger | ||
|
||
rescue_from JWT::DecodeError do |error| | ||
if error.message == 'Nil JSON web token' | ||
render_bad_request(:no_credentials) | ||
else | ||
key = error.message == 'obo' ? :obo : :credentials | ||
render_unauthorized(key) | ||
end | ||
end | ||
|
||
rescue_from RestClient::Exceptions::Timeout, with: :render_request_timeout | ||
rescue_from ActiveRecord::RecordNotFound, with: :render_not_found | ||
rescue_from ActionController::ParameterMissing, with: :render_unprocessable_entity | ||
|
||
private | ||
|
||
def authenticity_token | ||
(ActionController::HttpAuthentication::Token.token_and_options(request)&.first || params[:token])&.squish.presence | ||
end | ||
|
||
def set_tenant | ||
@tenant = Tenant.find(params.require(:id)) | ||
end | ||
|
||
|
||
def raise_with_resource_details(error = $!, resource, id, **options) | ||
error.resource = [resource, options.merge(id: id)] if error.respond_to?(:resource=) | ||
raise error | ||
end | ||
|
||
def log_request(error = nil) | ||
# TODO save the log somewhere | ||
end | ||
|
||
def wrap_in_request_logger | ||
yield | ||
rescue Error => error | ||
log_request(error) and raise(error) | ||
else | ||
log_request | ||
end | ||
|
||
|
||
def render_bad_request(key, **options) | ||
render status: :bad_request, json: { message: "Bad request" } | ||
end | ||
|
||
def render_unauthorized(key = :credentials) | ||
self.headers['WWW-Authenticate'] = 'Token realm="API"' | ||
render status: :unauthorized, json: { message: "Unauthorized" } | ||
end | ||
|
||
def render_unpermitted_param(**options) | ||
render status: :unprocessable_entity, json: { message: "Unprocessable entity" } | ||
end | ||
|
||
def render_forbidden_no_key | ||
render status: :forbidden, json: { message: "Forbidden" } | ||
end | ||
|
||
def render_forbidden(key, **options) | ||
render status: :forbidden, json: { message: "Forbidden" } | ||
end | ||
|
||
def render_not_found(key, **options) | ||
render status: :not_found, json: { message: "Not found" } | ||
end | ||
|
||
def render_request_timeout | ||
render status: :request_timeout, json: { message: "request timeout" } | ||
end | ||
|
||
def render_too_many_requests | ||
render status: :too_many_requests, json: { message: "Too many requests" } | ||
end | ||
|
||
def render_internal_server_error | ||
render status: :internal_server_error, json: { message: "Internal server error" } | ||
end | ||
|
||
def render_service_unavailable_error | ||
render status: :service_unavailable, json: { message: "Service unavailable" } | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
module ApiEnvironment | ||
extend self | ||
|
||
def tenant_token_authenticator | ||
@tenant_token_authenticator ||= ApiTokenAuthenticator.new( | ||
public_key_reader: API_TENANT_PUBLIC_KEY_READER, | ||
return_handler: API_TENANT_BY_IDENTITY_FINDER, | ||
) | ||
end | ||
|
||
def site_admin_token_authenticator | ||
@site_admin_token_authenticator ||= ApiTokenAuthenticator.new( | ||
public_key_reader: API_SITE_ADMIN_PUBLIC_KEY_READER, | ||
return_handler: -> (sub) { 0 }, | ||
) | ||
end | ||
|
||
|
||
API_TENANT_PUBLIC_KEY_READER = -> (sub) { OpenSSL::PKey::RSA.new(API_TENANT_BY_IDENTITY_FINDER.call(sub).api_token_public_key) } | ||
API_TENANT_BY_IDENTITY_FINDER = -> (sub) { Tenant.feature_enable(:api).find_by!(tenant_id: sub) } | ||
|
||
API_SITE_ADMIN_PUBLIC_KEY_READER = -> (sub) { OpenSSL::PKey::RSA.new(ENV.fetch('SITE_ADMIN_API_PUBLIC_KEY')) } | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
class ApiTokenAuthenticator | ||
MAX_EXP_IN = 120.minutes | ||
JTI_PATTERN = /\A[0-9a-z\-_]{32,256}\z/i | ||
|
||
def initialize(public_key_reader:, return_handler:) | ||
@public_key_reader = public_key_reader | ||
@return_handler = return_handler | ||
end | ||
|
||
def verify_token(token) | ||
options = { | ||
algorithm: 'RS256', | ||
verify_jti: -> (jti) { jti =~ JTI_PATTERN }, | ||
} | ||
|
||
key_finder = -> (_, payload) do | ||
@public_key_reader.call(payload['sub']) | ||
rescue | ||
raise JWT::InvalidSubError | ||
end | ||
|
||
payload, _ = JWT.decode(token, nil, true, options, &key_finder) | ||
sub, exp, jti = payload['sub'], payload['exp'], payload['jti'] | ||
|
||
raise JWT::ExpiredSignature unless exp.is_a?(Integer) | ||
raise JWT::InvalidPayload if exp > (Time.now + MAX_EXP_IN).to_i | ||
|
||
@return_handler.call(sub) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters