0.0
No commit activity in last 3 years
No release in over 3 years
This gem gives a developer a set of tools for securing access to their endpoints.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 0.4
~> 3.4

Runtime

< 5.0, >= 4.0
 Project Readme

Description

The Master Api Key gem allows you to easily integrate API access restrictions into your services. This gem will provide an API to create API Keys and revoke API access.

##API Groups##

The Master ApiKey Gem provides basic authorization with controller groups. With controller groups, you can separate your APIs into logical packages or products.

For example, you can have an AdminController and UserController under the "users" group or a MapsControllers, LocationsController, TrafficController under the "maps" group. This allows you to only give access to related controllers to a client easily.

##Read/Write Controller Protection##

All controllers automatically get read/write protection based off of the ApiKey being used. ApiKeys have read_access and write_access boolean fields that grant authorization to different controller actions. Read access grants the user authorization to use the index and show actions. While write access grants the user authorization to use the create, new, update, destroy, and edit actions.

Using Master Api Key

Setup

First, include the gem into your project's GemFile

gem 'master_api_key', '~> 2.0'

Then, install and run the migrations

$ rake master_api_key:install:migrations
$ rake db:migrate

Next, add the following line to the seed file for integrating MasterApiKey seed data.

MasterApiKey::Engine.load_seed

Finally, setup the MasterApiKey Engine routes.

  • Go to the routes.rb file in your application
  • Add the following line.
mount MasterApiKey::Engine => '/security'

You can replace the mounted path from 'security' to any sub path you'd like. In addition, running a db migration should automatically generate a master_key APIKey for you.

For more info on rails engines, please go to the following link: Rails Engine Tutorial

Managing the API Keys

Here we'll show you how to create, update, and revoke api keys from clients. Ensure that you keep track of who you've given access to the key. That way if you ever need to revoke the key, you'll know who to contact to prevent outages for your clients. A master_key api token is required for all endpoints that add, delete, or modify the APIKeys. The key should have been generated by either seeding the db or running a db migration.

IMPORTANT: Do not reuse this api key for other controllers and no not share this key outside of trusted users. This key will grant its users the ability to generate any api key they want, which is equivalent to giving them complete access to your API and control who accesses it.

For a detailed description of the protocol, read the PROTOCOL.md file

##Using the API## In order to use the api, you'll need to know your service's domain and a master api token for authentication. If you are running the rails app locally with the default settings and mounted the engine to the '/security' path, then your service domain for the master_api_key engine will be

http://localhost:3000/security

Finally, you'll need a master api token with read write access to use the api. A key should have been generated for you when you installed the engine. It will be an ApiKey record with a group name 'master_key'. If one does not exist then you can create a new record by doing the following in the rails console.

$ rails c
$ MasterApiKey::ApiKey.create(group:'master_key', read_access:true, write_access:true) 

Now that you have an access token and the service domain, you can now use the following API endpoints.

##Granting API Access### This is an example of creating a new 'administration' api key that has read access but not write access.

$ curl -v -X POST <service_domain>/api_keys \
    -H "X-API-TOKEN: <master_key_api_token>" \
    -H "Content-Type: application/json" \
    --data '{"group":"administration","authorizations":{"read_access":true,"write_access":false}}'   

###Changing Read/Write Access to API### This is an example of updating an existing api key to have both read and write access. You will need to replace <api_key_token_to_modify> with the api token of the target api key record.

$ curl -v -X PATCH <service_domain>/api_keys \
    -H "X-API-TOKEN: <master_key_api_token>" \
    -H "Content-Type: application/json" \
    --data '{"api_token":"<api_key_token_to_modify>","authorizations":{"read_access":true,"write_access":true}}'

###Revoking API Access### This is an example of deleting an existing api key to have both read and write access. You will need to replace <api_key_token_to_delete> with the api token of the api key to delete.

$ curl -v -X DELETE <service_domain>/security/api_keys \
    -H "X-API-TOKEN: <master_key_api_token>" \
    -H "Content-Type: application/json" \
    --data '{"api_token":"<api_key_token_to_delete>"}' 

Restricting Access to your APIs

Clients using your APIs

When restricting access to your APIs, a new header field in your http request will be required. The header key/value is:

X-API-TOKEN: <api_token>

If the access token is within the api_keys table and has been authorized to access the controller, then the user will be allowed to access you endpoint.

However, if the access token is not within the api_keys table then the user is considered not authenticated.

Error Code Http Code Name
401 Unauthorized

If the access token was authenticated but was not authorized to use the endpoint, then the following error code will be returned:

Error Code Http Code Name
403 Forbidden

Integrating Master Api Key into your Controllers

The core module of this project is "MasterApiKey::ApiGatekeeper", which is automatically mixed into all controllers. For each controller, you'll need to assign it a group at the top of the controller. Below is an example of assigning controller to API Groups.

class AdminController < ApplicationController

    #define the group that the controller is apart of. 
    #Only ApiKeys with this name in the group column will have access to the controller.
    belongs_to_api_group :admin

Now that you've defined the group, you'll need to restrict access is by either adding a filter to the top of the controller or explicitly calling the method to restrict access.

class AdminController < ApplicationController

    #define the group that the controller is apart of. 
    #Only ApiKeys with this name in the group column will have access to the controller.
    belongs_to_api_group :admin

    #Restricting access by filters
    before_action :authorize_action, only: [:create]
    
    def create
        #Code for creating admins.
        head :created
    end

    #Restricting access by explicitly calling method.
    #If the call is authorized then the code block passed in will be executed.
    def index
        authorize_action do
            #Code for accessing admins
            head :ok
        end
    end

If you want to override the default behavior when a request is considered not authenticated or unauthorized, you can override the following methods from ApiGateKeeper in your calling controller.

    #Called when a request was not authenticated.
    def on_authentication_failure
      head(:unauthorized)
    end

    #Called when a request is not authorized
    def on_forbidden_request
      head(:forbidden)
    end

Extending Authorization beyond API Groups

Adding additional ways to authorize users is easy with the MasterApiKey gem. The main tasks you'll need to do is the following:

  • Add a new column to the ApiKey table representing the new authorization factor.
  • Implement new authorization methods in the necessary controllers.
  • Assign required authorization methods to the necessary controller endpoints.

Below is an example of an AdminController using the multi authorization factor feature. The ApiKey model now has two new columns added to it, the company and level column. An endpoint user will have the ability to create new users if the new user has the same company as the ApiKey being used, and if the user has level access that is equal to or less than the level of the ApiKey being used.

class AdminController < ApplicationController 
    #define the group that the controller is apart of. 
    #Only ApiKeys with this group will have access to the controller.
    belongs_to_api_group :admin
    
    #Restricting access by filters. You can pass in a single authorizer or an array of authorizers.
    authorize_with authorizers:[:company_authorizer, :level_authorizer], only: [:create]

    #Will execute if company_authorizer and level_authorizer passes.
    def create
        @user = User.create!(company_access: company_param, level_authorizer: level_param)
        render json: { record: @user}, status: :created
    end

    #Restricting access by explicitly calling method. You can pass in a single authorizers
    #or an array of authorizers. In this case the code block will execute if company_authorizer passes.
    def index
        authorize_action(:company_authorizer) do
            respond_with User.find_by(company_access: company_param, level_authorizer: level_param)
        end
    end

    def company_authorizer
        @api_key.company_access == company_param
    end

    def level_authorizer
        @api_key.level_required >= level_param
    end

    private 
    
    def company_param
        params.require(:company)
    end
    
    def level_param
        params.require(:level).to_i
    end
end

Building the Gem

Use the build gem script if you want a simple way to setup your workstation for development. The script goes through several steps before verifying the build.

  1. The RSpec unit and integration tests are run against master_api_key
  2. The gem is built and installed in the current ruby environment

Once all tests are green, then it should be safe to push the gem to the repository.

The basic usage for the build script is the following:

./build_gem.sh

During development you will need to update the gems, especially when you update the version file. The option -u will update all gems including master_api_key

./build_gem.sh -u

For additional help use the -h option

Testing

To explicitly test this gem, you'll need to run the following command:

rake test