0.0
No release in over 3 years
Low commit activity in last 3 years
A declarative authorization Rack middleware that supports custom authorization logic on a per-resource basis
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

chronos_authz

A declarative authorization Rack middleware that supports custom authorization logic on a per-resource basis

Usage sample for Rails

1. Install the gem

gem 'chronos_authz'

2. Configure the ACL config/my_acl.yml

An incoming request's http method and path will be checked against the ACL file's records for a match. At minimum, you MUST configure the path of the resource in an ACL record and SHOULD configure the http_method. If the http_method isn't configured, http method checking will not be done. You can define any other configuration here per resource as needed (ex. :permissions is a custom configuration and is defined here as this will be used in the custom authorization rule.

manage_accounts:
  path: "/accounts/.*" # regex pattern
  http_method:         # if array is used, this would work as an OR operation: checking if the incoming http request's method matches ANY of the configured http_method
    - GET
    - put
  permissions:
    - VIEW_ACCOUNTS
    - UPDATE_ACCOUNTS

create_users:
  path: "/users"
  http_method: POST
  permissions:
    - CREATE_USERS
    
update_users:
  path: "/users/.*"
  http_method: PUT
  permissions:
    - UPDATE_USERS
  # rule: AnotherCustomRule # Use a different rule for this ACL record

2. Create an authorization rule initializers/MyCustomRule.rb

An authorization rule MUST implement the request_authorized? method. The rule has an access to the ff. instance variables:

  1. @request - Rack::Request for the incoming HTTP request
  2. @acl_record - ChronosAuthz::ACL::Record from the ACL yml that matches the incoming request's http method and path. Custom configuration in the ACL yaml will be accessible from this object. ex. @acl_record.permissions
class MyCustomRule < ChronosAuthz::Rule
  
  # Must return a boolean to check
  def request_authorized?
    (@acl_record.permissions - user_claims).blank?
  end
  
  # Optional. Implement how claims are retrieved for a given user. Normally claims could be retrieved using cookies,
  # JWT/id_token decoded from the request header, API calls, or a database query. Any value returned here will be available to the ChronosAuthz::User.claims helper module as well.
  def user_claims
    # SAMPLE ONLY! In this sample configuration, only the user with the access token '1d1234913em23' would only be able to successfully send a POST request to /users. Access token 'm123493429304' bearer could both create and update a User.
    access_tokens = {
      "1d1234913em23" => ["CREATE_USERS"],
      "m123493429304" => ["CREATE_USERS", "UPDATE_USERS", "SomeOtherClaimInOtherFormat", "any-format-should-work-claim"]
    }
    
    access_token_from_request = @request.get_header("HTTP_AUTHORIZATION").gsub("Bearer ")
    return (access_tokens[access_token_from_request] || [])
  end
  
  # Optional. Error response when authorization fails
  def json_error
    return {error: "User not authorized."}
  end
end

4. Use the middleware

Rails.application.config.middleware.use ChronosAuthz::Authorizer do |config|
  # Required. Default authorization rule to use
  config.default_rule = MyCustomRule
  
  # Optional. Default is false. If set to true, the ACL is treated as a whitelist of resource paths: authorization would return a 403 error if no ACL Record has been configured for a given resource path. If set to false, authorization check will only be done to the resources configured in the ACL.
  config.strict_mode = true
  
  # Optional. Configure the default error page to render when authorization fails 
  config.error_page = "public/403.html"
  
  # Optional. Default behavior will look for 'config/authorizer_acl.yml'. Configure which ACL yml to use
  config.acl_yaml = "config/my_acl.yml"
end

Helpers

Include the helper module ChronosAuthz::User as needed to have access to the current user's claims via the .claims method. example:

class User < ActiveRecord
  include ChronosAuthz::User
end

With this helper included in your User model and assuming you are using Devise or any other AuthN solution, you may do the ff.:

current_user.claims
=> ["CREATE_USERS"]

If the return value of user_claims method in your implementation is a hash:

current_user.claims
=> {permissions: ["CREATE_USERS"], email: "someemail@yourdomain.com"}

current_user.claim[:email]
=> someemail@yourdomain.com