icn_saml_idp 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +2 -0
- data/LICENSE +22 -0
- data/README.md +238 -0
- data/app/controllers/saml_idp/idp_controller.rb +53 -0
- data/app/views/saml_idp/idp/new.html.erb +22 -0
- data/app/views/saml_idp/idp/saml_post.html.erb +14 -0
- data/lib/saml_idp.rb +92 -0
- data/lib/saml_idp/algorithmable.rb +19 -0
- data/lib/saml_idp/assertion_builder.rb +172 -0
- data/lib/saml_idp/attribute_decorator.rb +27 -0
- data/lib/saml_idp/attributeable.rb +24 -0
- data/lib/saml_idp/configurator.rb +48 -0
- data/lib/saml_idp/controller.rb +128 -0
- data/lib/saml_idp/default.rb +49 -0
- data/lib/saml_idp/encryptor.rb +86 -0
- data/lib/saml_idp/engine.rb +5 -0
- data/lib/saml_idp/hashable.rb +26 -0
- data/lib/saml_idp/incoming_metadata.rb +144 -0
- data/lib/saml_idp/logout_builder.rb +42 -0
- data/lib/saml_idp/logout_request_builder.rb +34 -0
- data/lib/saml_idp/logout_response_builder.rb +35 -0
- data/lib/saml_idp/metadata_builder.rb +160 -0
- data/lib/saml_idp/name_id_formatter.rb +68 -0
- data/lib/saml_idp/persisted_metadata.rb +10 -0
- data/lib/saml_idp/request.rb +180 -0
- data/lib/saml_idp/response_builder.rb +62 -0
- data/lib/saml_idp/saml_response.rb +79 -0
- data/lib/saml_idp/service_provider.rb +76 -0
- data/lib/saml_idp/signable.rb +131 -0
- data/lib/saml_idp/signature_builder.rb +42 -0
- data/lib/saml_idp/signed_info_builder.rb +88 -0
- data/lib/saml_idp/version.rb +4 -0
- data/lib/saml_idp/xml_security.rb +181 -0
- data/saml_idp.gemspec +65 -0
- data/spec/acceptance/acceptance_helper.rb +9 -0
- data/spec/acceptance/idp_controller_spec.rb +16 -0
- data/spec/lib/saml_idp/algorithmable_spec.rb +48 -0
- data/spec/lib/saml_idp/assertion_builder_spec.rb +106 -0
- data/spec/lib/saml_idp/attribute_decorator_spec.rb +53 -0
- data/spec/lib/saml_idp/configurator_spec.rb +43 -0
- data/spec/lib/saml_idp/controller_spec.rb +94 -0
- data/spec/lib/saml_idp/encryptor_spec.rb +27 -0
- data/spec/lib/saml_idp/logout_request_builder_spec.rb +41 -0
- data/spec/lib/saml_idp/logout_response_builder_spec.rb +41 -0
- data/spec/lib/saml_idp/metadata_builder_spec.rb +19 -0
- data/spec/lib/saml_idp/name_id_formatter_spec.rb +42 -0
- data/spec/lib/saml_idp/request_spec.rb +106 -0
- data/spec/lib/saml_idp/response_builder_spec.rb +42 -0
- data/spec/lib/saml_idp/saml_response_spec.rb +68 -0
- data/spec/lib/saml_idp/service_provider_spec.rb +27 -0
- data/spec/lib/saml_idp/signable_spec.rb +77 -0
- data/spec/lib/saml_idp/signature_builder_spec.rb +19 -0
- data/spec/lib/saml_idp/signed_info_builder_spec.rb +25 -0
- data/spec/rails_app/.gitignore +15 -0
- data/spec/rails_app/README.rdoc +261 -0
- data/spec/rails_app/Rakefile +7 -0
- data/spec/rails_app/app/assets/images/rails.png +0 -0
- data/spec/rails_app/app/assets/javascripts/application.js +15 -0
- data/spec/rails_app/app/assets/stylesheets/application.css +13 -0
- data/spec/rails_app/app/controllers/application_controller.rb +3 -0
- data/spec/rails_app/app/controllers/saml_controller.rb +8 -0
- data/spec/rails_app/app/controllers/saml_idp_controller.rb +11 -0
- data/spec/rails_app/app/helpers/application_helper.rb +2 -0
- data/spec/rails_app/app/mailers/.gitkeep +0 -0
- data/spec/rails_app/app/models/.gitkeep +0 -0
- data/spec/rails_app/app/views/layouts/application.html.erb +14 -0
- data/spec/rails_app/config.ru +4 -0
- data/spec/rails_app/config/application.rb +60 -0
- data/spec/rails_app/config/boot.rb +6 -0
- data/spec/rails_app/config/database.yml +25 -0
- data/spec/rails_app/config/environment.rb +5 -0
- data/spec/rails_app/config/environments/development.rb +37 -0
- data/spec/rails_app/config/environments/production.rb +67 -0
- data/spec/rails_app/config/environments/test.rb +37 -0
- data/spec/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails_app/config/initializers/inflections.rb +15 -0
- data/spec/rails_app/config/initializers/mime_types.rb +5 -0
- data/spec/rails_app/config/initializers/secret_token.rb +7 -0
- data/spec/rails_app/config/initializers/session_store.rb +8 -0
- data/spec/rails_app/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails_app/config/locales/en.yml +5 -0
- data/spec/rails_app/config/routes.rb +6 -0
- data/spec/rails_app/db/seeds.rb +7 -0
- data/spec/rails_app/doc/README_FOR_APP +2 -0
- data/spec/rails_app/lib/assets/.gitkeep +0 -0
- data/spec/rails_app/lib/tasks/.gitkeep +0 -0
- data/spec/rails_app/log/.gitkeep +0 -0
- data/spec/rails_app/public/404.html +26 -0
- data/spec/rails_app/public/422.html +26 -0
- data/spec/rails_app/public/500.html +25 -0
- data/spec/rails_app/public/favicon.ico +0 -0
- data/spec/rails_app/public/index.html +241 -0
- data/spec/rails_app/public/robots.txt +5 -0
- data/spec/rails_app/script/rails +6 -0
- data/spec/rails_app/test/fixtures/.gitkeep +0 -0
- data/spec/rails_app/test/functional/.gitkeep +0 -0
- data/spec/rails_app/test/integration/.gitkeep +0 -0
- data/spec/rails_app/test/performance/browsing_test.rb +12 -0
- data/spec/rails_app/test/test_helper.rb +13 -0
- data/spec/rails_app/test/unit/.gitkeep +0 -0
- data/spec/rails_app/vendor/assets/javascripts/.gitkeep +0 -0
- data/spec/rails_app/vendor/assets/stylesheets/.gitkeep +0 -0
- data/spec/rails_app/vendor/plugins/.gitkeep +0 -0
- data/spec/spec_helper.rb +49 -0
- data/spec/support/certificates/certificate1 +12 -0
- data/spec/support/certificates/r1_certificate2_base64 +1 -0
- data/spec/support/responses/adfs_response_sha1.xml +46 -0
- data/spec/support/responses/adfs_response_sha256.xml +46 -0
- data/spec/support/responses/adfs_response_sha384.xml +46 -0
- data/spec/support/responses/adfs_response_sha512.xml +46 -0
- data/spec/support/responses/logoutresponse_fixtures.rb +67 -0
- data/spec/support/responses/no_signature_ns.xml +48 -0
- data/spec/support/responses/open_saml_response.xml +56 -0
- data/spec/support/responses/r1_response6.xml.base64 +1 -0
- data/spec/support/responses/response1.xml.base64 +1 -0
- data/spec/support/responses/response2.xml.base64 +79 -0
- data/spec/support/responses/response3.xml.base64 +66 -0
- data/spec/support/responses/response4.xml.base64 +93 -0
- data/spec/support/responses/response5.xml.base64 +102 -0
- data/spec/support/responses/response_with_ampersands.xml +139 -0
- data/spec/support/responses/response_with_ampersands.xml.base64 +93 -0
- data/spec/support/responses/simple_saml_php.xml +71 -0
- data/spec/support/responses/starfield_response.xml.base64 +1 -0
- data/spec/support/responses/wrapped_response_2.xml.base64 +150 -0
- data/spec/support/saml_request_macros.rb +38 -0
- data/spec/support/security_helpers.rb +61 -0
- data/spec/xml_security_spec.rb +137 -0
- metadata +465 -0
@@ -0,0 +1,19 @@
|
|
1
|
+
module SamlIdp
|
2
|
+
module Algorithmable
|
3
|
+
def algorithm
|
4
|
+
algorithm_check = raw_algorithm || SamlIdp.config.algorithm
|
5
|
+
return algorithm_check if algorithm_check.respond_to?(:digest)
|
6
|
+
begin
|
7
|
+
OpenSSL::Digest.const_get(algorithm_check.to_s.upcase)
|
8
|
+
rescue NameError
|
9
|
+
OpenSSL::Digest::SHA1
|
10
|
+
end
|
11
|
+
end
|
12
|
+
private :algorithm
|
13
|
+
|
14
|
+
def algorithm_name
|
15
|
+
algorithm.to_s.split('::').last.downcase
|
16
|
+
end
|
17
|
+
private :algorithm_name
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,172 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'saml_idp/algorithmable'
|
3
|
+
require 'saml_idp/signable'
|
4
|
+
module SamlIdp
|
5
|
+
class AssertionBuilder
|
6
|
+
include Algorithmable
|
7
|
+
include Signable
|
8
|
+
attr_accessor :reference_id
|
9
|
+
attr_accessor :issuer_uri
|
10
|
+
attr_accessor :principal
|
11
|
+
attr_accessor :audience_uri
|
12
|
+
attr_accessor :saml_request_id
|
13
|
+
attr_accessor :saml_acs_url
|
14
|
+
attr_accessor :raw_algorithm
|
15
|
+
attr_accessor :authn_context_classref
|
16
|
+
attr_accessor :expiry
|
17
|
+
attr_accessor :encryption_opts
|
18
|
+
|
19
|
+
delegate :config, to: :SamlIdp
|
20
|
+
|
21
|
+
def initialize(reference_id, issuer_uri, principal, audience_uri, saml_request_id, saml_acs_url, raw_algorithm, authn_context_classref, expiry=60*60, encryption_opts=nil)
|
22
|
+
self.reference_id = reference_id
|
23
|
+
self.issuer_uri = issuer_uri
|
24
|
+
self.principal = principal
|
25
|
+
self.audience_uri = audience_uri
|
26
|
+
self.saml_request_id = saml_request_id
|
27
|
+
self.saml_acs_url = saml_acs_url
|
28
|
+
self.raw_algorithm = raw_algorithm
|
29
|
+
self.authn_context_classref = authn_context_classref
|
30
|
+
self.expiry = expiry
|
31
|
+
self.encryption_opts = encryption_opts
|
32
|
+
end
|
33
|
+
|
34
|
+
def fresh
|
35
|
+
builder = Builder::XmlMarkup.new
|
36
|
+
builder.Assertion xmlns: Saml::XML::Namespaces::ASSERTION,
|
37
|
+
ID: reference_string,
|
38
|
+
IssueInstant: now_iso,
|
39
|
+
Version: "2.0" do |assertion|
|
40
|
+
assertion.Issuer issuer_uri
|
41
|
+
sign assertion
|
42
|
+
assertion.Subject do |subject|
|
43
|
+
subject.NameID name_id, Format: name_id_format[:name]
|
44
|
+
subject.SubjectConfirmation Method: Saml::XML::Namespaces::Methods::BEARER do |confirmation|
|
45
|
+
confirmation_hash = {}
|
46
|
+
confirmation_hash[:InResponseTo] = saml_request_id unless saml_request_id.nil?
|
47
|
+
confirmation_hash[:NotOnOrAfter] = not_on_or_after_subject
|
48
|
+
confirmation_hash[:Recipient] = saml_acs_url
|
49
|
+
|
50
|
+
confirmation.SubjectConfirmationData "", confirmation_hash
|
51
|
+
end
|
52
|
+
end
|
53
|
+
assertion.Conditions NotBefore: not_before, NotOnOrAfter: not_on_or_after_condition do |conditions|
|
54
|
+
conditions.AudienceRestriction do |restriction|
|
55
|
+
restriction.Audience audience_uri
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if asserted_attributes
|
59
|
+
assertion.AttributeStatement do |attr_statement|
|
60
|
+
asserted_attributes.each do |friendly_name, attrs|
|
61
|
+
attrs = (attrs || {}).with_indifferent_access
|
62
|
+
attr_statement.Attribute Name: attrs[:name] || friendly_name,
|
63
|
+
NameFormat: attrs[:name_format] || Saml::XML::Namespaces::Formats::Attr::URI,
|
64
|
+
FriendlyName: friendly_name.to_s do |attr|
|
65
|
+
values = get_values_for friendly_name, attrs[:getter]
|
66
|
+
values.each do |val|
|
67
|
+
attr.AttributeValue val.to_s
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
assertion.AuthnStatement AuthnInstant: now_iso, SessionIndex: reference_string do |statement|
|
74
|
+
statement.AuthnContext do |context|
|
75
|
+
context.AuthnContextClassRef authn_context_classref
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
alias_method :raw, :fresh
|
81
|
+
private :fresh
|
82
|
+
|
83
|
+
def encrypt(opts = {})
|
84
|
+
raise "Must set encryption_opts to encrypt" unless encryption_opts
|
85
|
+
raw_xml = opts[:sign] ? signed : raw
|
86
|
+
require 'saml_idp/encryptor'
|
87
|
+
encryptor = Encryptor.new encryption_opts
|
88
|
+
encryptor.encrypt(raw_xml)
|
89
|
+
end
|
90
|
+
|
91
|
+
def asserted_attributes
|
92
|
+
if principal.respond_to?(:asserted_attributes)
|
93
|
+
principal.send(:asserted_attributes)
|
94
|
+
elsif !config.attributes.nil? && !config.attributes.empty?
|
95
|
+
config.attributes
|
96
|
+
end
|
97
|
+
end
|
98
|
+
private :asserted_attributes
|
99
|
+
|
100
|
+
def get_values_for(friendly_name, getter)
|
101
|
+
result = nil
|
102
|
+
if getter.present?
|
103
|
+
if getter.respond_to?(:call)
|
104
|
+
result = getter.call(principal)
|
105
|
+
else
|
106
|
+
message = getter.to_s.underscore
|
107
|
+
result = principal.public_send(message) if principal.respond_to?(message)
|
108
|
+
end
|
109
|
+
elsif getter.nil?
|
110
|
+
message = friendly_name.to_s.underscore
|
111
|
+
result = principal.public_send(message) if principal.respond_to?(message)
|
112
|
+
end
|
113
|
+
Array(result)
|
114
|
+
end
|
115
|
+
private :get_values_for
|
116
|
+
|
117
|
+
def name_id
|
118
|
+
name_id_getter.call principal
|
119
|
+
end
|
120
|
+
private :name_id
|
121
|
+
|
122
|
+
def name_id_getter
|
123
|
+
getter = name_id_format[:getter]
|
124
|
+
if getter.respond_to? :call
|
125
|
+
getter
|
126
|
+
else
|
127
|
+
->(principal) { principal.public_send getter.to_s }
|
128
|
+
end
|
129
|
+
end
|
130
|
+
private :name_id_getter
|
131
|
+
|
132
|
+
def name_id_format
|
133
|
+
@name_id_format ||= NameIdFormatter.new(config.name_id.formats).chosen
|
134
|
+
end
|
135
|
+
private :name_id_format
|
136
|
+
|
137
|
+
def reference_string
|
138
|
+
"_#{reference_id}"
|
139
|
+
end
|
140
|
+
private :reference_string
|
141
|
+
|
142
|
+
def now
|
143
|
+
@now ||= Time.now.utc
|
144
|
+
end
|
145
|
+
private :now
|
146
|
+
|
147
|
+
def now_iso
|
148
|
+
iso { now }
|
149
|
+
end
|
150
|
+
private :now_iso
|
151
|
+
|
152
|
+
def not_before
|
153
|
+
iso { now - 5 }
|
154
|
+
end
|
155
|
+
private :not_before
|
156
|
+
|
157
|
+
def not_on_or_after_condition
|
158
|
+
iso { now + expiry }
|
159
|
+
end
|
160
|
+
private :not_on_or_after_condition
|
161
|
+
|
162
|
+
def not_on_or_after_subject
|
163
|
+
iso { now + 3 * 60 }
|
164
|
+
end
|
165
|
+
private :not_on_or_after_subject
|
166
|
+
|
167
|
+
def iso
|
168
|
+
yield.iso8601
|
169
|
+
end
|
170
|
+
private :iso
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
module SamlIdp
|
3
|
+
class AttributeDecorator < SimpleDelegator
|
4
|
+
alias_method :source, :__getobj__
|
5
|
+
|
6
|
+
def initialize(*)
|
7
|
+
super
|
8
|
+
__setobj__((source || {}).with_indifferent_access)
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
source[:name]
|
13
|
+
end
|
14
|
+
|
15
|
+
def friendly_name
|
16
|
+
source[:friendly_name]
|
17
|
+
end
|
18
|
+
|
19
|
+
def name_format
|
20
|
+
source[:name_format] || Saml::XML::Namespaces::Formats::Attr::URI
|
21
|
+
end
|
22
|
+
|
23
|
+
def values
|
24
|
+
Array(source[:values])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module SamlIdp
|
2
|
+
module Attributeable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
def initialize(attributes = {})
|
6
|
+
self.attributes = attributes
|
7
|
+
end
|
8
|
+
|
9
|
+
def attributes
|
10
|
+
@attributes ||= {}.with_indifferent_access
|
11
|
+
end
|
12
|
+
|
13
|
+
def attributes=(new_attributes)
|
14
|
+
@attributes = (new_attributes || {}).with_indifferent_access
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def attribute(att)
|
19
|
+
define_method(att) { attributes[att] }
|
20
|
+
define_method("#{att}=") { |new_value| self.attributes[att] = new_value }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'ostruct'
|
3
|
+
module SamlIdp
|
4
|
+
class Configurator
|
5
|
+
attr_accessor :x509_certificate
|
6
|
+
attr_accessor :secret_key
|
7
|
+
attr_accessor :password
|
8
|
+
attr_accessor :algorithm
|
9
|
+
attr_accessor :organization_name
|
10
|
+
attr_accessor :organization_url
|
11
|
+
attr_accessor :base_saml_location
|
12
|
+
attr_accessor :entity_id
|
13
|
+
attr_accessor :reference_id_generator
|
14
|
+
attr_accessor :attribute_service_location
|
15
|
+
attr_accessor :single_service_post_location
|
16
|
+
attr_accessor :single_logout_service_post_location
|
17
|
+
attr_accessor :attributes
|
18
|
+
attr_accessor :service_provider
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
self.x509_certificate = Default::X509_CERTIFICATE
|
22
|
+
self.secret_key = Default::SECRET_KEY
|
23
|
+
self.algorithm = :sha1
|
24
|
+
self.reference_id_generator = ->() { UUID.generate }
|
25
|
+
self.service_provider = OpenStruct.new
|
26
|
+
self.service_provider.finder = ->(_) { Default::SERVICE_PROVIDER }
|
27
|
+
self.service_provider.metadata_persister = ->(id, settings) { }
|
28
|
+
self.service_provider.persisted_metadata_getter = ->(id, service_provider) { }
|
29
|
+
self.attributes = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
# formats
|
33
|
+
# getter
|
34
|
+
def name_id
|
35
|
+
@name_id ||= OpenStruct.new
|
36
|
+
end
|
37
|
+
|
38
|
+
def technical_contact
|
39
|
+
@technical_contact ||= TechnicalContact.new
|
40
|
+
end
|
41
|
+
|
42
|
+
class TechnicalContact < OpenStruct
|
43
|
+
def mail_to_string
|
44
|
+
"mailto:#{email_address}" if email_address.to_s.length > 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'openssl'
|
3
|
+
require 'base64'
|
4
|
+
require 'time'
|
5
|
+
require 'uuid'
|
6
|
+
require 'saml_idp/request'
|
7
|
+
require 'saml_idp/logout_response_builder'
|
8
|
+
module SamlIdp
|
9
|
+
module Controller
|
10
|
+
extend ActiveSupport::Concern
|
11
|
+
|
12
|
+
included do
|
13
|
+
helper_method :saml_acs_url if respond_to? :helper_method
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_accessor :algorithm
|
17
|
+
|
18
|
+
protected
|
19
|
+
|
20
|
+
def saml_request
|
21
|
+
@saml_request ||= Struct.new(:request_id) do
|
22
|
+
def authn_request?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
def issuer
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def acs_url
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end.new(nil)
|
34
|
+
end
|
35
|
+
|
36
|
+
def validate_saml_request(raw_saml_request = params[:SAMLRequest])
|
37
|
+
decode_request(raw_saml_request)
|
38
|
+
render nothing: true, status: :forbidden unless valid_saml_request?
|
39
|
+
end
|
40
|
+
|
41
|
+
def decode_request(raw_saml_request)
|
42
|
+
@saml_request = Request.from_deflated_request(raw_saml_request)
|
43
|
+
end
|
44
|
+
|
45
|
+
def authn_context_classref
|
46
|
+
Saml::XML::Namespaces::AuthnContext::ClassRef::PASSWORD
|
47
|
+
end
|
48
|
+
|
49
|
+
def encode_authn_response(principal, opts = {})
|
50
|
+
response_id = get_saml_response_id
|
51
|
+
reference_id = opts[:reference_id] || get_saml_reference_id
|
52
|
+
audience_uri = opts[:audience_uri] || saml_request.issuer || saml_acs_url[/^(.*?\/\/.*?\/)/, 1]
|
53
|
+
opt_issuer_uri = opts[:issuer_uri] || issuer_uri
|
54
|
+
my_authn_context_classref = opts[:authn_context_classref] || authn_context_classref
|
55
|
+
acs_url = opts[:acs_url] || saml_acs_url
|
56
|
+
expiry = opts[:expiry] || 60*60
|
57
|
+
encryption_opts = opts[:encryption] || nil
|
58
|
+
|
59
|
+
SamlResponse.new(
|
60
|
+
reference_id,
|
61
|
+
response_id,
|
62
|
+
opt_issuer_uri,
|
63
|
+
principal,
|
64
|
+
audience_uri,
|
65
|
+
saml_request_id,
|
66
|
+
acs_url,
|
67
|
+
(opts[:algorithm] || algorithm || default_algorithm),
|
68
|
+
my_authn_context_classref,
|
69
|
+
expiry,
|
70
|
+
encryption_opts
|
71
|
+
).build
|
72
|
+
end
|
73
|
+
|
74
|
+
def encode_logout_response(principal, opts = {})
|
75
|
+
SamlIdp::LogoutResponseBuilder.new(
|
76
|
+
get_saml_response_id,
|
77
|
+
(opts[:issuer_uri] || issuer_uri),
|
78
|
+
saml_logout_url,
|
79
|
+
saml_request_id,
|
80
|
+
(opts[:algorithm] || algorithm || default_algorithm)
|
81
|
+
).signed
|
82
|
+
end
|
83
|
+
|
84
|
+
def encode_response(principal, opts = {})
|
85
|
+
if saml_request.authn_request?
|
86
|
+
encode_authn_response(principal, opts)
|
87
|
+
elsif saml_request.logout_request?
|
88
|
+
encode_logout_response(principal, opts)
|
89
|
+
else
|
90
|
+
raise "Unknown request: #{saml_request}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def issuer_uri
|
95
|
+
(SamlIdp.config.base_saml_location.present? && SamlIdp.config.base_saml_location) ||
|
96
|
+
(defined?(request) && request.url.to_s.split("?").first) ||
|
97
|
+
"http://example.com"
|
98
|
+
end
|
99
|
+
|
100
|
+
def valid_saml_request?
|
101
|
+
saml_request.valid?
|
102
|
+
end
|
103
|
+
|
104
|
+
def saml_request_id
|
105
|
+
saml_request.request_id
|
106
|
+
end
|
107
|
+
|
108
|
+
def saml_acs_url
|
109
|
+
saml_request.acs_url
|
110
|
+
end
|
111
|
+
|
112
|
+
def saml_logout_url
|
113
|
+
saml_request.logout_url
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_saml_response_id
|
117
|
+
UUID.generate
|
118
|
+
end
|
119
|
+
|
120
|
+
def get_saml_reference_id
|
121
|
+
UUID.generate
|
122
|
+
end
|
123
|
+
|
124
|
+
def default_algorithm
|
125
|
+
OpenSSL::Digest::SHA256
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module SamlIdp
|
3
|
+
module Default
|
4
|
+
NAME_ID_FORMAT = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
|
5
|
+
X509_CERTIFICATE = <<EOS.strip
|
6
|
+
MIIDqzCCAxSgAwIBAgIBATANBgkqhkiG9w0BAQsFADCBhjELMAkGA1UEBhMCQVUx
|
7
|
+
DDAKBgNVBAgTA05TVzEPMA0GA1UEBxMGU3lkbmV5MQwwCgYDVQQKDANQSVQxCTAH
|
8
|
+
BgNVBAsMADEYMBYGA1UEAwwPbGF3cmVuY2VwaXQuY29tMSUwIwYJKoZIhvcNAQkB
|
9
|
+
DBZsYXdyZW5jZS5waXRAZ21haWwuY29tMB4XDTEyMDQyODAyMjIyOFoXDTMyMDQy
|
10
|
+
MzAyMjIyOFowgYYxCzAJBgNVBAYTAkFVMQwwCgYDVQQIEwNOU1cxDzANBgNVBAcT
|
11
|
+
BlN5ZG5leTEMMAoGA1UECgwDUElUMQkwBwYDVQQLDAAxGDAWBgNVBAMMD2xhd3Jl
|
12
|
+
bmNlcGl0LmNvbTElMCMGCSqGSIb3DQEJAQwWbGF3cmVuY2UucGl0QGdtYWlsLmNv
|
13
|
+
bTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuBywPNlC1FopGLYfF96SotiK
|
14
|
+
8Nj6/nW084O4omRMifzy7x955RLEy673q2aiJNB3LvE6Xvkt9cGtxtNoOXw1g2Uv
|
15
|
+
HKpldQbr6bOEjLNeDNW7j0ob+JrRvAUOK9CRgdyw5MC6lwqVQQ5C1DnaT/2fSBFj
|
16
|
+
asBFTR24dEpfTy8HfKECAwEAAaOCASUwggEhMAkGA1UdEwQCMAAwCwYDVR0PBAQD
|
17
|
+
AgUgMB0GA1UdDgQWBBQNBGmmt3ytKpcJaBaYNbnyU2xkazATBgNVHSUEDDAKBggr
|
18
|
+
BgEFBQcDATAdBglghkgBhvhCAQ0EEBYOVGVzdCBYNTA5IGNlcnQwgbMGA1UdIwSB
|
19
|
+
qzCBqIAUDQRpprd8rSqXCWgWmDW58lNsZGuhgYykgYkwgYYxCzAJBgNVBAYTAkFV
|
20
|
+
MQwwCgYDVQQIEwNOU1cxDzANBgNVBAcTBlN5ZG5leTEMMAoGA1UECgwDUElUMQkw
|
21
|
+
BwYDVQQLDAAxGDAWBgNVBAMMD2xhd3JlbmNlcGl0LmNvbTElMCMGCSqGSIb3DQEJ
|
22
|
+
AQwWbGF3cmVuY2UucGl0QGdtYWlsLmNvbYIBATANBgkqhkiG9w0BAQsFAAOBgQAE
|
23
|
+
cVUPBX7uZmzqZJfy+tUPOT5ImNQj8VE2lerhnFjnGPHmHIqhpzgnwHQujJfs/a30
|
24
|
+
9Wm5qwcCaC1eO5cWjcG0x3OjdllsgYDatl5GAumtBx8J3NhWRqNUgitCIkQlxHIw
|
25
|
+
UfgQaCushYgDDL5YbIQa++egCgpIZ+T0Dj5oRew//A==
|
26
|
+
EOS
|
27
|
+
FINGERPRINT = "9E:65:2E:03:06:8D:80:F2:86:C7:6C:77:A1:D9:14:97:0A:4D:F4:4D"
|
28
|
+
SECRET_KEY = <<EOS
|
29
|
+
-----BEGIN RSA PRIVATE KEY-----
|
30
|
+
MIICXAIBAAKBgQC4HLA82ULUWikYth8X3pKi2Irw2Pr+dbTzg7iiZEyJ/PLvH3nl
|
31
|
+
EsTLrverZqIk0Hcu8Tpe+S31wa3G02g5fDWDZS8cqmV1Buvps4SMs14M1buPShv4
|
32
|
+
mtG8BQ4r0JGB3LDkwLqXCpVBDkLUOdpP/Z9IEWNqwEVNHbh0Sl9PLwd8oQIDAQAB
|
33
|
+
AoGAQmUGIUtwUEgbXe//kooPc26H3IdDLJSiJtcvtFBbUb/Ik/dT7AoysgltA4DF
|
34
|
+
pGURNfqERE+0BVZNJtCCW4ixew4uEhk1XowYXHCzjkzyYoFuT9v5SP4cu4q3t1kK
|
35
|
+
51JF237F0eCY3qC3k96CzPGG67bwOu9EeXAu4ka/plLdsAECQQDkg0uhR/vsJffx
|
36
|
+
tiWxcDRNFoZpCpzpdWfQBnHBzj9ZC0xrdVilxBgBpupCljO2Scy4MeiY4S1Mleel
|
37
|
+
CWRqh7RBAkEAzkIjUnllEkr5sjVb7pNy+e/eakuDxvZck0Z8X3USUki/Nm3E/GPP
|
38
|
+
c+CwmXR4QlpMpJr3/Prf1j59l/LAK9AwYQJBAL9eRSQYCJ3HXlGKXR6v/NziFEY7
|
39
|
+
oRTSQdIw02ueseZ8U89aQpbwFbqsclq5Ny1duJg5E7WUPj94+rl3mCSu6QECQBVh
|
40
|
+
0duY7htpXl1VHsSq0H6MmVgXn/+eRpaV9grHTjDtjbUMyCEKD9WJc4VVB6qJRezC
|
41
|
+
i/bT4ySIsehwp+9i08ECQEH03lCpHpbwiWH4sD25l/z3g2jCbIZ+RTV6yHIz7Coh
|
42
|
+
gAbBqA04wh64JhhfG69oTBwqwj3imlWF8+jDzV9RNNw=
|
43
|
+
-----END RSA PRIVATE KEY-----
|
44
|
+
EOS
|
45
|
+
SERVICE_PROVIDER = {
|
46
|
+
fingerprint: FINGERPRINT
|
47
|
+
}
|
48
|
+
end
|
49
|
+
end
|