1

OmniAuth 2.0 requires that requests to the IdP authentication server be POSTs instead of GETs.

What this means for most users is that on their login page, where they have links to OmniAuth providers like Facebook and Google, they change the method on those links or buttons to be POSTs. No problem.

But for one of my apps, we want it so that if authentication fails (like coming to the app and you need to login still) we redirect in a custom Devise::Failure App to the IdP authentication server. This means you come to our app with a GET request, of course, and we see you're not authenticated so we redirect you to the IdP. But we can't do that anymore because it has to be a POST. The only way I can see around it is I have to remove our custom Failure App so that you're redirected to the normal login page where our link to the IdP is.

Any ideas on how I can keep our current redirect straight to the IdP logic?

1 Answers1

0

The answer is you can't do that with OmniAuth 2.0. You're not going to be able to redirect your DeviseFailureApp to the IdP's login page because that's going to be a GET.

Instead, have your Failure App return a redirect_url to a new controller action you can add in your SessionsController. I called it saml_redirect. Add a route for it:

  devise_scope :user do
    match 'saml_redirect' => 'sessions#saml_redirect', as: :saml_redirect, via: [:get]
  end

That controller action doesn't really have to do anything but render an .html.erb. In that html.erb, simply have a hidden button which will do the POST to the IdP's login page, same as if you had a button to Facebook and a user clicked it. Then when the page loads, you automatically click the button. Here's the full code of the html.erb:

<div class="info_box">You are being redirected to your corporate network sign-in page</div>
<%= button_to "Login with #{ENV['saml_idp_name']}", user_saml_omniauth_authorize_path(provider: :saml), method: :post, id: 'saml_button', style: 'display: none' %>
<script>
  function ready(callbackFunction){
    if(document.readyState != 'loading')
      callbackFunction();
    else
      document.addEventListener("DOMContentLoaded", callbackFunction);
  }
  ready(() => {
    document.getElementById('saml_button').click();
  })
</script>

So no rocket science here. The name of the game is if you want a user to automatically go to the Identity Provider's page when they need to login instead of forcing them to click a button from your login page, then you simply automate the clicking of the button.