ppd
ppd

Reputation: 69

Omniauth-saml in Rails: Route not found error for /auth/saml/metadata

I have a routing question in Rails (3.2.1).

I am using omniauth-saml for authentication (https://github.com/PracticallyGreen/omniauth-saml). The doc says:

"The service provider metadata used to ease configuration of the SAML SP in the IdP can be retrieved from http://example.com/auth/saml/metadata. Send this URL to the administrator of the IdP."

When I go to myserver.com/auth/saml/metadata, I get a routing error (No route matches). The only relevant route I have in routes.rb is /auth/:provider/callback. What route do I need to add to be able to access the metadata URL?

The authentication itself is working as expected. I am only having problems with the metadata.

Thanks a lot!

Upvotes: 1

Views: 1390

Answers (1)

Kevin Kohrt
Kevin Kohrt

Reputation: 226

You can generate a metadata route by adding the following matcher to routes.rb*:

devise_scope :user do
  match "/users/auth/:action/metadata",
    constraints: { action: /saml/ },
    to: "omniauth_callbacks",
    as: :user_omniauth_metadata,
    via: [:get, :post]
end

Resulting in the following route (sans "(.format)"):

user_omniauth_metadata  GET|POST /users/auth/:action/metadata omniauth_callbacks#(?-mix:saml)

This is in addition to the standard omniauth routes:

user_omniauth_authorize GET|POST /users/auth/:provider        omniauth_callbacks#passthru {:provider=>/saml/}
user_omniauth_callback  GET|POST /users/auth/:action/callback omniauth_callbacks#(?-mix:saml)

which results from:

devise_for :users, controllers: { omniauth_callbacks: "omniauth_callbacks" }

Note: I am doing this with devise in the :user scope, but outside the scope it would look more like:

match( "/auth/:action/metadata",
  constraints: { action: /saml/ },
  to: "omniauth_callbacks",
  as: :omniauth_metadata,
  via: [:get, :post]
)

You also need to define a callback for "other_phase"; e.g. add something like the following to your SAML strategy

module OmniAuth
  module Strategies
    class Saml

      include OmniAuth::Strategy

      def other_phase
        if on_path?("#{request_path}/metadata")
          # omniauth does not set the strategy on the "other_phase"
          @env['omniauth.strategy'] ||= self
          setup_phase

          response = OneLogin::RubySaml::Metadata.new
          settings = OneLogin::RubySaml::Settings.new # set whatever params you want on this guy
          Rack::Response.new(response.generate(settings), 200,
                             { "Content-Type" => "application/xml" }).finish
        else
          call_app!
        end
      end
    end
  end
end

Upvotes: 1

Related Questions