This is an example Rails 3 app behaving as a trivial SAML IdP (Identity Provider) using https://github.com/lawrencepit/ruby-saml-idp It exists mostly to allow you to test your SAML Service Provider implementation.
SAML (Security Assertion Markup Language) is an XML-based open standard for exchanging authentication and authorization data between security domains, that is, between an identity provider (a producer of assertions) and a service provider (a consumer of assertions).
A SAML IdP offers Single Sign On to one or more web applications (SAML Service Providers). Based on its implementation it may actually be a proxy to an LDAP or ActiveDirectory server within your organization. This example IdP does not do that. It exists mostly to allow you to test your SAML Service Provider implementation.
In production, you would allow your corporate customers to connect their own SAML IdP to your web application (a SAML Service Provider). Alternately, they could outsource the hosting of a SAML IdP to a company like onelogin or a self-hosted solution like PingFederate.
A SAML IdP is a running web application that has two-way communication, and browser redirection, with one or more SAML Service Providers (web applications that you actually want to use).
Since this codebase exists primarily to allow you to test your own SAML implementation, you could throw it up on the free Heroku hosting service:
cd /tmp
git clone git://github.com/drnic/ruby-saml-idp-rails3-example.git
cd ruby-saml-idp-rails3-example
bundle
heroku create
git push heroku master
heroku run rake db:migrate
heroku apps:info
The "Web URL" value will be used when registering this example IdP with your SAML SP.
If you want to see the example IdP work with an example SP, then you are in luck!.
cd /tmp
git clone git://github.com/drnic/ruby-saml-rails3-example.git
cd ruby-saml-rails3-example
bundle
heroku create
git push heroku master
heroku run rake db:migrate
# when its finished...
heroku apps:open
This automatically redirects to /saml endpoint, which shows "No Settings" header.
Click on "Admin section" to create your first IdP backend (NOTE: the example SP app only supports on IdP backend currently).
For this example IdP, which doesn't have a metadata endpoint, the only fields to fill in are the last two:
For example:
Click "Create account" to save the IdP backend.
Your administration of an IdP backend is complete. You can now pretend to be a real user. Go to the home page of the SP application:
heroku apps:open
You'll see "Not logged in." Click on "Log in". Notice that the browser URL changes from your SP app to your IdP application.
Enter any email/password (values are ignored, see "Example authentication controller" section below). Click "Sign in".
You are now returned to the SP application and will see something like this:
Congratulations, as a user of the SP example application you have authenticated in via the IdP application.
The authentication controller accepts any email/password and always returns "[email protected]".
class SamlIdpController < SamlIdp::IdpController
def idp_authenticate(email, password)
true
end
def idp_make_saml_response(user)
encode_SAMLResponse("[email protected]")
end
end
Another almost-as-trivial controller is in ruby-saml-idp's specs:
class SamlIdpController < SamlIdp::IdpController
def idp_authenticate(email, password)
{ :email => email }
end
def idp_make_saml_response(user)
encode_SAMLResponse(user[:email])
end
end
If you were actually going to use this code base as a real single-sign on (SSO) server with accounts and users, then you might do something like following (which comes from the README of ruby-saml-idp):
class SamlIdpController < SamlIdp::IdpController
before_filter :find_account
# layout 'saml_idp'
def idp_authenticate(email, password)
user = @account.users.where(:email => params[:email]).first
user && user.valid_password?(params[:password]) ? user : nil
end
def idp_make_saml_response(user)
encode_SAMLResponse(user.email)
end
private
def find_account
@subdomain = saml_acs_url[/https?:\/\/(.+?)\.example.com/, 1]
@account = Account.find_by_subdomain(@subdomain)
render :status => :forbidden unless @account.saml_enabled?
end
end