Skip to content

Alternative authentication approaches #158

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
NobodysNightmare opened this issue May 23, 2025 · 1 comment
Open

Alternative authentication approaches #158

NobodysNightmare opened this issue May 23, 2025 · 1 comment

Comments

@NobodysNightmare
Copy link

NobodysNightmare commented May 23, 2025

Hey there,

we are currently in the process of integrating Scimitar into our application. One thing that I am currently trying to work on is the authentication.

tl; dr: Should it be possible to disable authentication in scimitar entirely, so that the application can take care of authentication itself?

Long form:

How I understand Scimitar's approach to authentication

First of all, let me quickly outline how I understand authentication to work in scimitar. Maybe I am simply overlooking something. I am aware of the ability to pass a token_authenticator in an initializer:

Scimitar.engine_configuration = Scimitar::EngineConfiguration.new(
  token_authenticator: Proc.new do |token, _options|
    # simple example that one should never use in production for so many reasons
    token == "secret"
  end
)

In this approach scimitar will:

  • always return a 401 if no Bearer token was present
  • if a Bearer token was present it will be passed to the token authenticator
    • if the authenticator returns true, the request passes
    • if the authenticator returns false, a 401 is returned

I think this is a very pragmatic implementation that covers a lot of basic authentication needs.

Limitations

However, I also see some limitations:

  • It's limited to Bearer authentication when the SCIM specs don't pick any specific authentication means
    • among others the spec uses mutual TLS and Basic authentication as an example
  • It doesn't have built-in capabilities to differentiate SCIM clients (e.g. two different clients that I want to manage different user pools)
  • It can't be disabled
    • This means even if I wanted to take care of authentication myself (e.g. through a rack middleware), scimitar would still require the presence of a Bearer token, even if I wanted to use different means of authentication

In our specific use case, we'll practically only be using Bearer tokens, so that's not too bad, but authentication of all other API requests is done through Warden, so preferably we can use the same authentication code for our SCIM routes that we already use for other APIs. That also includes associating the requests being made to an identity (let's say user), so that we have basic auditing capabilities (e.g. "User was created by SCIM Client A").

The best approach that currently comes to my mind is to implement the token authenticator as ->(*) { true } and then implement authentication as either a rack middleware or possibly by using application_controller_mixin. This would allow us to use all Bearer-token based authentication methods inside the custom authentication layer. If we wanted to support a different auth method though, we couldn't do it.

Thus the main limitation that I currently seem to face is the inability to disable authentication entirely and at the same time I wish that there was a way to do that that's endorsed by the docs. Because right now my proposal outlined above feels a lot like working against scimitar, which is usually a bad idea with any given gem.

I guess it would also be possible to extend scimitar with more authenticators, but on the other hand it feels like a lot of work being done in this gem, that other gems already solved. That's why I am leaning into the "let's disable it" direction.

P.S.: Thanks for making and maintaining this gem. <3

@NobodysNightmare
Copy link
Author

This is a current proof of concept, showing how I'd now integrate warden-based authentication:

# config/initializers/scimitar.rb
Scimitar.engine_configuration = Scimitar::EngineConfiguration.new(application_controller_mixin: ScimV2::ScimControllerMixins)

# app/controllers/scim_controller_mixins.rb
module ScimControllerMixins
  def self.included(base)
    base.prepend(Overwrites)
  end

  module Overwrites
    # Overwriting existing authenticate method of scimitar has two effects:
    # * default behaviour of failing authentication when no token was passed is gone
    # * we have access to the request environment and thus can integrate with warden as intended
    def authenticate
      warden = request.env["warden"]
      user = warden.authenticate! scope: :scim_v2

      handle_scim_error(Scimitar::AuthenticationError.new) if !user.allowed_to_wield_scimitar?
    end
  end
end

I am quite happy with the amount of modification necessary to Scimitar. Since this is effectively still a monkey-patch, not changing anything would be best, but it definitely feels handleable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant