-
Notifications
You must be signed in to change notification settings - Fork 192
Rails_Integration
gem 'saml_idp' get '/saml/metadata' => 'saml_idp#show'
get '/saml/auth' => 'saml_idp#new'
post '/saml/auth' => 'saml_idp#create'
match '/saml/logout' => 'saml_idp#logout', via: [:get, :post, :delete]The following example only shows the required methods you need to define in your controller. If you are a Devise user, please properly use Devise methods for the authentication of your users.
Note: For Devise user, please be aware that the SAML request could be more than 4Kb if you are using cookie for your session storage.
You might want to use Redis for your session storage or override Devise function store_location_for to store SAML request to different places.
class SamlIdpController < ApplicationController
include SamlIdp::Controller
protect_from_forgery
before_action :validate_saml_request, only: [:new, :create, :logout]
def new
render template: "saml_idp/idp/new"
end
def show
render xml: SamlIdp.metadata.signed
end
def create
unless params[:email].blank? && params[:password].blank?
person = idp_authenticate(params[:email], params[:password])
if person.nil?
@saml_idp_fail_msg = "Incorrect email or password."
else
@saml_response = idp_make_saml_response(person)
render :template => "saml_idp/idp/saml_post", :layout => false
return
end
end
render :template => "saml_idp/idp/new"
end
def logout
idp_logout
@saml_response = idp_make_saml_response(nil)
render :template => "saml_idp/idp/saml_post", :layout => false
end
def idp_logout
user = User.by_email(saml_request.name_id)
user.logout
end
private :idp_logout
def idp_authenticate(email, password)
user = User.by_email(email).first
user && user.valid_password?(password) ? user : nil
end
protected :idp_authenticate
def idp_make_saml_response(person)
# NOTE encryption is optional
encode_response person, encryption: {
cert: saml_request.service_provider.cert,
block_encryption: 'aes256-cbc',
key_transport: 'rsa-oaep-mgf1p'
}
end
protected :idp_make_saml_response
endThe following sample views are used as a SAML GET request and mimic a POST request for your SAML controller Or if you want to handle a GET request in your new action with your own login, you don't need to use a form.
Without the Devise gem, you probably need to authenticate your user with your own login form.
# saml_idp/idp/new
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body>
<% if @saml_idp_fail_msg %>
<div id="saml_idp_fail_msg" class="flash error"><%= @saml_idp_fail_msg %></div>
<% end %>
<%= form_tag do %>
<%= hidden_field_tag("SAMLRequest", params[:SAMLRequest]) %>
<%= hidden_field_tag("RelayState", params[:RelayState]) %>
<p>
<%= label_tag :email %>
<%= email_field_tag :email, params[:email], :autocapitalize => "off", :autocorrect => "off", :autofocus => "autofocus", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %>
</p>
<p>
<%= label_tag :password %>
<%= password_field_tag :password, params[:password], :autocapitalize => "off", :autocorrect => "off", :spellcheck => "false", :size => 30, :class => "email_pwd txt" %>
</p>
<p>
<%= submit_tag "Sign in", :class => "button big blueish" %>
</p>
<% end %>
</body>
</html>
If you are a Devise user you following sample view will help to mimic a GET request automatically as a POST request.
# saml_idp/idp/new
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body onload="document.forms[0].submit();" style="visibility:hidden;">
<%= form_tag do %>
<%= hidden_field_tag("SAMLRequest", params[:SAMLRequest]) %>
<%= hidden_field_tag("RelayState", params[:RelayState]) %>
<% end %>
</body>
</html>The most important view for SAML IdP is the following auto submit form that submit SAML response to the SAML SP via browser. This is a minimal example of auto submit form, you can override the form in your Rails app to creating same file.
# saml_idp/idp/saml_post
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
</head>
<body onload="document.forms[0].submit();" style="visibility:hidden;">
<form action="<%= saml_acs_url %>" method="post">
<%= hidden_field_tag("SAMLResponse", @saml_response) %>
<%= hidden_field_tag("RelayState", params[:RelayState]) %>
<%= submit_tag "Submit" %>
</form>
</body>
</html>-
Never use sample public and private keys from this gem. Private key used to secure your SAML request and response. If you use a publicly published private key, your IdP service become a door without a lock.
-
To implement the security validation feature on your controller The most common security validations are listed in OWASP SAML Security page. We would suggest implementing the required one for your IdP. SAML Security Cheat Sheet Recommending to implement: "AuthnRequest(ID, SP)" from Validate Protocol Usage.
-
We highly recommend that you store your private key in a very secure place, such as KMS.