SkillAgentSearch skills...

Scimitar

A SCIM v2 API endpoint implementation

Install / Use

/learn @pond/Scimitar
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Scimitar

Gem Version Build Status License

A SCIM v2 API endpoint implementation for Ruby On Rails.

For a list of changes and information on major version upgrades, please see CHANGELOG.md.

Overview

System for Cross-domain Identity Management (SCIM) is a protocol that helps systems synchronise user data between different business systems. A service provider hosts a SCIM API endpoint implementation and the Scimitar gem is used to help quickly build this implementation. One or more enterprise subscribers use these APIs to let that service know about changes in the enterprise's user (employee) list.

In the context of the names used by the SCIM standard, the service that is provided is some kind of software-as-a-service solution that the enterprise subscriber uses to assist with their day to day business. The enterprise maintains its user (employee) list via whatever means it wants, but includes SCIM support so that any third party services it uses can be kept up to date with adds, removals or changes to employee data.

Installation

Install using:

gem install scimitar

In your Gemfile:

gem 'scimitar', '~> 2.0'

Scimitar uses semantic versioning so you can be confident that patch and minor version updates for features, bug fixes and/or security patches will not break your application.

Heritage

Scimitar borrows heavily - to the point of cut-and-paste - from:

  • ScimEngine for the Rails controllers and resource-agnostic subclassing approach that makes supporting User and/or Group, along with custom resource types if you need them, quite easy.
  • ScimRails for the bearer token support, 'index' actions and filter support.
  • SCIM Query Filter Parser for advanced filter handling.

All three are provided under the MIT license. Scimitar is too.

Usage

Scimitar is best used with Rails and ActiveRecord, but it can be used with other persistence back-ends too - you just have to do more of the work in controllers using Scimitar's lower level controller subclasses, rather than relying on Scimitar's higher level ActiveRecord abstractions.

Some aspects of configuration are handled via a config/initializers/scimitar.rb file. It is strongly recommended that you wrap Scimitar configuration with Rails.application.config.to_prepare do... so that any changes you make to configuration during local development are reflected via auto-reload, rather than requiring a server restart:

Rails.application.config.to_prepare do
  Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
    # ...see subsections below for configuration options...
  })
end

In general, Scimitar's own development and tests assume this approach. If you choose to put the configuration directly into an initializer file without the to_prepare wrapper, you will be at a slightly higher risk of tripping over unrecognised Scimitar bugs; please make sure that your own application test coverage is reasonably comprehensive.

Authentication

You can define a token-based authenticator, a basic username-password authenticator or a custom authenticator in the engine configuration section documented in the sample file and examples of these are given in the sub-sections below. In all cases, it boils down to a Proc that you define which is invoked for every handled request. Your Proc code executes as if it were an instance method of an ApplicationController subclass which is handling a before_action callback in the normal Rails fashion, so it has full access to all the usual Rails objects such as request and response.

Please take note of the Security section later for additional information related to authorisation, as well as other security considerations.

Token-based

The Proc shown below must evaluate to true or false. The way you do that is up to you; in the examples below, code within the Proc.new block is just for illustration.

Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
  token_authenticator: Proc.new do | token, options |

    # This is where you'd write the code to validate `token`. The means by
    # which your application issues tokens to SCIM clients, or validates them,
    # is outside the scope of the gem. The required mechanisms vary by client.
    # More on this can be found in the 'Security' section later.
    #
    SomeLibraryModule.validate_access_token(token)

  end
})

Scimitar returns either a 401 error if your block evaluated to false, else consider the request authenticated and set HTTP header WWW-Authenticate to a value of **Bearer(( in the response per RFC 7644.

Scimitar neither enforces nor presumes any kind of encoding for bearer tokens. You can use anything you like, including encoding/encrypting JWTs if you so wish - https://rubygems.org/gems/jwt may be useful. The way in which a client might integrate with your SCIM service varies by client and you will have to check documentation to see how a token gets conveyed to that client in the first place (e.g. a full OAuth flow with your application, or just a static token generated in some UI which an administrator copies and pastes into their client's SCIM configuration UI).

Username and password-based

For username/passwords, use something like this (again, the code inside the Proc is just an illustration):

Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
  basic_authenticator: Proc.new do | username, password |

    User.find_by_username(username)&.valid_password?(password) || false

  end
})

Scimitar returns either a 401 error if your block evaluated to false, else consider the request authenticated and set HTTP header WWW-Authenticate to a value of Basic in the response per RFC 7644.

Custom

To fully take over authentication, you can supply a custom authenticator. If the authentication mechanism you're using does not already do so, you become responsible for setting an appropriate value for the WWW-Authenticate header in your response to indicate the appropriate authentication type. Scimitar won't do that itself, since it doesn't know what approach your custom code is using.

Here's an example where Warden is being used for authentication, with Warden storing the authenticated information under a scope of scim_v2 in this case, so the user could be later read back using warden.user(:scim_v2) (though you can use any Warden scope name you want, of course, or not use any authentication scope at all).

Scimitar.engine_configuration = Scimitar::EngineConfiguration.new({
  custom_authenticator: Proc.new do

    # In this example we catch the Warden 'throw' for failed authentication, as
    # well as allowing Warden to successfully find an *authenticated* user, but
    # then fail *authorisation* based on some hypothetical permissions check.
    #
    catch(:warden) do
      response.headers['WWW-Authenticate'] = '...something...'

      warden = request.env["warden"]
      user   = warden.authenticate!(scope: :scim_v2)
      user.can_use_scim? # (just a hypothetical User model method that might check some permissions)
    end or false

  end
})

If you only wanted Warden authentication and not further authorisation, that block becomes even simpler:

catch(:warden) do
  response.headers['WWW-Authenticate'] = '...something...'

  warden = request.env["warden"]
  warden.authenticate!(scope: :scim_v2) # This'll either throw (caught -> block 'nil' -> "or false" -> false), else continue
  true # If we reach this line, Warden didn't throw, so authentication was successful
end or false

Scimitar handles false responses for you, rendering a 401 response, but you can override that for even more customised behaviour if you want. Should your Proc have already responded, either by calling handle_scim_error and passing it an instance of an Exception - e.g. the Scimitar::ErrorResponse subclass of Exception initialised with status: <HTTP status code>, detail: "error message") - or by any other means, then Scimitar won't render its standard 401 at all and your code becomes responsible for the returned JSON payload.

Routes

For each resource you support, add these lines to your routes.rb:

namespace :scim_v2 do
  mount Scimitar::Engine, at: '/'

  get    'Users',     to: 'users#index'
  get    'Users/:id', to: 'users#show'
  post   'Users',     to: 'users#create'
  put    'Users/:id', to: 'users#replace'
  patch  'Users/:id', to: 'users#update'
  delete 'Users/:id', to: 'users#destroy'
end

All routes then will be available at https://.../scim_v2/... via controllers you write in app/controllers/scim_v2/..., e.g. app/controllers/scim_v2/users_controller.rb. More on controllers later.

URL helpers

Internally Scimitar always invokes URL helpers in the controller layer. I.e. any variable path pa

View on GitHub
GitHub Stars85
CategoryDevelopment
Updated1mo ago
Forks47

Languages

Ruby

Security Score

95/100

Audited on Mar 5, 2026

No findings