saml_camel 0.2.2 → 0.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|