Setting up SAML callback in Rails using Devise and OmniAuth-SAML
Asked Answered
M

1

12

EDIT: Additional info and condensed question near the bottom ;)

I'm setting up integration between a small app I'm making and an identity provider using SAML2.0.

In general, I've been following the instructions on the Devise page, and then on the Omniauth-SAML docs.

The issue seems currently to be that no callback path has been generated. Here's the relevant code bits below; feel free to request additional information.

app/models/user.rb

class User < ActiveRecord::Base
  devise :omniauthable, omniauth_providers: [:saml]

  def from_omniauth(auth_hash)
    puts auth_hash
    new  # Stub for now I guess?
  end
end

app/controllers/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def saml
    @user = User.from_omniauth request.env['omniauth.auth']
    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: 'SAML') if is_navicational_format?
    else
      session['devise.saml_data'] = request.env['omniauth.auth']
      redirect_to permission_denied # this isn't going to work lol
    end
  end

  def failure
    redirect_to root_path
  end
end

A truncated & sanitized chunk from config/initializers/devise.rb

  config.omniauth :saml,
                  idp_cert_fingerprint: 'aa:bb:cc...', # an actual fingerprint here 
                  idp_sso_target_url: 'https://sso.bla.thing.com/fss/idp/startSSO.ping?PartnerSpId=SAML_UID',
                  issuer: 'myidpname',  # Not actually sure what this should be
                  idp_entity_id: 'thingfssdp',
                  assertion_consumer_service_url: 'https://myapp.com/auth/saml/callback',
                  name_identifier_format: 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress'

According to the docs here and here, adding more than the above (that is, putting the additional requirements into config/initializers/omniauth.rb) would be incorrect.

My controllers have before_action :authenticate_user! as their first line.

config/routes.rb has the following line at the top:

Rails.application.routes.draw do
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }

But it's possibly important to note that I haven't manually added any logic for callback handling yet

Attempting to visit my app yields an ERR_TOO_MANY_REDIRECTS; quite a few 302s all apparently pointing back to itself. Doing a GET /auth/saml/callback yields the following helpful error (not sure how or why /users/ gets prepended there; do I need to request a change in ACS URL or is this something I have control of?):

rails_error_message

Any insight or assistance would be much appreciated.

EDIT: It looks as though the issue is that user_saml_omniauth_authorize_path is being set to /users/auth/saml -- and not directly the IDP signin page. I have no explicit controller for this route, but apparently requiring signin for OTHER controllers means I am requiring signin for this one. The end result is that, as some have suggested, we get an infinite redirect loop.

Millennium answered 25/9, 2017 at 21:54 Comment(1)
Use the sso gem.Lunarian
A
5

About the redirect loop: Since you have before_action :authenticate_user! it leads any unauthenticated request to users sign in page. My guess is that you also have the same callback on your sign in page. Thus on every redirect to /sign_in rails puts it through this authenticate_user! and redirects it again since user is not authenticated. For it to work correctly you have to skip_before_action :authenticate_user! in the controller where you have the sign on (SessionsController I presume).

As for your second question - the correct authorization route. the answer is in the screenshot you presented, below the error. You can see there that the correct path is /users/auth/saml and users/auth/saml/callback

UPDATE: users gets prepended by default from Devise (using your devisable model name)

Aggiornamento answered 28/9, 2017 at 18:18 Comment(2)
The signin should be on the identity management server though, no?Millennium
That is - I'd expect the redirect to be to the idp_sso_target_url defined in devise.rb's config.omniauth hash.Millennium

© 2022 - 2024 — McMap. All rights reserved.