saml_camel 0.2.2 → 0.2.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +8 -6
- data/app/controllers/concerns/saml_camel/saml_service.rb +35 -0
- data/app/controllers/saml_camel/saml_controller.rb +10 -23
- data/app/models/saml_camel/application_record.rb +1 -1
- data/app/models/saml_camel/service_provider.rb +161 -0
- data/app/models/saml_camel/shib.rb +26 -0
- data/app/views/layouts/saml_camel/application.html.erb +0 -2
- data/lib/saml_camel.rb +98 -1
- data/lib/saml_camel/engine.rb +1 -1
- data/lib/saml_camel/transaction.rb +0 -0
- data/lib/saml_camel/version.rb +1 -1
- data/lib/tasks/saml_camel_tasks.rake +14 -15
- metadata +6 -12
- data/app/assets/config/saml_camel_manifest.js +0 -2
- data/app/assets/javascripts/saml_camel/application.js +0 -13
- data/app/assets/stylesheets/saml_camel/application.css +0 -15
- data/app/assets/stylesheets/scaffold.css +0 -80
- data/app/controllers/concerns/saml_camel/saml_helpers.rb +0 -134
- data/app/helpers/saml_camel/application_helper.rb +0 -4
- data/app/jobs/saml_camel/application_job.rb +0 -4
- data/app/mailers/saml_camel/application_mailer.rb +0 -6
- data/app/models/saml_camel/logging.rb +0 -51
- data/app/models/saml_camel/transaction.rb +0 -56
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b7fd883c9fb712daac3a0eec2ceecf41158452b8
|
4
|
+
data.tar.gz: a54c29f80e07049a3cae26a5ac2661fe458ca10e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 605cb590546df8667225f53750abc9ebd08a8e6e3884182a7f22464a916de928470955f24b04e6ccee3d564382057e88c078f7f48b9901288b54d0c2bfea2fe3
|
7
|
+
data.tar.gz: 4238d45a9998662d3abebea3b41a9dffe300561847f94871f70ed5eef979f9a980e45cf3cd47ad72023f7c110cc8ac3d41034e3c6093001ecbd8e7c10dd3cb10
|
data/README.md
CHANGED
@@ -31,24 +31,26 @@ $ bundle
|
|
31
31
|
### IMPORTANT: This step enables security features and is required to use the gem!
|
32
32
|
1. in your environments config (`config/development.rb` for example) ensure that you have caching configured as follows
|
33
33
|
|
34
|
-
|
34
|
+
|
35
35
|
```ruby
|
36
36
|
config.action_controller.perform_caching = true
|
37
37
|
config.cache_store = :memory_store
|
38
38
|
```
|
39
39
|
|
40
|
+
**NOTE:** use the cache_store most appropriate for your situation. It may make more sense to use a file store, or a redis server. For example it may not make sense to cache in memory in production. You can read more about rails caching behavior here http://guides.rubyonrails.org/caching_with_rails.html
|
41
|
+
|
40
42
|
2. run `rake saml_camel:generate_saml` to generate metadata files for each environment. you can also specify a custom environment like this `rake saml_camel:generate_saml environment=acceptance`
|
41
43
|
|
42
44
|
**Note: these steps will use development as an example, if you use separate metadata per environment, you will repeat each step for your chosen environment**
|
43
45
|
|
44
|
-
3. from the root of your app open `saml/development/settings.json` and specify an entity ID of your choice. this is a unique identifier used by the
|
46
|
+
3. from the root of your app open `config/saml/development/settings.json` and specify an entity ID of your choice. this is a unique identifier used by the
|
45
47
|
Identity Provider(idp) to recognize your app. Typically it should take the form of a url, however note that it is just an identifier and does not have to resolve (e.g. https://my-app-name/not/a/real/route)
|
46
48
|
|
47
|
-
4. Go to https://authentication.oit.duke.edu/manager/register/sp and register your metadata with the identity provider. You will need the values from `saml/development/settings.json` in addition to the `saml/development/saml_certificate.crt`
|
49
|
+
4. Go to https://authentication.oit.duke.edu/manager/register/sp and register your metadata with the identity provider. You will need the values from `config/saml/development/settings.json` in addition to the `config/saml/development/saml_certificate.crt`
|
48
50
|
|
49
51
|
- copy the entity_id you chose in the `settings.json` file and paste it into the "Entity Field"
|
50
52
|
- fill out functional purpose, responsible dept, function owner dept, and audience with information relevant to your application
|
51
|
-
- copy the cert from `saml/development/saml_certificate.crt` and paste it into the Certificate Field
|
53
|
+
- copy the cert from `config/saml/development/saml_certificate.crt` and paste it into the Certificate Field
|
52
54
|
- copy the acs value and paste it into the Location field in the Assertion Consumer Service box
|
53
55
|
- note that the default host value for ACS is `http://locahost:3000` which is the default `rails s` host. If you're using a different host (such as in production or using docker) you will want to replace the host value with what is relevent for your situation(*e.g. https://my-app.duke.edu/saml/consumeSaml*), but keep the path `/saml/consumeSaml`
|
54
56
|
|
@@ -78,7 +80,7 @@ Identity Provider(idp) to recognize your app. Typically it should take the form
|
|
78
80
|
|
79
81
|
8. It is recommended to set `config.force_ssl = true` in the `config/environments/production.rb` file for security
|
80
82
|
|
81
|
-
9. Logging is turned on by default. Logging is configured in `saml/development/settings.json`. To utilize logging saml_logging should be set to true (default), and primary_id must have a value. primary_id is the saml attribute you consider to be a primary identifier for a user
|
83
|
+
9. Logging is turned on by default. Logging is configured in `config/saml/development/settings.json`. To utilize logging saml_logging should be set to true (default), and primary_id must have a value. primary_id is the saml attribute you consider to be a primary identifier for a user
|
82
84
|
|
83
85
|
|
84
86
|
10. Users can go to http://localhost:3000/saml/attributes to view attributes being passed through
|
@@ -92,7 +94,7 @@ Identity Provider(idp) to recognize your app. Typically it should take the form
|
|
92
94
|
"acs": "http://localhost:3000/saml/consumeSaml",
|
93
95
|
"entity_id": "https://samlCamel.com/doesNotResolve",
|
94
96
|
"sso_url": "https://shib.oit.duke.edu/idp/profile/SAML2/Redirect/SSO",
|
95
|
-
"
|
97
|
+
"logout_url": "https://shib.oit.duke.edu/cgi-bin/logout.pl",
|
96
98
|
"primary_id": "eduPersonPrincipalName",
|
97
99
|
"sp_session_timeout": 1,
|
98
100
|
"sp_session_lifetime": 8,
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require_dependency "saml_camel/application_controller"
|
2
|
+
|
3
|
+
module SamlCamel::SamlService
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
def cache_available?(app_cache)
|
7
|
+
if app_cache
|
8
|
+
true
|
9
|
+
else
|
10
|
+
session[:sp_session] = nil
|
11
|
+
false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def saml_protect
|
16
|
+
user_cache = cache_available?(Rails.cache.fetch(session[:saml_session_id])) if session[:saml_session_id]
|
17
|
+
if session[:saml_session_id] && user_cache
|
18
|
+
sp = SamlCamel::ServiceProvider.new(cache_permit_key: session[:saml_session_id].to_sym, saml_attributes: session[:saml_attributes])
|
19
|
+
session[:sp_session] = sp.validate_sp_session(session[:sp_session],request.remote_ip)
|
20
|
+
unless (session[:saml_response_success] || session[:sp_session])
|
21
|
+
saml_request_url = sp.generate_saml_request(request)
|
22
|
+
redirect_to(saml_request_url)
|
23
|
+
end
|
24
|
+
|
25
|
+
else
|
26
|
+
session[:saml_session_id] = SamlCamel::ServiceProvider.generate_permit_key
|
27
|
+
saml_request_url = SamlCamel::ServiceProvider.new(cache_permit_key: session[:saml_session_id].to_sym).generate_saml_request(request)
|
28
|
+
redirect_to(saml_request_url)
|
29
|
+
end
|
30
|
+
session[:saml_response_success] = nil #keeps us from looping
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -2,7 +2,7 @@ require_dependency "saml_camel/application_controller"
|
|
2
2
|
|
3
3
|
module SamlCamel
|
4
4
|
class SamlController < ApplicationController
|
5
|
-
include SamlCamel::
|
5
|
+
include SamlCamel::SamlService
|
6
6
|
skip_before_action :verify_authenticity_token ,only: [:consume,:logout]
|
7
7
|
before_action :saml_protect, only: [:attr_check]
|
8
8
|
|
@@ -19,31 +19,18 @@ module SamlCamel
|
|
19
19
|
permit_key = session[:saml_session_id].to_sym
|
20
20
|
user_cache = Rails.cache.fetch(permit_key)
|
21
21
|
raise "Unable to access cache. Ensure cache is configrued according to documentation." unless cache_available?(user_cache)
|
22
|
-
|
23
22
|
redirect_path = user_cache[:redirect_url]
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
if response.is_valid? # validate the SAML Response
|
28
|
-
|
29
|
-
#verify not sha1
|
30
|
-
verify_sha_type(response)
|
31
|
-
|
32
|
-
response_id = response.id(response.document)
|
33
|
-
|
34
|
-
#confirm that IP address from response matches that of original request
|
35
|
-
valid_ip?(request.remote_ip)
|
36
|
-
|
37
|
-
#check that response id has not already been used
|
38
|
-
duplicate_response_id?(response_id)
|
23
|
+
sp = SamlCamel::ServiceProvider.new(cache_permit_key: permit_key, saml_attributes: session[:saml_attributes])
|
24
|
+
ol_response = SamlCamel::ServiceProvider.ol_response(params[:SAMLResponse])
|
39
25
|
|
26
|
+
if sp.validate_idp_response(ol_response,request.remote_ip)
|
40
27
|
# authorize_success, log the user
|
41
28
|
session[:saml_response_success] = true
|
42
|
-
set_saml_session_lifetime
|
29
|
+
sp.set_saml_session_lifetime
|
43
30
|
session[:sp_session] = Time.now
|
44
31
|
|
45
|
-
session[:saml_attributes] = SamlCamel::Transaction.map_attributes(
|
46
|
-
SamlCamel::Logging.
|
32
|
+
session[:saml_attributes] = SamlCamel::Transaction.map_attributes(ol_response.attributes)
|
33
|
+
SamlCamel::Logging.successful_auth(session[:saml_attributes])
|
47
34
|
|
48
35
|
redirect_to redirect_path
|
49
36
|
else # otherwise list out the errors in the response
|
@@ -55,9 +42,9 @@ module SamlCamel
|
|
55
42
|
session[:sp_session] = nil
|
56
43
|
session[:saml_response_success] = false
|
57
44
|
response.errors
|
58
|
-
SamlCamel::Logging.auth_failure(
|
45
|
+
SamlCamel::Logging.auth_failure(ol_response.errors)
|
59
46
|
|
60
|
-
redirect_to action: "failure", locals:{errors:
|
47
|
+
redirect_to action: "failure", locals:{errors: ol_response.errors}
|
61
48
|
end
|
62
49
|
rescue => e
|
63
50
|
if session[:saml_session_id]
|
@@ -86,7 +73,7 @@ module SamlCamel
|
|
86
73
|
session[:sp_session] = nil
|
87
74
|
|
88
75
|
# return_url = SamlCamel::Transaction.logout #this methods logs the user out of the IDP, and returns a url to be redirected to
|
89
|
-
redirect_to "
|
76
|
+
redirect_to SP_SETTINGS["settings"]["logout_url"]
|
90
77
|
end
|
91
78
|
|
92
79
|
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module SamlCamel
|
2
|
+
class ServiceProvider
|
3
|
+
attr_reader :cache_permit_key, :user_cache, :saml_attributes
|
4
|
+
|
5
|
+
def initialize(cache_permit_key: nil, user_cache: nil, saml_attributes: nil)
|
6
|
+
@cache_permit_key = cache_permit_key.to_sym
|
7
|
+
@saml_attributes = saml_attributes
|
8
|
+
@user_cache = Rails.cache.fetch(@cache_permit_key)
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def self.generate_permit_key
|
13
|
+
secure_random = SecureRandom.base64.chomp.gsub( /\W/, '' )
|
14
|
+
"samlCamel#{secure_random}"
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.ol_response(idp_response)
|
18
|
+
response = OneLogin::RubySaml::Response.new(idp_response, :settings => SamlCamel::Transaction.saml_settings)
|
19
|
+
response.settings = SamlCamel::Transaction.saml_settings
|
20
|
+
|
21
|
+
response
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
def check_expired_session(sp_session)
|
26
|
+
# cache_available?(user_cache) TODO come back to this
|
27
|
+
sp_timeout = SP_SETTINGS["settings"]["sp_session_timeout"]
|
28
|
+
sp_lifetime = SP_SETTINGS['settings']["sp_session_lifetime"]
|
29
|
+
|
30
|
+
set_saml_session_lifetime if @user_cache[:session_start_time].nil?
|
31
|
+
sp_session_init_time = @user_cache[:session_start_time]
|
32
|
+
|
33
|
+
|
34
|
+
######## set session[:sp_session] maybe a seperate method
|
35
|
+
if sp_session
|
36
|
+
|
37
|
+
#if the session has timed out remove session, otherwise refresh
|
38
|
+
if (Time.now - Time.parse(sp_session)) < sp_timeout.hour
|
39
|
+
return Time.now
|
40
|
+
else
|
41
|
+
SamlCamel::Logging.expired_session(@saml_attributes)
|
42
|
+
return nil
|
43
|
+
end
|
44
|
+
|
45
|
+
#if the session has exceeded the allowed lifetime, remove session
|
46
|
+
if (Time.now - sp_session_init_time) > sp_lifetime.hour
|
47
|
+
SamlCamel::Logging.expired_session(@saml_attributes)
|
48
|
+
return nil
|
49
|
+
end
|
50
|
+
else #if no sp session return nil
|
51
|
+
return nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
def duplicate_response_id?(response_id, count: 3)
|
57
|
+
#use semaphore to only allow 1 thread at a time to access
|
58
|
+
@semaphore ||= Mutex.new
|
59
|
+
@semaphore.synchronize {
|
60
|
+
ids = Rails.cache.fetch("saml_camel_response_ids")
|
61
|
+
if ids
|
62
|
+
if ids.include?(response_id)
|
63
|
+
session[:sp_session] = nil
|
64
|
+
raise "SAML response ID already issued."
|
65
|
+
else
|
66
|
+
ids << response_id
|
67
|
+
Rails.cache.fetch("saml_camel_response_ids", expires_in: 1.hours) do
|
68
|
+
ids
|
69
|
+
end
|
70
|
+
end
|
71
|
+
else
|
72
|
+
Rails.cache.fetch("saml_camel_response_ids", expires_in: 1.hours) do
|
73
|
+
[response_id]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
}
|
77
|
+
rescue ThreadError
|
78
|
+
puts "locked "* 50
|
79
|
+
if count > 0
|
80
|
+
sleep(0.1)
|
81
|
+
duplicate_response_id?(response_id, count: count - 1)
|
82
|
+
else raise "Resposne ID Validation Error"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
#generates a saml requests and establishes a cache for the user
|
89
|
+
def generate_saml_request(host_request)
|
90
|
+
request = OneLogin::RubySaml::Authrequest.new
|
91
|
+
lifetime = SamlCamel::SP_SETTINGS['settings']["sp_session_lifetime"]
|
92
|
+
|
93
|
+
#store ip address and original url request in memory to be used for verification and redirect after response
|
94
|
+
Rails.cache.fetch(@cache_permit_key, expires_in: lifetime.hours) do
|
95
|
+
{ip_address: host_request.remote_ip, redirect_url: host_request.url }
|
96
|
+
end
|
97
|
+
request.create(SamlCamel::Transaction.saml_settings)
|
98
|
+
end
|
99
|
+
|
100
|
+
#set saml_session lifetime, called if none set
|
101
|
+
def set_saml_session_lifetime
|
102
|
+
user_saml_cache = Rails.cache.fetch(@cache_permit_key)
|
103
|
+
user_saml_cache[:session_start_time] = Time.now
|
104
|
+
sp_lifetime = SP_SETTINGS['settings']["sp_session_lifetime"]
|
105
|
+
Rails.cache.fetch(@cache_permit_key, expires_in: sp_lifetime.hours) do
|
106
|
+
user_saml_cache #not sure if this can use @user_cache
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
#NOTE these methods will raise errors if not a valid response_id
|
111
|
+
# which in turn will trigger a resuce that kills the sp session
|
112
|
+
def validate_idp_response(response,remote_ip)
|
113
|
+
if response.is_valid?
|
114
|
+
#validate not sha1
|
115
|
+
verify_sha_type(response)
|
116
|
+
|
117
|
+
#validate IP address
|
118
|
+
raise "IP mismatch error" unless validate_ip(remote_ip)
|
119
|
+
|
120
|
+
response_id = response.id(response.document)
|
121
|
+
duplicate_response_id?(response_id)
|
122
|
+
|
123
|
+
response
|
124
|
+
else
|
125
|
+
false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
#validate that ip address has not changed
|
130
|
+
def validate_ip(remote_ip)
|
131
|
+
# cache_available?(saml_cache) TODO come back to this
|
132
|
+
return true if remote_ip == @user_cache[:ip_address]
|
133
|
+
SamlCamel::Logging.bad_ip(@saml_attributes, @user_cache[:ip_address], remote_ip)
|
134
|
+
return nil
|
135
|
+
end
|
136
|
+
|
137
|
+
#validates a the sp timestamps and ip. returns a new timestamp if everything is good
|
138
|
+
# otherwise returns nil
|
139
|
+
def validate_sp_session(sp_session,remote_ip)
|
140
|
+
new_session = check_expired_session(sp_session)
|
141
|
+
if new_session
|
142
|
+
has_valid_ip = validate_ip(remote_ip)
|
143
|
+
else
|
144
|
+
return nil
|
145
|
+
end
|
146
|
+
return new_session if has_valid_ip
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
def verify_sha_type(response)
|
151
|
+
#was suggested to use an xml parser, however was having great difficulyt with nokogiri
|
152
|
+
#open to trying a different parser or advice on nokogiri as it's not reacting as I would typically expect it to
|
153
|
+
raw_xml_string = response.decrypted_document.to_s
|
154
|
+
attr_scan = raw_xml_string.scan(/<ds:SignatureMethod.*\/>/)
|
155
|
+
is_sha1 = attr_scan[0].match("sha1")
|
156
|
+
|
157
|
+
raise "SHA1 algorithm not supported " if is_sha1
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module SamlCamel
|
2
|
+
class Shib
|
3
|
+
|
4
|
+
ATTRIBUTE_MAP = JSON.parse(File.read("config/saml/shibboleth.json"))
|
5
|
+
|
6
|
+
def self.attributes(request)
|
7
|
+
attrs = {}
|
8
|
+
ATTRIBUTE_MAP.each do |header_key, new_key|
|
9
|
+
attrs[new_key] = request.env.dig(header_key)
|
10
|
+
end
|
11
|
+
attrs
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.create_identity(values_hash)
|
15
|
+
identity = {}
|
16
|
+
values_hash.each {|k,v| identity[k] = v}
|
17
|
+
identity
|
18
|
+
end
|
19
|
+
|
20
|
+
#sets shib headers directly
|
21
|
+
def self.set_headers(request: nil,identity: nil)
|
22
|
+
identity.each {|k,v| request.env[k] = v }
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
data/lib/saml_camel.rb
CHANGED
@@ -1,5 +1,102 @@
|
|
1
1
|
require "saml_camel/engine"
|
2
2
|
|
3
3
|
module SamlCamel
|
4
|
-
|
4
|
+
begin
|
5
|
+
SP_SETTINGS = JSON.parse(File.read("config/saml/#{Rails.env}/settings.json"))
|
6
|
+
rescue
|
7
|
+
#rescue othewise the generator fails
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
module Transaction
|
12
|
+
begin
|
13
|
+
IDP_CERT = File.read("config/saml/#{Rails.env}/idp_certificate.crt")
|
14
|
+
SP_CERT = File.read("config/saml/#{Rails.env}/saml_certificate.crt")
|
15
|
+
SP_KEY = File.read("config/saml/#{Rails.env}/saml_key.key")
|
16
|
+
rescue
|
17
|
+
#rescue othewise the generator fails
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.map_attributes(sp_attributes)
|
21
|
+
attr_map = SP_SETTINGS["attribute_map"]
|
22
|
+
mapped_attributes = {}
|
23
|
+
|
24
|
+
sp_attributes.each do |sp_attribute,value|
|
25
|
+
sp_attribute = attr_map[sp_attribute] || value
|
26
|
+
mapped_attributes[sp_attribute] = value
|
27
|
+
end
|
28
|
+
mapped_attributes
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.saml_settings
|
32
|
+
sp_settings = SP_SETTINGS["settings"]
|
33
|
+
|
34
|
+
settings = OneLogin::RubySaml::Settings.new
|
35
|
+
settings.assertion_consumer_service_url = sp_settings["acs"]
|
36
|
+
|
37
|
+
settings.issuer = sp_settings["entity_id"]
|
38
|
+
settings.idp_sso_target_url = sp_settings["sso_url"]
|
39
|
+
|
40
|
+
# certificate to register with IDP and key to decrypt
|
41
|
+
settings.certificate = SP_CERT
|
42
|
+
|
43
|
+
# certificate to decrypt SAML response
|
44
|
+
settings.private_key = SP_KEY
|
45
|
+
|
46
|
+
# certificate to verify IDP signature
|
47
|
+
settings.idp_cert = IDP_CERT
|
48
|
+
|
49
|
+
settings
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
module Logging
|
55
|
+
begin
|
56
|
+
PRIMARY_ID = SP_SETTINGS["settings"]["primary_id"]
|
57
|
+
SHOULD_LOG = SP_SETTINGS["settings"]["saml_logging"]
|
58
|
+
LOGGER = Logger.new("log/saml.log")
|
59
|
+
rescue
|
60
|
+
#rescue othewise the generator fails
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
def self.auth_failure(error_context)
|
65
|
+
LOGGER.error("An error occured during authentication. #{error_context}") if SHOULD_LOG
|
66
|
+
LOGGER.error("Backtrace: \n\t\t#{error_context.backtrace.join("\n\t\t")}") if SHOULD_LOG
|
67
|
+
rescue
|
68
|
+
LOGGER.debug("Unknown Error During auth_failure logging.") if SHOULD_LOG
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.bad_ip(saml_attrs,request_ip,current_ip)
|
72
|
+
LOGGER.info("Bad IP address for #{saml_attrs[PRIMARY_ID]}. IP at SAML request #{request_ip} | IP presented #{current_ip}") if SHOULD_LOG
|
73
|
+
rescue
|
74
|
+
LOGGER.debug("Unknown Error During relay state logging. IP check") if SHOULD_LOG
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.expired_session(saml_attrs)
|
78
|
+
LOGGER.info("Session Expired for #{saml_attrs[PRIMARY_ID]}") if SHOULD_LOG
|
79
|
+
rescue
|
80
|
+
LOGGER.debug("Unknown Error During relay state logging. Expired session check") if SHOULD_LOG
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.logout(saml_attrs)
|
84
|
+
LOGGER.info("#{saml_attrs[PRIMARY_ID]} has succesfully logged out.") if SHOULD_LOG
|
85
|
+
rescue
|
86
|
+
LOGGER.debug("Unknown error logging user logout. Most likely anonymous user clicked a logout button.") if SHOULD_LOG
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.saml_state(data)
|
90
|
+
LOGGER.info("Stored Relay: #{data[:stored_relay]} | RequestRelay: #{data[:request_relay]} | Stored IP: #{data[:stored_ip]} RemoteIP: #{data[:remote_ip]}") if SHOULD_LOG
|
91
|
+
rescue
|
92
|
+
LOGGER.debug("Unknown Error During relay state logging. Saml state check") if SHOULD_LOG
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.successful_auth(saml_attrs)
|
96
|
+
LOGGER.info("#{saml_attrs[PRIMARY_ID]} has succesfully authenticated.") if SHOULD_LOG
|
97
|
+
rescue
|
98
|
+
LOGGER.debug("Unknown Error During successful_auth logging. Check PRIMARY_ID configured in settings.json and that user has attribute.") if SHOULD_LOG
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
5
102
|
end
|
data/lib/saml_camel/engine.rb
CHANGED
File without changes
|
data/lib/saml_camel/version.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
namespace :saml_camel do
|
2
2
|
desc "Generate Files for Saml"
|
3
3
|
task :generate_saml do
|
4
|
-
dir = "#{Rails.root}/saml/"
|
4
|
+
dir = "#{Rails.root}/config/saml/"
|
5
5
|
FileUtils.mkdir(dir) unless Dir.exists?(dir)
|
6
6
|
|
7
7
|
specified_env = ENV['environment']
|
@@ -12,7 +12,6 @@ namespace :saml_camel do
|
|
12
12
|
|
13
13
|
|
14
14
|
#TODO pull in specified idp certificate
|
15
|
-
# idp_cert = File.read("saml/idp_certs/#{ENV['idp']}.crt") if ENV['idp']
|
16
15
|
idp_cert = """MIIEWjCCA0KgAwIBAgIJAP1rB/FjRgy6MA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV
|
17
16
|
BAYTAlVTMRcwFQYDVQQIEw5Ob3J0aCBDYXJvbGluYTEPMA0GA1UEBxMGRHVyaGFt
|
18
17
|
MRgwFgYDVQQKEw9EdWtlIFVuaXZlcnNpdHkxDDAKBgNVBAsTA09JVDEaMBgGA1UE
|
@@ -41,22 +40,22 @@ tA6SX0infqNRyPRNJK+bnQd1yOP4++tjD/lAPE+5tiD/waI3fArt43ZE/qp7pYMS
|
|
41
40
|
|
42
41
|
unless specified_env
|
43
42
|
default_envs.each do |e|
|
44
|
-
dir = "#{Rails.root}/saml/#{e}"
|
43
|
+
dir = "#{Rails.root}/config/saml/#{e}"
|
45
44
|
FileUtils.mkdir(dir) unless Dir.exists?(dir)
|
46
|
-
File.open("#{Rails.root}/saml/#{e}/saml_certificate.crt","w+") {|f| f.write(cert) }
|
47
|
-
File.open("#{Rails.root}/saml/#{e}/saml_key.key","w+") {|f| f.write(key) }
|
48
|
-
File.open("#{Rails.root}/saml/#{e}/idp_certificate.crt","w+") {|f| f.write(idp_cert) }
|
49
|
-
File.open("#{Rails.root}/saml/#{e}/settings.json","w+") {|f| f.write(settings) }
|
50
|
-
File.open('.gitignore', 'a') { |f| f.write("saml/#{e}/saml_key.key\n") }
|
45
|
+
File.open("#{Rails.root}/config/saml/#{e}/saml_certificate.crt","w+") {|f| f.write(cert) }
|
46
|
+
File.open("#{Rails.root}/config/saml/#{e}/saml_key.key","w+") {|f| f.write(key) }
|
47
|
+
File.open("#{Rails.root}/config/saml/#{e}/idp_certificate.crt","w+") {|f| f.write(idp_cert) }
|
48
|
+
File.open("#{Rails.root}/config/saml/#{e}/settings.json","w+") {|f| f.write(settings) }
|
49
|
+
File.open('.gitignore', 'a') { |f| f.write("config/saml/#{e}/saml_key.key\n") }
|
51
50
|
end
|
52
51
|
else
|
53
|
-
dir = "#{Rails.root}/saml/#{specified_env}"
|
52
|
+
dir = "#{Rails.root}/config/saml/#{specified_env}"
|
54
53
|
FileUtils.mkdir(dir) unless Dir.exists?(dir)
|
55
|
-
File.open("#{Rails.root}/saml/#{specified_env}/saml_certificate.crt","w+") {|f| f.write(cert) }
|
56
|
-
File.open("#{Rails.root}/saml/#{specified_env}/saml_key.key","w+") {|f| f.write(key) }
|
57
|
-
File.open("#{Rails.root}/saml/#{specified_env}/idp_certificate.crt","w+") {|f| f.write(idp_cert) }
|
58
|
-
File.open("#{Rails.root}/saml/#{specified_env}/settings.json","w+") {|f| f.write(settings) }
|
59
|
-
File.open('.gitignore', 'a') { |f| f.write("saml/#{specified_env}/saml_key.key") }
|
54
|
+
File.open("#{Rails.root}/config/saml/#{specified_env}/saml_certificate.crt","w+") {|f| f.write(cert) }
|
55
|
+
File.open("#{Rails.root}/config/saml/#{specified_env}/saml_key.key","w+") {|f| f.write(key) }
|
56
|
+
File.open("#{Rails.root}/config/saml/#{specified_env}/idp_certificate.crt","w+") {|f| f.write(idp_cert) }
|
57
|
+
File.open("#{Rails.root}/config/saml/#{specified_env}/settings.json","w+") {|f| f.write(settings) }
|
58
|
+
File.open('.gitignore', 'a') { |f| f.write("config/saml/#{specified_env}/saml_key.key") }
|
60
59
|
end
|
61
60
|
end
|
62
61
|
|
@@ -68,7 +67,7 @@ tA6SX0infqNRyPRNJK+bnQd1yOP4++tjD/lAPE+5tiD/waI3fArt43ZE/qp7pYMS
|
|
68
67
|
acs: "http://localhost:3000/saml/consumeSaml" ,
|
69
68
|
entity_id: "https://your-entity-id.com",
|
70
69
|
sso_url: "https://shib.oit.duke.edu/idp/profile/SAML2/Redirect/SSO",
|
71
|
-
|
70
|
+
logout_url: "https://shib.oit.duke.edu/cgi-bin/logout.pl",
|
72
71
|
primary_id: "eduPersonPrincipalName",
|
73
72
|
sp_session_timeout: 1,
|
74
73
|
sp_session_lifetime: 8,
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saml_camel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- 'Danai Adkisson '
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-05-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -76,25 +76,19 @@ files:
|
|
76
76
|
- MIT-LICENSE
|
77
77
|
- README.md
|
78
78
|
- Rakefile
|
79
|
-
- app/
|
80
|
-
- app/assets/javascripts/saml_camel/application.js
|
81
|
-
- app/assets/stylesheets/saml_camel/application.css
|
82
|
-
- app/assets/stylesheets/scaffold.css
|
83
|
-
- app/controllers/concerns/saml_camel/saml_helpers.rb
|
79
|
+
- app/controllers/concerns/saml_camel/saml_service.rb
|
84
80
|
- app/controllers/saml_camel/application_controller.rb
|
85
81
|
- app/controllers/saml_camel/saml_controller.rb
|
86
|
-
- app/helpers/saml_camel/application_helper.rb
|
87
|
-
- app/jobs/saml_camel/application_job.rb
|
88
|
-
- app/mailers/saml_camel/application_mailer.rb
|
89
82
|
- app/models/saml_camel/application_record.rb
|
90
|
-
- app/models/saml_camel/
|
91
|
-
- app/models/saml_camel/
|
83
|
+
- app/models/saml_camel/service_provider.rb
|
84
|
+
- app/models/saml_camel/shib.rb
|
92
85
|
- app/views/layouts/saml_camel/application.html.erb
|
93
86
|
- app/views/saml_camel/saml/attr_check.html.erb
|
94
87
|
- app/views/saml_camel/saml/failure.html.erb
|
95
88
|
- config/routes.rb
|
96
89
|
- lib/saml_camel.rb
|
97
90
|
- lib/saml_camel/engine.rb
|
91
|
+
- lib/saml_camel/transaction.rb
|
98
92
|
- lib/saml_camel/version.rb
|
99
93
|
- lib/tasks/saml_camel_tasks.rake
|
100
94
|
homepage: https://idms-git.oit.duke.edu/da129/saml_camel
|
@@ -1,13 +0,0 @@
|
|
1
|
-
// This is a manifest file that'll be compiled into application.js, which will include all the files
|
2
|
-
// listed below.
|
3
|
-
//
|
4
|
-
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
|
5
|
-
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
|
6
|
-
//
|
7
|
-
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
8
|
-
// compiled file. JavaScript code in this file should be added after the last require_* statement.
|
9
|
-
//
|
10
|
-
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
|
11
|
-
// about supported directives.
|
12
|
-
//
|
13
|
-
//= require_tree .
|
@@ -1,15 +0,0 @@
|
|
1
|
-
/*
|
2
|
-
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
-
* listed below.
|
4
|
-
*
|
5
|
-
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
-
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
-
*
|
8
|
-
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
-
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
-
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
-
* It is generally better to create a new file per style scope.
|
12
|
-
*
|
13
|
-
*= require_tree .
|
14
|
-
*= require_self
|
15
|
-
*/
|
@@ -1,80 +0,0 @@
|
|
1
|
-
body {
|
2
|
-
background-color: #fff;
|
3
|
-
color: #333;
|
4
|
-
margin: 33px;
|
5
|
-
}
|
6
|
-
|
7
|
-
body, p, ol, ul, td {
|
8
|
-
font-family: verdana, arial, helvetica, sans-serif;
|
9
|
-
font-size: 13px;
|
10
|
-
line-height: 18px;
|
11
|
-
}
|
12
|
-
|
13
|
-
pre {
|
14
|
-
background-color: #eee;
|
15
|
-
padding: 10px;
|
16
|
-
font-size: 11px;
|
17
|
-
}
|
18
|
-
|
19
|
-
a {
|
20
|
-
color: #000;
|
21
|
-
}
|
22
|
-
|
23
|
-
a:visited {
|
24
|
-
color: #666;
|
25
|
-
}
|
26
|
-
|
27
|
-
a:hover {
|
28
|
-
color: #fff;
|
29
|
-
background-color: #000;
|
30
|
-
}
|
31
|
-
|
32
|
-
th {
|
33
|
-
padding-bottom: 5px;
|
34
|
-
}
|
35
|
-
|
36
|
-
td {
|
37
|
-
padding: 0 5px 7px;
|
38
|
-
}
|
39
|
-
|
40
|
-
div.field,
|
41
|
-
div.actions {
|
42
|
-
margin-bottom: 10px;
|
43
|
-
}
|
44
|
-
|
45
|
-
#notice {
|
46
|
-
color: green;
|
47
|
-
}
|
48
|
-
|
49
|
-
.field_with_errors {
|
50
|
-
padding: 2px;
|
51
|
-
background-color: red;
|
52
|
-
display: table;
|
53
|
-
}
|
54
|
-
|
55
|
-
#error_explanation {
|
56
|
-
width: 450px;
|
57
|
-
border: 2px solid red;
|
58
|
-
padding: 7px 7px 0;
|
59
|
-
margin-bottom: 20px;
|
60
|
-
background-color: #f0f0f0;
|
61
|
-
}
|
62
|
-
|
63
|
-
#error_explanation h2 {
|
64
|
-
text-align: left;
|
65
|
-
font-weight: bold;
|
66
|
-
padding: 5px 5px 5px 15px;
|
67
|
-
font-size: 12px;
|
68
|
-
margin: -7px -7px 0;
|
69
|
-
background-color: #c00;
|
70
|
-
color: #fff;
|
71
|
-
}
|
72
|
-
|
73
|
-
#error_explanation ul li {
|
74
|
-
font-size: 12px;
|
75
|
-
list-style: square;
|
76
|
-
}
|
77
|
-
|
78
|
-
label {
|
79
|
-
display: block;
|
80
|
-
}
|
@@ -1,134 +0,0 @@
|
|
1
|
-
require_dependency "saml_camel/application_controller"
|
2
|
-
|
3
|
-
module SamlCamel::SamlHelpers
|
4
|
-
extend ActiveSupport::Concern
|
5
|
-
SP_SETTINGS = JSON.parse(File.read("saml/#{Rails.env}/settings.json"))
|
6
|
-
|
7
|
-
#this generates a call to the idp, which will then be returned to the consume action the in saml_contorller
|
8
|
-
def saml_request(host_request)
|
9
|
-
request = OneLogin::RubySaml::Authrequest.new
|
10
|
-
assign_permit_key
|
11
|
-
lifetime = SP_SETTINGS['settings']["sp_session_lifetime"]
|
12
|
-
permit_key = session[:saml_session_id].to_sym
|
13
|
-
|
14
|
-
#store ip address and original url request in memory to be used for verification and redirect after response
|
15
|
-
Rails.cache.fetch(permit_key, expires_in: lifetime.hours) do
|
16
|
-
{ip_address: host_request.remote_ip, redirect_url: host_request.url }
|
17
|
-
end
|
18
|
-
|
19
|
-
saml_request_url = request.create(SamlCamel::Transaction.saml_settings)
|
20
|
-
redirect_to(saml_request_url)
|
21
|
-
end
|
22
|
-
|
23
|
-
|
24
|
-
#ensures that a saml response can not be used more than once.
|
25
|
-
#stores response ids and checks to see if the response id has already been used.
|
26
|
-
def duplicate_response_id?(response_id)
|
27
|
-
ids = Rails.cache.fetch("response_ids")
|
28
|
-
if ids
|
29
|
-
if ids.include?(response_id)
|
30
|
-
session[:sp_session] = nil
|
31
|
-
raise "SAML response ID already issued."
|
32
|
-
else
|
33
|
-
ids << response_id
|
34
|
-
Rails.cache.fetch("response_ids", expires_in: 1.hours) do
|
35
|
-
ids
|
36
|
-
end
|
37
|
-
end
|
38
|
-
else
|
39
|
-
Rails.cache.fetch("response_ids", expires_in: 1.hours) do
|
40
|
-
[]
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def set_saml_session_lifetime(permit_key)
|
46
|
-
user_saml_cache = Rails.cache.fetch(permit_key)
|
47
|
-
user_saml_cache[:session_start_time] = Time.now
|
48
|
-
Rails.cache.fetch(permit_key, expires_in: 8.hours) do
|
49
|
-
user_saml_cache
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
|
54
|
-
#Make it so sp sessions only last 1 hour, sp_session is set on a succesfull saml response.
|
55
|
-
#We check that the session time is less than in hour if so we refresh, otherwise we delete the session
|
56
|
-
def expired_session?
|
57
|
-
permit_key = session[:saml_session_id].to_sym
|
58
|
-
user_cache = Rails.cache.fetch(permit_key)
|
59
|
-
cache_available?(user_cache)
|
60
|
-
|
61
|
-
sp_timeout = SP_SETTINGS["settings"]["sp_session_timeout"]
|
62
|
-
sp_lifetime = SP_SETTINGS['settings']["sp_session_lifetime"]
|
63
|
-
|
64
|
-
set_saml_session_lifetime(permit_key) if user_cache[:session_start_time].nil?
|
65
|
-
sp_session_init_time = user_cache[:session_start_time]
|
66
|
-
|
67
|
-
if session[:sp_session]
|
68
|
-
#if the session has timed out remove session, otherwise refresh
|
69
|
-
if (Time.now - Time.parse(session[:sp_session])) < sp_timeout.hour
|
70
|
-
session[:sp_session] = Time.now
|
71
|
-
else
|
72
|
-
SamlCamel::Logging.expired_session(session[:saml_attributes])
|
73
|
-
session[:sp_session] = nil
|
74
|
-
end
|
75
|
-
|
76
|
-
#if the session has exceeded the allowed lifetime, remove session
|
77
|
-
if (Time.now - sp_session_init_time) > sp_lifetime.hour
|
78
|
-
SamlCamel::Logging.expired_session(session[:saml_attributes])
|
79
|
-
session[:sp_session] = nil
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
|
85
|
-
def valid_ip?(remote_ip)
|
86
|
-
permit_key = session[:saml_session_id].to_sym
|
87
|
-
saml_cache = Rails.cache.fetch(permit_key)
|
88
|
-
cache_available?(saml_cache)
|
89
|
-
unless remote_ip == saml_cache[:ip_address]
|
90
|
-
SamlCamel::Logging.bad_ip(session[:saml_attributes], saml_cache[:ip_address], remote_ip)
|
91
|
-
session[:sp_session] = nil
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
|
96
|
-
#saml_protect is what is called in the app. it initiates the saml request if there is no active session, or if a user has been idle for over an hour
|
97
|
-
def saml_protect
|
98
|
-
user_cache = cache_available?(Rails.cache.fetch(session[:saml_session_id]))
|
99
|
-
if session[:saml_session_id] && user_cache
|
100
|
-
#sets session[:sp_session] to nil if expired, of if the ip adress changes
|
101
|
-
|
102
|
-
expired_session?
|
103
|
-
valid_ip?(request.remote_ip)
|
104
|
-
saml_request(request) unless (session[:saml_response_success] || session[:sp_session])
|
105
|
-
else
|
106
|
-
saml_request(request)
|
107
|
-
end
|
108
|
-
session[:saml_response_success] = nil #keeps us from looping
|
109
|
-
end
|
110
|
-
|
111
|
-
|
112
|
-
def cache_available?(app_cache)
|
113
|
-
if app_cache
|
114
|
-
true
|
115
|
-
else
|
116
|
-
session[:sp_session] = nil
|
117
|
-
false
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
|
122
|
-
def verify_sha_type(response)
|
123
|
-
raw_xml_string = response.decrypted_document.to_s
|
124
|
-
attr_scan = raw_xml_string.scan(/<ds:SignatureMethod.*\/>/)
|
125
|
-
is_sha1 = attr_scan[0].match("sha1")
|
126
|
-
|
127
|
-
raise "SHA1 algorithm not supported " if is_sha1
|
128
|
-
end
|
129
|
-
|
130
|
-
def assign_permit_key
|
131
|
-
session[:saml_session_id] = SecureRandom.base64.chomp.gsub( /\W/, '' )
|
132
|
-
end
|
133
|
-
|
134
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
module SamlCamel
|
2
|
-
class Logging
|
3
|
-
SP_SETTINGS = JSON.parse(File.read("saml/#{Rails.env}/settings.json"))
|
4
|
-
PRIMARY_ID = SP_SETTINGS["settings"]["primary_id"]
|
5
|
-
SHOULD_LOG = SP_SETTINGS["settings"]["saml_logging"]
|
6
|
-
|
7
|
-
def self.successfull_auth(saml_attrs)
|
8
|
-
logger = Logger.new("log/saml.log")
|
9
|
-
logger.info("#{saml_attrs[PRIMARY_ID]} has succesfully authenticated.")
|
10
|
-
rescue
|
11
|
-
logger.debug("Unknown Error During successfull_auth logging. Check PRIMARY_ID configured in settings.json and that user has attribute.")
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.auth_failure(error_context)
|
15
|
-
logger = Logger.new("log/saml.log")
|
16
|
-
logger.error("An error occured during authentication. #{error_context}")
|
17
|
-
logger.error("Backtrace: \n\t\t#{error_context.backtrace.join("\n\t\t")}")
|
18
|
-
rescue
|
19
|
-
logger.debug("Unknown Error During auth_failure logging.")
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.logout(saml_attrs)
|
23
|
-
logger = Logger.new("log/saml.log")
|
24
|
-
logger.info("#{saml_attrs[PRIMARY_ID]} has succesfully logged out.")
|
25
|
-
rescue
|
26
|
-
logger.debug("Unknown error logging user logout. Most likely anonymous user clicked a logout button.")
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.expired_session(saml_attrs)
|
30
|
-
logger = Logger.new("log/saml.log")
|
31
|
-
logger.info("Session Expired for #{saml_attrs[PRIMARY_ID]}")
|
32
|
-
rescue
|
33
|
-
logger.debug("Unknown Error During relay state logging.")
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.bad_ip(saml_attrs,request_ip,current_ip)
|
37
|
-
logger = Logger.new("log/saml.log")
|
38
|
-
logger.info("Bad IP address for #{saml_attrs[PRIMARY_ID]}. IP at SAML request #{request_ip} | IP presented #{current_ip}")
|
39
|
-
rescue
|
40
|
-
logger.debug("Unknown Error During relay state logging.")
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.saml_state(data)
|
44
|
-
logger = Logger.new("log/saml.log")
|
45
|
-
logger.info("Stored Relay: #{data[:stored_relay]} | RequestRelay: #{data[:request_relay]} | Stored IP: #{data[:stored_ip]} RemoteIP: #{data[:remote_ip]}")
|
46
|
-
rescue
|
47
|
-
logger.debug("Unknown Error During relay state logging.")
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module SamlCamel
|
2
|
-
class Transaction
|
3
|
-
SP_SETTINGS = JSON.parse(File.read("saml/#{Rails.env}/settings.json"))
|
4
|
-
|
5
|
-
def self.saml_settings
|
6
|
-
sp_settings = SP_SETTINGS["settings"]
|
7
|
-
settings = OneLogin::RubySaml::Settings.new
|
8
|
-
settings.assertion_consumer_service_url = sp_settings["acs"]
|
9
|
-
|
10
|
-
|
11
|
-
settings.issuer = sp_settings["entity_id"]
|
12
|
-
settings.idp_sso_target_url = sp_settings["sso_url"]
|
13
|
-
|
14
|
-
|
15
|
-
# certificate to register with IDP and key to decrypt
|
16
|
-
settings.certificate = File.read("saml/#{Rails.env}/saml_certificate.crt")
|
17
|
-
|
18
|
-
# certificate to decrypt SAML response
|
19
|
-
settings.private_key = File.read("saml/#{Rails.env}/saml_key.key")
|
20
|
-
|
21
|
-
# certificate to verify IDP signature
|
22
|
-
settings.idp_cert = File.read("saml/#{Rails.env}/idp_certificate.crt")
|
23
|
-
|
24
|
-
|
25
|
-
#TODO test by modding relying party duke-coi-smart example
|
26
|
-
settings.security[:digest_method] = XMLSecurity::Document::SHA256
|
27
|
-
settings.security[:signature_method] = XMLSecurity::Document::RSA_SHA256
|
28
|
-
|
29
|
-
# Optional for most SAML IdPs
|
30
|
-
settings.authn_context = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
|
31
|
-
settings.attribute_consuming_service.configure do
|
32
|
-
service_name "Service"
|
33
|
-
service_index 5
|
34
|
-
add_attribute :redirect_path => "root_path"
|
35
|
-
end
|
36
|
-
settings
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.map_attributes(attrs)
|
40
|
-
attr_map = SP_SETTINGS["attribute_map"]
|
41
|
-
mapped_attributes = {}
|
42
|
-
|
43
|
-
attrs.each do |attr,value|
|
44
|
-
mapped_name = attr_map[attr]
|
45
|
-
if mapped_name.nil? #handles attributes not in map
|
46
|
-
mapped_attributes[attr] = value
|
47
|
-
else
|
48
|
-
mapped_attributes[mapped_name] = value
|
49
|
-
end
|
50
|
-
end
|
51
|
-
mapped_attributes
|
52
|
-
end
|
53
|
-
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|