Skip to content
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

Examples? such as a devise example #23

Open
TJM opened this issue Jun 2, 2015 · 14 comments
Open

Examples? such as a devise example #23

TJM opened this issue Jun 2, 2015 · 14 comments
Milestone

Comments

@TJM
Copy link

TJM commented Jun 2, 2015

I wondered if there should be an examples directory that had some different example deployments. It might be "handy" for new implementations? For example. We had an "existing" rails application that uses "devise" for user authentication / management. We just wanted to add the ability for it to be the IdP. It turns out that is super easy, once you have fought it long enough ;)

Devise Example

app/controllers/saml_idp_controller.rb

class SamlIdpController < SamlIdp::IdpController
  before_filter :authenticate_user!, except: [:show]

# override create and make sure to set both "GET" and "POST" requests to /saml/auth to #create
  def create
    if user_signed_in?
      @saml_response = idp_make_saml_response(current_user)
      render :template => "saml_idp/idp/saml_post", :layout => false
      return 
    else
      # it shouldn't be possible to get here, but lets render 403 just in case
      render :status => :forbidden
    end
  end

# NOT USED -- def idp_authenticate(email, password) -- NOT USED

  def idp_make_saml_response(found_user) # not using params intentionally
    encode_response found_user
  end
  private :idp_make_saml_response
end

config/routes.rb

(add the following)

# SAMLv2 IdP
  get '/saml/auth' => 'saml_idp#create'
  post '/saml/auth' => 'saml_idp#create'
  get '/saml/metadata' => 'saml_idp#show'

config/initializers/saml_idp.rb

Add this file per the README. Note that it does require customization.

  • You must set "base" and it should probably be something like base = Rails.configuration.x.saml_idp_base which should be set as config.x.saml_idp_base = https://www.example.com/ in your config/environments/${RAILS_ENV}.rb.
  • The SSL KEY should probably be in secrets.yaml (and not in version control).
  • The config.name_id_formats must be set (watch out, the example has a # before the =)
  • Also, for config.service_provider.persisted_metadata_getter, see Issue Errno::ENOENT (No such file or directory @ rb_sysopen - .../cache/saml/metadata/Influitive-AdvocateHub) #16 just in case that hasn't been fixed yet.
@jphenow
Copy link
Collaborator

jphenow commented Jun 2, 2015

I love this idea! Even just a Devise example would be a great start for a ton of people I would think.

If you want to submit a PR that adds this directory and outlines how to do this within one file or a set of files, that'd be great.

@TJM
Copy link
Author

TJM commented Jun 2, 2015

I am thinking a directory of markdown docs, sort of like above, provide a fairly simple way of sprinkling documentation and code together into a single file. I might add Prerequisites or something? The thing that hurt me the worst (besides being a fairly newb ruby guy) was the initializer. I had to go through a lot of stack traces to figure out what was going wrong. It kept trying to call ".persistent" against my User object, and I couldn't figure out why :). Anyhow, I will see if I can carve off another half hour or something to polish this up.

@jphenow
Copy link
Collaborator

jphenow commented Jun 2, 2015

That'd be Great, thanks a bunch for anything you can contribute!

@Yanchek99
Copy link

Would also be nice to provide examples on how to test this with rspec/minitest. Running in circles trying to write tests for the IDP controller.

@MatthewBartlett
Copy link

Did any of these examples ever materialise? I'm finding it difficult to understand the configuration requirements.

At the moment my service provider is never trying to get fresh metadata, and there is no persisted metadata. Validation of the request then fails due to missing acs_url. I've added a base, defined the service provider name and metadata URL, it just never calls refresh metadata.

Appreciate any help or examples!

-Matt

@Yanchek99
Copy link

Also note that the Devise Example above only works if using the SAML Http redirect protocol. If using the HTTP post method this does not work, as you will never be redirected back to the sp.

@jphenow jphenow added this to the 0.4 milestone Jun 7, 2016
@rayson1223
Copy link

@TJM : Did you solve the ".persistent" undefined method for the User model object in Devise?

@TJM
Copy link
Author

TJM commented Nov 22, 2016

@rayson1223 - I will admit that I am the "IT" guy, and I was just part of the project to help with the SAML stuff. I know "it works" for us, but use it at your own risk. The only place I see "persistent" in our initializer is:

  config.name_id.formats =
    {                         # All 2.0
      email_address: -> (principal) { principal.email },
      transient: -> (principal) { principal.id },
      persistent: -> (p) { p.id },
    }

There is also some stuff further down about metadata, but I think its unrelated.

@vipera
Copy link

vipera commented Dec 16, 2020

I've found an issue with this type of Devise usage. When you use:

before_action :authenticate_user!

To redirect incoming SAML auth requests to Devise's session controllers, you will easily exceed the cookie size limit if the SP is sending a signed authn request. For example, I'm using devise + omniauth-saml on the SP side with the following rather ordinary settings (Gitlab uses similar settings):

security: {
  authn_requests_signed: true,
  logout_requests_signed: true,
  logout_responses_signed: true,
  want_assertions_signed: true,
  metadata_signed: true,
  embed_sign: true,
  signature_method: XMLSecurity::Document::RSA_SHA256,
  digest_method: XMLSecurity::Document::SHA256,
}

If authn_requests_signed is enabled, then before redirecting to Devise's sign in page, the URL containing the SAMLRequest parameter will fail to be stored in the session for use as return URL. This will be too large to be persisted in a session cookie jar.

Since saml_idp required signed logout requests to support SP-initated SLO, I've found that you have to at least exclude the logout action from authentication:

before_action :authenticate_user!, except: %i[logout]

I've not yet found a solution for enabling signed authn requests apart from switching to another type of session storage on the IdP.

I assume the ideal thing would be to redirect around Devise's session controllers while always persisting the SAMLRequest in the querystring, then after logging in or signing up getting redirected back (this time with a principal yielded by Devise when calling current_*) everything would work. I don't know my way around Devise/Warden enough to know whether this is possible. I'm going to do some more digging.

@JohnKacz
Copy link

@vipera were you able to figure anything out. I've got the same issue I believe.

@vipera
Copy link

vipera commented Jan 11, 2022

@JohnKacz I have currently set authn_requests_signed to false in the SP configuration. This "fixes" the issue by shortening the SAMLRequest payload. My IdP is currently used only by internally developed SP applications, so I'm permitting unsigned requests from those sources.

Alternatively, you could look into using Memcached or Redis as the session store within the saml_idp application. Then you should not run into this problem as you can store more data in the session store. I understand that CookieStore has its benefits and that this might not be practical if you're not already using either for other caching.

So basically I didn't manage to get to the bottom of it, I worked around it. I didn't have the time to tackle it properly, but if anyone has any pointers I'd be glad to try and make it work with cookie-stored sessions.

@Zogoo
Copy link
Collaborator

Zogoo commented Jan 13, 2022

@JohnKacz, @vipera
I'm not sure why authn_requests_signed is affecting failure of the non authenticated SAML request. We need to do more investigation about this issue. If you guys could provide more information like logs or whatever to help to speed up the investigation that would be great.

About cookie store issue is cookie only allows to store 4kb but the SAML request is too big to store it. Instead of that you guys can store SP initiated SAML request URL (not request itself) for SAML request and let "devise" redirect back to SP url again after successfully logged into your IdP.

@mrobock
Copy link

mrobock commented Jan 26, 2022

I had the same issue and wasn't able to get devise to help so I modified the validate_saml_request before action and set the SAMLRequest to the session on post and then pulled it back out on get.

def validate_saml_request
      if request.get?
        params["SAMLRequest"] = session["SAMLRequest"]
      elsif request.post?
        session["SAMLRequest"] = params["SAMLRequest"]
        store_location_for("user", "#{request.base_url}/saml/auth") if current_user.blank?
      end

      super
    end

I'm on a forked branch of 0.9.0

@Zogoo
Copy link
Collaborator

Zogoo commented Feb 1, 2022

@mrobock your code has a hint. I would like to clarify one thing who also looking for some solution.
SAML has also specification GET request (not only POST), people who uses your way need to be aware of SP has only support POST request.
And I think you really don't need to override the method since you have full management of your own session controller, or application controller of a Rails app.

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

No branches or pull requests

9 participants