IntegrationPal
This engine is meant to contain the elements of big_sis that can be shared across sis integrations such as
- access token
- job starting
- job monitoring
- error capturing
- Okta SAML2 authentication
Usage
1) Create an active job
bin/rails generate job example_job
Installation
Add
integration_pal
to your application's Gemfile:gem 'integration_pal'
And install the bundle:
$ bundle install
Or install the Gem manually:
$ gem install integration_pal
Define Environment variables
ENCRYPTION_KEY=... # must be 32 chars SALT_KEY=... # must be 32 chars OKTA_APP=okta_app_key OKTA_ID=xxxxxxxxxxx # Usually Base64 SAML_DOMAIN=https://example-app-test.herokuapp.com/ SAML_AUDIENCE=https://example-app.herokuapp.com/login # If using a single Okta app for all environments, this should be set to the prod instance + /login
Generate template files for your project:
$ bundle exec rails g integration_pal:install
Set active job config.active_job.queue_adapter = :sidekiq # If you are using sidekiq
Configure app. Include
sp_metadata.xml[.erb]
inconfig/saml
:<?xml version="1.0"?> <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="<%= ENV['SAML_AUDIENCE'] || URI.join(ENV['SAML_DOMAIN'], saml2_meta_path) %>"> <md:SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:AssertionConsumerService Location="<%= URI.join(ENV['SAML_DOMAIN'], saml2_login_path) %>" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" index="0"/> </md:SPSSODescriptor> </md:EntityDescriptor>
Also include
idp_metadata.xml[.erb]
inconfig/saml
:<?xml version="1.0" encoding="UTF-8"?> <md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" entityID="http://www.okta.com/<%= ENV['OKTA_ID'] %>"> <md:IDPSSODescriptor WantAuthnRequestsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"> <md:KeyDescriptor use="signing"> <ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#"> <ds:X509Data> <ds:X509Certificate> {{ INSERT OKTA CERTIFICATE HERE }} </ds:X509Certificate> </ds:X509Data> </ds:KeyInfo> </md:KeyDescriptor> <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified</md:NameIDFormat> <md:NameIDFormat>urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress</md:NameIDFormat> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="https://instructure.okta.com/app/<%= ENV['OKTA_APP'] %>/<%= ENV['OKTA_ID'] %>/sso/saml"/> <md:SingleSignOnService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="https://instructure.okta.com/app/<%= ENV['OKTA_APP'] %>/<%= ENV['OKTA_ID'] %>/sso/saml"/> </md:IDPSSODescriptor> </md:EntityDescriptor>
Metadata file names can be overriden from within an initializer:
IntegrationPal. = 'idp_metadata.xml' IntegrationPal. = 'sp_metadata.xml'
To validate or begin Okta authentication within a controller, use:
session[:saml_username] ||= ENV['USER'] if Rails.env.in?(%w(development test)) redirect_to saml2_login_url unless session[:saml_username]
Deploying to Heroku
The SAML2 Authentication library that this tool uses requires libxmlsec1-dev
. In order to ensure that it is installed on the Heroku dyno, add https://github.com/ABASystems/heroku-buildpack-apt as the first buildpack in Heroku, followed by heroku/ruby
. Also include an Aptfile
in the root of your project:
libxmlsec1-dev
! - Double check this if Heroku fails to build Gem native extensions for nokogiri-xmlsec-instructure
during deployment.
License
The gem is available as open source under the terms of the MIT License.
Example API Request
Note how we sign the request using ApiAuth
require "uri"
require "net/https"
require "time"
require "rubygems"
require "api_auth"
require 'active_record'
JOB_URL = "http://localhost:3000/api/v1/jobs"
access_key_id = "test"
secret_access_key = "test"
uri = URI.parse(JOB_URL)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = {
job: {
worker_id: 1,
job_params: {
start_date: "2016-05-25T19:57:16Z",
end_date: "2017-05-25T13:57:59-06:00"
}
}
}.to_json
ApiAuth.sign!(request, access_key_id, secret_access_key)
response = http.request(request)
puts response.body