omniauth-realme
Omniauth strategy for New Zealand's secure online identity verification service.
This Gem has been developed for the intention of using Devise as the account model with Realme SSO integration. This gem covers all of the SAML client requirements for RealMe integrations including the RealMe's default error messages.
You will need to set up your frontend login pages to match RealMe's branding guidelines We suggest you use their assets in a zip file on their page.
Getting to Production:
You will need to complete the RealMe Operational handover checklist login service
form to gain access to RealMe production environments.
Not using Ruby but need to integrate? Use this gem as a baseline and find a suitable Library on onelogin's github account.
Installation
Add this line to your application's Gemfile:
gem 'devise'
gem 'omniauth-realme'
And then execute:
$ bundle
Realme
To test that you have installed the Gem correctly integrate with their message testing servies RealMe MTS first, followed by ITE then Production integrations.
You will need to set up your applications integration via their developers website for ITE and production.
Devise
Setup
# config/initializers/devise.rb
Devise.setup do |config|
# ...
config.omniauth :realme
end
Here we configure the ruby-saml gem.
Realme provides the necessary service-metadata.xml
files for their side of the integration. They can be found on this page
# config/initializers/omniauth.rb
# Use OmniAuthCallbacksController#failure as the Rack app which OmniAuth will
# redirect to in the event of a failure
OmniAuth.config.on_failure = Proc.new { |env| OmniAuthCallbacksController.action(:failure).call(env) }
OmniAuth.configure do |config|
# Always redirect to the failure endpoint if there is an error. Normally the
# exception would just be raised in development mode. This is useful for
# testing your Realme error handling in development.
config.failure_raise_out_environments = []
# We want to see OmniAuth messages in the log
config.logger = Rails.logger
end
# config/initializers/realme_omniauth.rb
OmniAuth::Strategies::Realme.configure do |config|
# Website issuer namespace
config.issuer = 'http://myapp/<issuer>/<access>'
# Callback url
config.assertion_consumer_service_url = 'http://myapp.com/users/auth/realme/callback'
# Sign the request saml and decrypt response
# Read the public+private keypair from a file. This example demonstrates
# using the .p12 file Realme provides to help you get up an running with their
# MTS environment.
p12 = OpenSSL::PKCS12.new(File.read(Rails.root.join("realme/Integration-Bundle-MTS-V3.2/mts_saml_sp.p12")), "password")
# Give the strategy the public key that will identify your SP to Realme (the IdP)
config.certificate = p12.certificate.to_s
# Give the strategy the corresponding private key so it can decrypt messages
# sent by Realme which are encrypted with the public key
config.private_key = p12.key.to_s
# Realme login service xml file.
# You will need to download the different XML files for the different environments found here: https://developers.realme.govt.nz/how-realme-works/technical-integration-steps/
config. = Rails.root.join('path', 'to', 'logon-service-metadata.xml')
# default strength
config.auth_strength = 'urn:nzl:govt:ict:stds:authn:deployment:GLS:SAML:2.0:ac:classes:LowStrength'
# The allowed clock drift is added to the current time at which the response
# is validated before it's tested against the NotBefore assertion. Its value
# must be given in a number (and/or fraction) of seconds.
#
# Make sure to keep the value as comfortably small as possible to keep
# security risks to a minimum.
#
# See: https://github.com/onelogin/ruby-saml#clock-drift
#
config.allowed_clock_drift = 5.seconds # default is 0.seconds
# It can be very useful to fail noisily in development if there are SAML
# validation errors. We recommend enabling this in Rails development env at
# least.
#
config.raise_exceptions_for_saml_validation_errors = Rails.env.development? # default: false
# Versions 0.1.0 and older of this gem return the FLT or any errors from
# Realme in the Rails session. We are migrating away from this to a more
# conventional OmniAuth approach of returning the FLT in
# `request.env['omniauth.auth'] and errors redirect to the OmniAuth failure
# Rack app.
#
# As of version 0.1.0, using the Rails session is enabled by default to not
# break existing installations. If you are configuring this strategy in a new
# application, you should set this behaviour to `false` to ensure your app
# continues to work seamlessly in future versions of this gem.
#
config.legacy_rails_session_behaviour_enabled = false
end
Routes
# config/routes.rb
# Add/edit the `devise_for` line in your routes file as shown here
devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
Controllers
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
# ...
private
def configure_permitted_parameters
# :uid, :provider and any new fields need to be added here
devise_parameter_sanitizer.permit(:sign_up, keys: [:password, :password_confirmation, :email, :uid, :provider])
end
# ...
end
The customer uid
will come through in request.env['omniauth.auth']['uid']
# app/controllers/users/omniauth_callbacks_controller.rb
module Users
class OmniauthCallbacksController < ::Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def realme
realme_flt_token = request.env["omniauth.auth"]["uid"]
@user = User.from_omniauth('realme', realme_flt_token)
unless @user.valid?
@user.errors.each { |err| @user.errors.delete(err) }
flash.notice = 'RealMe login successful, please fill in your user details.'
return render 'devise/registrations/new.html.haml'
end
flash.notice = 'RealMe login successful.'
sign_in_and_redirect @user
end
def failure
exception = request.env["omniauth.error"] # a reference to the exception instance class
error_type = request.env["omniauth.error.type"] # the first symbol passed to fail!()
erroring_strategy = request.env["omniauth.error.strategy"] # a reference to the strategy instance that threw the error
flash.alert = "Realme login failed because #{exception.}"
redirect_to root_path
end
end
end
Views
- You will need to update your registration
new
andedit
views by adding the new fields as well as hidden fields forprovider
anduid
. - User sign in view will also need to be updated so that it links to the OmniAuth realme pass through using the link helper
user_realme_omniauth_authorize_path
.
Model
# app/models/user.rb
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable,
:omniauthable, omniauth_providers: [:realme]
validates :provider, presence: true
validates :uid, presence: true, uniqueness: true
validates :email, presence: true, uniqueness: true
def self.from_omniauth(provider, uid)
where(provider: provider, uid: uid).first_or_create do |user|
user.provider = provider
user.uid = uid
end
end
end
Migrations
You will need to add
provider
anduid
to your model and index theuid
# db/migrate/<timestamp>_devise_create_users.rb class DeviseCreateUsers < ActiveRecord::Migration[5.2] def change create_table :users do |t| # ... t.string :provider, null: false t.string :uid, null: false, unique: true # ... end # ... add_index :users, :uid, unique: true end end
Remove SAMLResponse from Rails log
#config/initializers/filter_parameter_logging.rb
Rails.application.config.filter_parameters += [:password, 'SAMLResponse']
Metadata
This gem includes OmniAuth::Realme.generate_metadata_xml
which will generate SAML SP metadata in a form suitable for uploading to the Realme MTS Metadata upload endpoint using the same settings you used to configure this strategy.
Below is an example of using it to create a /saml/metadata.xml
endpoint in your app. This can be convenient but might be unnecessary for your application, depending on your use case so this step is optional.
# config/routes.rb
# Example: curl http://localhost:3000/saml/metadata.xml
get "saml/metadata", to: "saml_metadata#metadata"
# app/controllers/saml_metadata_controller.rb
class SamlMetadataController < ApplicationController
# Skip authentication on the metadata action (this line is only required if
# you are using devise)
skip_before_action :authenticate_user!, only: [:metadata]
def
respond_to do |format|
format.xml { render xml: OmniAuth::Realme. }
end
end
end
If you don't need an endpoint in your app you can just invoke the function from the console e.g.
rails-console> puts OmniAuth::Realme.generate_metadata_xml
Realme Context Mapping Service (RCMS)
Realme Context Mapping Service is an additional service which your app can optionally integrate with.
Most of the work of integrating with RCMS is outside of the scope of what OmniAuth does. If your app is using RCMS then you will receive a Login Attributes Token as well as the normal Realme FLT with the SAMLResponse.
This strategy facilitates your use of RCMS by making that additional token (if
it exists) available in
request.env['omniauth.auth']['credentials']['realme_cms_lat']
e.g.
# app/controllers/users/omniauth_callbacks_controller.rb
module Users
class OmniauthCallbacksController < ::Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def realme
realme_flt = request.env['omniauth.auth']['uid']
realme_cms_lat = request.env['omniauth.auth']['credentials']['realme_cms_lat']
# complete your RCMS integration here ...
end
end
end
Development
After checking out the repo, run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and tags, and push the .gem
file to rubygems.org.
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/DigitalNZ/omniauth-realme.
License
GNU GENERAL PUBLIC LICENSE