saml-kit 0.2.2 → 0.2.3
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/lib/saml/kit.rb +10 -0
- data/lib/saml/kit/bindings/binding.rb +20 -0
- data/lib/saml/kit/builders.rb +3 -0
- data/lib/saml/kit/builders/assertion.rb +62 -0
- data/lib/saml/kit/builders/authentication_request.rb +15 -10
- data/lib/saml/kit/builders/identity_provider_metadata.rb +7 -54
- data/lib/saml/kit/builders/logout_request.rb +3 -12
- data/lib/saml/kit/builders/logout_response.rb +8 -17
- data/lib/saml/kit/builders/response.rb +8 -120
- data/lib/saml/kit/builders/service_provider_metadata.rb +5 -40
- data/lib/saml/kit/builders/templates/assertion.builder +29 -0
- data/lib/saml/kit/builders/templates/authentication_request.builder +6 -0
- data/lib/saml/kit/builders/templates/certificate.builder +7 -0
- data/lib/saml/kit/builders/templates/identity_provider_metadata.builder +32 -0
- data/lib/saml/kit/builders/templates/logout_request.builder +6 -0
- data/lib/saml/kit/builders/templates/logout_response.builder +8 -0
- data/lib/saml/kit/builders/templates/response.builder +11 -0
- data/lib/saml/kit/builders/templates/service_provider_metadata.builder +29 -0
- data/lib/saml/kit/builders/templates/xml_encryption.builder +16 -0
- data/lib/saml/kit/builders/templates/xml_signature.builder +20 -0
- data/lib/saml/kit/builders/xml_encryption.rb +20 -0
- data/lib/saml/kit/builders/xml_signature.rb +41 -0
- data/lib/saml/kit/certificate.rb +14 -0
- data/lib/saml/kit/composite_metadata.rb +36 -0
- data/lib/saml/kit/configuration.rb +4 -21
- data/lib/saml/kit/metadata.rb +3 -1
- data/lib/saml/kit/requestable.rb +0 -3
- data/lib/saml/kit/signature.rb +8 -50
- data/lib/saml/kit/signatures.rb +28 -0
- data/lib/saml/kit/templatable.rb +33 -0
- data/lib/saml/kit/template.rb +29 -0
- data/lib/saml/kit/version.rb +1 -1
- data/lib/saml/kit/xml_decryption.rb +5 -5
- data/saml-kit.gemspec +1 -0
- metadata +33 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 68d768bf760de038c1d2509056882bdd822d6d9d81449e9b6b3ee55b1f0061b0
|
4
|
+
data.tar.gz: 36ddb0f1d8f7692518e43604bed5505ff5503235b99644e83923049cbc86cf0d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03dec61510539ae84a0fa52e64f0b522d75ae2388a289f657a47480d716913e16d2c52e369b761581c32467e812aec22eb78b50e311518d877a9a891d1d0a2a0
|
7
|
+
data.tar.gz: 687f187faeb6e73c31abe59ec6734f30cb41213262b4c5fdd0fd4dd4ada9d712a7bce27959e92a03ee8ccbe6efc75d2ce8d9ff75d8595e5e87c15e54da0525ba
|
data/lib/saml/kit.rb
CHANGED
@@ -12,9 +12,11 @@ require "logger"
|
|
12
12
|
require "net/http"
|
13
13
|
require "nokogiri"
|
14
14
|
require "securerandom"
|
15
|
+
require "tilt"
|
15
16
|
require "xmldsig"
|
16
17
|
|
17
18
|
require "saml/kit/buildable"
|
19
|
+
require "saml/kit/templatable"
|
18
20
|
require "saml/kit/builders"
|
19
21
|
require "saml/kit/namespaces"
|
20
22
|
require "saml/kit/serializable"
|
@@ -34,6 +36,7 @@ require "saml/kit/fingerprint"
|
|
34
36
|
require "saml/kit/logout_response"
|
35
37
|
require "saml/kit/logout_request"
|
36
38
|
require "saml/kit/metadata"
|
39
|
+
require "saml/kit/composite_metadata"
|
37
40
|
require "saml/kit/response"
|
38
41
|
require "saml/kit/id"
|
39
42
|
require "saml/kit/identity_provider_metadata"
|
@@ -41,6 +44,8 @@ require "saml/kit/invalid_document"
|
|
41
44
|
require "saml/kit/self_signed_certificate"
|
42
45
|
require "saml/kit/service_provider_metadata"
|
43
46
|
require "saml/kit/signature"
|
47
|
+
require "saml/kit/signatures"
|
48
|
+
require "saml/kit/template"
|
44
49
|
require "saml/kit/xml"
|
45
50
|
require "saml/kit/xml_decryption"
|
46
51
|
|
@@ -64,6 +69,11 @@ module Saml
|
|
64
69
|
def registry
|
65
70
|
configuration.registry
|
66
71
|
end
|
72
|
+
|
73
|
+
def deprecate(message)
|
74
|
+
@deprecation ||= ActiveSupport::Deprecation.new('next-release', 'saml-kit')
|
75
|
+
@deprecation.deprecation_warning(message)
|
76
|
+
end
|
67
77
|
end
|
68
78
|
end
|
69
79
|
end
|
@@ -25,6 +25,26 @@ module Saml
|
|
25
25
|
{ binding: binding, location: location }
|
26
26
|
end
|
27
27
|
|
28
|
+
def ==(other)
|
29
|
+
self.to_s == other.to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def eql?(other)
|
33
|
+
self == other
|
34
|
+
end
|
35
|
+
|
36
|
+
def hash
|
37
|
+
to_s.hash
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
"#{location}#{binding}"
|
42
|
+
end
|
43
|
+
|
44
|
+
def inspect
|
45
|
+
to_h.inspect
|
46
|
+
end
|
47
|
+
|
28
48
|
protected
|
29
49
|
|
30
50
|
def saml_param_from(params)
|
data/lib/saml/kit/builders.rb
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
+
require 'saml/kit/builders/assertion'
|
1
2
|
require 'saml/kit/builders/authentication_request'
|
2
3
|
require 'saml/kit/builders/identity_provider_metadata'
|
3
4
|
require 'saml/kit/builders/logout_request'
|
4
5
|
require 'saml/kit/builders/logout_response'
|
5
6
|
require 'saml/kit/builders/response'
|
6
7
|
require 'saml/kit/builders/service_provider_metadata'
|
8
|
+
require 'saml/kit/builders/xml_encryption'
|
9
|
+
require 'saml/kit/builders/xml_signature'
|
7
10
|
|
8
11
|
module Saml
|
9
12
|
module Kit
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class Assertion
|
5
|
+
include Templatable
|
6
|
+
extend Forwardable
|
7
|
+
|
8
|
+
def_delegators :@response_builder, :encrypt, :sign, :request, :issuer, :reference_id, :now, :configuration, :user, :version
|
9
|
+
|
10
|
+
def initialize(response_builder)
|
11
|
+
@response_builder = response_builder
|
12
|
+
end
|
13
|
+
|
14
|
+
def name_id_format
|
15
|
+
request.name_id_format
|
16
|
+
end
|
17
|
+
|
18
|
+
def name_id
|
19
|
+
user.name_id_for(name_id_format)
|
20
|
+
end
|
21
|
+
|
22
|
+
def assertion_attributes
|
23
|
+
user.assertion_attributes_for(request)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def assertion_options
|
29
|
+
{
|
30
|
+
ID: reference_id,
|
31
|
+
IssueInstant: now.iso8601,
|
32
|
+
Version: version,
|
33
|
+
xmlns: Namespaces::ASSERTION,
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
def subject_confirmation_data_options
|
38
|
+
{
|
39
|
+
InResponseTo: request.id,
|
40
|
+
NotOnOrAfter: 3.hours.since(now).utc.iso8601,
|
41
|
+
Recipient: request.assertion_consumer_service_url,
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def conditions_options
|
46
|
+
{
|
47
|
+
NotBefore: now.utc.iso8601,
|
48
|
+
NotOnOrAfter: configuration.session_timeout.from_now.utc.iso8601,
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def authn_statement_options
|
53
|
+
{
|
54
|
+
AuthnInstant: now.iso8601,
|
55
|
+
SessionIndex: reference_id,
|
56
|
+
SessionNotOnOrAfter: 3.hours.since(now).utc.iso8601,
|
57
|
+
}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -2,26 +2,29 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class AuthenticationRequest
|
5
|
+
include Saml::Kit::Templatable
|
5
6
|
attr_accessor :id, :now, :issuer, :assertion_consumer_service_url, :name_id_format, :sign, :destination
|
6
7
|
attr_accessor :version
|
8
|
+
attr_reader :configuration
|
7
9
|
|
8
10
|
def initialize(configuration: Saml::Kit.configuration, sign: true)
|
11
|
+
@configuration = configuration
|
9
12
|
@id = Id.generate
|
10
13
|
@issuer = configuration.issuer
|
11
14
|
@name_id_format = Namespaces::PERSISTENT
|
12
15
|
@now = Time.now.utc
|
13
|
-
@version = "2.0"
|
14
16
|
@sign = sign
|
17
|
+
@version = "2.0"
|
15
18
|
end
|
16
19
|
|
17
|
-
def
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def acs_url
|
21
|
+
Saml::Kit.deprecate("acs_url is deprecated. Use assertion_consumer_service_url instead")
|
22
|
+
self.assertion_consumer_service_url
|
23
|
+
end
|
24
|
+
|
25
|
+
def acs_url=(value)
|
26
|
+
Saml::Kit.deprecate("acs_url= is deprecated. Use assertion_consumer_service_url= instead")
|
27
|
+
self.assertion_consumer_service_url = value
|
25
28
|
end
|
26
29
|
|
27
30
|
def build
|
@@ -39,7 +42,9 @@ module Saml
|
|
39
42
|
IssueInstant: now.utc.iso8601,
|
40
43
|
Destination: destination,
|
41
44
|
}
|
42
|
-
|
45
|
+
if assertion_consumer_service_url.present?
|
46
|
+
options[:AssertionConsumerServiceURL] = assertion_consumer_service_url
|
47
|
+
end
|
43
48
|
options
|
44
49
|
end
|
45
50
|
end
|
@@ -2,19 +2,21 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class IdentityProviderMetadata
|
5
|
+
include Saml::Kit::Templatable
|
5
6
|
attr_accessor :id, :organization_name, :organization_url, :contact_email, :entity_id, :attributes, :name_id_formats
|
6
7
|
attr_accessor :want_authn_requests_signed, :sign
|
7
8
|
attr_reader :logout_urls, :single_sign_on_urls
|
9
|
+
attr_reader :configuration
|
8
10
|
|
9
11
|
def initialize(configuration = Saml::Kit.configuration)
|
10
|
-
@id = Id.generate
|
11
|
-
@entity_id = configuration.issuer
|
12
12
|
@attributes = []
|
13
|
-
@name_id_formats = [Namespaces::PERSISTENT]
|
14
|
-
@single_sign_on_urls = []
|
15
|
-
@logout_urls = []
|
16
13
|
@configuration = configuration
|
14
|
+
@entity_id = configuration.issuer
|
15
|
+
@id = Id.generate
|
16
|
+
@logout_urls = []
|
17
|
+
@name_id_formats = [Namespaces::PERSISTENT]
|
17
18
|
@sign = true
|
19
|
+
@single_sign_on_urls = []
|
18
20
|
@want_authn_requests_signed = true
|
19
21
|
end
|
20
22
|
|
@@ -26,55 +28,6 @@ module Saml
|
|
26
28
|
@logout_urls.push(location: url, binding: Bindings.binding_for(binding))
|
27
29
|
end
|
28
30
|
|
29
|
-
def to_xml
|
30
|
-
Signature.sign(sign: sign) do |xml, signature|
|
31
|
-
xml.instruct!
|
32
|
-
xml.EntityDescriptor entity_descriptor_options do
|
33
|
-
signature.template(id)
|
34
|
-
xml.IDPSSODescriptor idp_sso_descriptor_options do
|
35
|
-
if @configuration.signing_certificate_pem.present?
|
36
|
-
xml.KeyDescriptor use: "signing" do
|
37
|
-
xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
|
38
|
-
xml.X509Data do
|
39
|
-
xml.X509Certificate @configuration.stripped_signing_certificate
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
if @configuration.encryption_certificate_pem.present?
|
45
|
-
xml.KeyDescriptor use: "encryption" do
|
46
|
-
xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
|
47
|
-
xml.X509Data do
|
48
|
-
xml.X509Certificate @configuration.stripped_encryption_certificate
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
53
|
-
logout_urls.each do |item|
|
54
|
-
xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
|
55
|
-
end
|
56
|
-
name_id_formats.each do |format|
|
57
|
-
xml.NameIDFormat format
|
58
|
-
end
|
59
|
-
single_sign_on_urls.each do |item|
|
60
|
-
xml.SingleSignOnService Binding: item[:binding], Location: item[:location]
|
61
|
-
end
|
62
|
-
attributes.each do |attribute|
|
63
|
-
xml.tag! 'saml:Attribute', Name: attribute
|
64
|
-
end
|
65
|
-
end
|
66
|
-
xml.Organization do
|
67
|
-
xml.OrganizationName organization_name, 'xml:lang': "en"
|
68
|
-
xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
|
69
|
-
xml.OrganizationURL organization_url, 'xml:lang': "en"
|
70
|
-
end
|
71
|
-
xml.ContactPerson contactType: "technical" do
|
72
|
-
xml.Company "mailto:#{contact_email}"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
31
|
def build
|
79
32
|
Saml::Kit::IdentityProviderMetadata.new(to_xml)
|
80
33
|
end
|
@@ -2,11 +2,13 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class LogoutRequest
|
5
|
+
include Saml::Kit::Templatable
|
5
6
|
attr_accessor :id, :destination, :issuer, :name_id_format, :now
|
6
7
|
attr_accessor :sign, :version
|
7
|
-
attr_reader :user
|
8
|
+
attr_reader :user, :configuration
|
8
9
|
|
9
10
|
def initialize(user, configuration: Saml::Kit.configuration, sign: true)
|
11
|
+
@configuration = configuration
|
10
12
|
@user = user
|
11
13
|
@id = "_#{SecureRandom.uuid}"
|
12
14
|
@issuer = configuration.issuer
|
@@ -16,17 +18,6 @@ module Saml
|
|
16
18
|
@sign = sign
|
17
19
|
end
|
18
20
|
|
19
|
-
def to_xml
|
20
|
-
Signature.sign(sign: sign) do |xml, signature|
|
21
|
-
xml.instruct!
|
22
|
-
xml.LogoutRequest logout_request_options do
|
23
|
-
xml.Issuer({ xmlns: Namespaces::ASSERTION }, issuer)
|
24
|
-
signature.template(id)
|
25
|
-
xml.NameID name_id_options, user.name_id_for(name_id_format)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
21
|
def build
|
31
22
|
Saml::Kit::LogoutRequest.new(to_xml)
|
32
23
|
end
|
@@ -2,30 +2,21 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class LogoutResponse
|
5
|
+
include Saml::Kit::Templatable
|
5
6
|
attr_accessor :id, :issuer, :version, :status_code, :sign, :now, :destination
|
6
7
|
attr_reader :request
|
8
|
+
attr_reader :configuration
|
7
9
|
|
8
10
|
def initialize(user, request, configuration: Saml::Kit.configuration, sign: true)
|
9
|
-
@
|
11
|
+
@configuration = configuration
|
12
|
+
@id = Id.generate
|
13
|
+
@issuer = configuration.issuer
|
10
14
|
@now = Time.now.utc
|
11
15
|
@request = request
|
12
|
-
@id = Id.generate
|
13
|
-
@version = "2.0"
|
14
|
-
@status_code = Namespaces::SUCCESS
|
15
16
|
@sign = sign
|
16
|
-
@
|
17
|
-
|
18
|
-
|
19
|
-
def to_xml
|
20
|
-
Signature.sign(sign: sign) do |xml, signature|
|
21
|
-
xml.LogoutResponse logout_response_options do
|
22
|
-
xml.Issuer(issuer, xmlns: Namespaces::ASSERTION)
|
23
|
-
signature.template(id)
|
24
|
-
xml.Status do
|
25
|
-
xml.StatusCode Value: status_code
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
17
|
+
@status_code = Namespaces::SUCCESS
|
18
|
+
@user = user
|
19
|
+
@version = "2.0"
|
29
20
|
end
|
30
21
|
|
31
22
|
def build
|
@@ -2,12 +2,14 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class Response
|
5
|
+
include Templatable
|
5
6
|
attr_reader :user, :request
|
6
7
|
attr_accessor :id, :reference_id, :now
|
7
8
|
attr_accessor :version, :status_code
|
8
9
|
attr_accessor :issuer, :sign, :destination, :encrypt
|
10
|
+
attr_reader :configuration
|
9
11
|
|
10
|
-
def initialize(user, request)
|
12
|
+
def initialize(user, request, configuration: Saml::Kit.configuration)
|
11
13
|
@user = user
|
12
14
|
@request = request
|
13
15
|
@id = Id.generate
|
@@ -19,6 +21,7 @@ module Saml
|
|
19
21
|
@destination = destination_for(request)
|
20
22
|
@sign = want_assertions_signed
|
21
23
|
@encrypt = false
|
24
|
+
@configuration = configuration
|
22
25
|
end
|
23
26
|
|
24
27
|
def want_assertions_signed
|
@@ -28,97 +31,18 @@ module Saml
|
|
28
31
|
true
|
29
32
|
end
|
30
33
|
|
31
|
-
def to_xml
|
32
|
-
Signature.sign(sign: sign) do |xml, signature|
|
33
|
-
xml.Response response_options do
|
34
|
-
xml.Issuer(issuer, xmlns: Namespaces::ASSERTION)
|
35
|
-
signature.template(id)
|
36
|
-
xml.Status do
|
37
|
-
xml.StatusCode Value: status_code
|
38
|
-
end
|
39
|
-
assertion(xml, signature)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
34
|
def build
|
45
35
|
Saml::Kit::Response.new(to_xml, request_id: request.id)
|
46
36
|
end
|
47
37
|
|
48
38
|
private
|
49
39
|
|
50
|
-
def assertion
|
51
|
-
|
52
|
-
xml.Assertion(assertion_options) do
|
53
|
-
xml.Issuer issuer
|
54
|
-
signature.template(reference_id) unless encrypt
|
55
|
-
xml.Subject do
|
56
|
-
xml.NameID user.name_id_for(request.name_id_format), Format: request.name_id_format
|
57
|
-
xml.SubjectConfirmation Method: Namespaces::BEARER do
|
58
|
-
xml.SubjectConfirmationData "", subject_confirmation_data_options
|
59
|
-
end
|
60
|
-
end
|
61
|
-
xml.Conditions conditions_options do
|
62
|
-
xml.AudienceRestriction do
|
63
|
-
xml.Audience request.issuer
|
64
|
-
end
|
65
|
-
end
|
66
|
-
xml.AuthnStatement authn_statement_options do
|
67
|
-
xml.AuthnContext do
|
68
|
-
xml.AuthnContextClassRef Namespaces::PASSWORD
|
69
|
-
end
|
70
|
-
end
|
71
|
-
assertion_attributes = user.assertion_attributes_for(request)
|
72
|
-
if assertion_attributes.any?
|
73
|
-
xml.AttributeStatement do
|
74
|
-
assertion_attributes.each do |key, value|
|
75
|
-
xml.Attribute Name: key, NameFormat: Namespaces::URI, FriendlyName: key do
|
76
|
-
xml.AttributeValue value.to_s
|
77
|
-
end
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
40
|
+
def assertion
|
41
|
+
@assertion ||= Saml::Kit::Builders::Assertion.new(self)
|
83
42
|
end
|
84
43
|
|
85
|
-
def
|
86
|
-
|
87
|
-
temp = ::Builder::XmlMarkup.new
|
88
|
-
yield temp
|
89
|
-
raw_xml_to_encrypt = temp.target!
|
90
|
-
|
91
|
-
encryption_certificate = request.provider.encryption_certificates.first
|
92
|
-
public_key = encryption_certificate.public_key
|
93
|
-
|
94
|
-
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
95
|
-
cipher.encrypt
|
96
|
-
key = cipher.random_key
|
97
|
-
iv = cipher.random_iv
|
98
|
-
encrypted = cipher.update(raw_xml_to_encrypt) + cipher.final
|
99
|
-
|
100
|
-
Saml::Kit.logger.debug ['+iv', iv].inspect
|
101
|
-
Saml::Kit.logger.debug ['+key', key].inspect
|
102
|
-
|
103
|
-
xml.EncryptedAssertion xmlns: Namespaces::ASSERTION do
|
104
|
-
xml.EncryptedData xmlns: Namespaces::XMLENC do
|
105
|
-
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
|
106
|
-
xml.KeyInfo xmlns: Namespaces::XMLDSIG do
|
107
|
-
xml.EncryptedKey xmlns: Namespaces::XMLENC do
|
108
|
-
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
|
109
|
-
xml.CipherData do
|
110
|
-
xml.CipherValue Base64.encode64(public_key.public_encrypt(key))
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
xml.CipherData do
|
115
|
-
xml.CipherValue Base64.encode64(iv + encrypted)
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
else
|
120
|
-
yield xml
|
121
|
-
end
|
44
|
+
def encryption_certificate
|
45
|
+
request.provider.encryption_certificates.first
|
122
46
|
end
|
123
47
|
|
124
48
|
def destination_for(request)
|
@@ -129,10 +53,6 @@ module Saml
|
|
129
53
|
end
|
130
54
|
end
|
131
55
|
|
132
|
-
def configuration
|
133
|
-
Saml::Kit.configuration
|
134
|
-
end
|
135
|
-
|
136
56
|
def response_options
|
137
57
|
{
|
138
58
|
ID: id,
|
@@ -144,38 +64,6 @@ module Saml
|
|
144
64
|
xmlns: Namespaces::PROTOCOL,
|
145
65
|
}
|
146
66
|
end
|
147
|
-
|
148
|
-
def assertion_options
|
149
|
-
{
|
150
|
-
ID: reference_id,
|
151
|
-
IssueInstant: now.iso8601,
|
152
|
-
Version: "2.0",
|
153
|
-
xmlns: Namespaces::ASSERTION,
|
154
|
-
}
|
155
|
-
end
|
156
|
-
|
157
|
-
def subject_confirmation_data_options
|
158
|
-
{
|
159
|
-
InResponseTo: request.id,
|
160
|
-
NotOnOrAfter: 3.hours.since(now).utc.iso8601,
|
161
|
-
Recipient: request.assertion_consumer_service_url,
|
162
|
-
}
|
163
|
-
end
|
164
|
-
|
165
|
-
def conditions_options
|
166
|
-
{
|
167
|
-
NotBefore: now.utc.iso8601,
|
168
|
-
NotOnOrAfter: Saml::Kit.configuration.session_timeout.from_now.utc.iso8601,
|
169
|
-
}
|
170
|
-
end
|
171
|
-
|
172
|
-
def authn_statement_options
|
173
|
-
{
|
174
|
-
AuthnInstant: now.iso8601,
|
175
|
-
SessionIndex: assertion_options[:ID],
|
176
|
-
SessionNotOnOrAfter: 3.hours.since(now).utc.iso8601,
|
177
|
-
}
|
178
|
-
end
|
179
67
|
end
|
180
68
|
end
|
181
69
|
end
|
@@ -2,14 +2,17 @@ module Saml
|
|
2
2
|
module Kit
|
3
3
|
module Builders
|
4
4
|
class ServiceProviderMetadata
|
5
|
+
include Saml::Kit::Templatable
|
5
6
|
attr_accessor :id, :entity_id, :acs_urls, :logout_urls, :name_id_formats, :sign
|
7
|
+
attr_accessor :organization_name, :organization_url, :contact_email
|
6
8
|
attr_accessor :want_assertions_signed
|
9
|
+
attr_reader :configuration
|
7
10
|
|
8
11
|
def initialize(configuration = Saml::Kit.configuration)
|
9
|
-
@
|
12
|
+
@acs_urls = []
|
10
13
|
@configuration = configuration
|
11
14
|
@entity_id = configuration.issuer
|
12
|
-
@
|
15
|
+
@id = Id.generate
|
13
16
|
@logout_urls = []
|
14
17
|
@name_id_formats = [Namespaces::PERSISTENT]
|
15
18
|
@sign = true
|
@@ -24,44 +27,6 @@ module Saml
|
|
24
27
|
@logout_urls.push(location: url, binding: Bindings.binding_for(binding))
|
25
28
|
end
|
26
29
|
|
27
|
-
def to_xml
|
28
|
-
Signature.sign(sign: sign) do |xml, signature|
|
29
|
-
xml.instruct!
|
30
|
-
xml.EntityDescriptor entity_descriptor_options do
|
31
|
-
signature.template(id)
|
32
|
-
xml.SPSSODescriptor descriptor_options do
|
33
|
-
if @configuration.signing_certificate_pem.present?
|
34
|
-
xml.KeyDescriptor use: "signing" do
|
35
|
-
xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
|
36
|
-
xml.X509Data do
|
37
|
-
xml.X509Certificate @configuration.stripped_signing_certificate
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
if @configuration.encryption_certificate_pem.present?
|
43
|
-
xml.KeyDescriptor use: "encryption" do
|
44
|
-
xml.KeyInfo "xmlns": Namespaces::XMLDSIG do
|
45
|
-
xml.X509Data do
|
46
|
-
xml.X509Certificate @configuration.stripped_encryption_certificate
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
logout_urls.each do |item|
|
52
|
-
xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
|
53
|
-
end
|
54
|
-
name_id_formats.each do |format|
|
55
|
-
xml.NameIDFormat format
|
56
|
-
end
|
57
|
-
acs_urls.each_with_index do |item, index|
|
58
|
-
xml.AssertionConsumerService Binding: item[:binding], Location: item[:location], index: index, isDefault: index == 0 ? true : false
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
30
|
def build
|
66
31
|
Saml::Kit::ServiceProviderMetadata.new(to_xml)
|
67
32
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
xml.Assertion(assertion_options) do
|
2
|
+
xml.Issuer issuer
|
3
|
+
signature_for(reference_id: reference_id, xml: xml) unless encrypt
|
4
|
+
xml.Subject do
|
5
|
+
xml.NameID name_id, Format: name_id_format
|
6
|
+
xml.SubjectConfirmation Method: Saml::Kit::Namespaces::BEARER do
|
7
|
+
xml.SubjectConfirmationData "", subject_confirmation_data_options
|
8
|
+
end
|
9
|
+
end
|
10
|
+
xml.Conditions conditions_options do
|
11
|
+
xml.AudienceRestriction do
|
12
|
+
xml.Audience request.issuer
|
13
|
+
end
|
14
|
+
end
|
15
|
+
xml.AuthnStatement authn_statement_options do
|
16
|
+
xml.AuthnContext do
|
17
|
+
xml.AuthnContextClassRef Saml::Kit::Namespaces::PASSWORD
|
18
|
+
end
|
19
|
+
end
|
20
|
+
if assertion_attributes.any?
|
21
|
+
xml.AttributeStatement do
|
22
|
+
assertion_attributes.each do |key, value|
|
23
|
+
xml.Attribute Name: key, NameFormat: Saml::Kit::Namespaces::URI, FriendlyName: key do
|
24
|
+
xml.AttributeValue value.to_s
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
xml.instruct!
|
2
|
+
xml.EntityDescriptor entity_descriptor_options do
|
3
|
+
signature_for(reference_id: id, xml: xml)
|
4
|
+
xml.IDPSSODescriptor idp_sso_descriptor_options do
|
5
|
+
if configuration.signing_certificate_pem.present?
|
6
|
+
render configuration.signing_certificate, xml: xml
|
7
|
+
end
|
8
|
+
if configuration.encryption_certificate_pem.present?
|
9
|
+
render configuration.encryption_certificate, xml: xml
|
10
|
+
end
|
11
|
+
logout_urls.each do |item|
|
12
|
+
xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
|
13
|
+
end
|
14
|
+
name_id_formats.each do |format|
|
15
|
+
xml.NameIDFormat format
|
16
|
+
end
|
17
|
+
single_sign_on_urls.each do |item|
|
18
|
+
xml.SingleSignOnService Binding: item[:binding], Location: item[:location]
|
19
|
+
end
|
20
|
+
attributes.each do |attribute|
|
21
|
+
xml.tag! 'saml:Attribute', Name: attribute
|
22
|
+
end
|
23
|
+
end
|
24
|
+
xml.Organization do
|
25
|
+
xml.OrganizationName organization_name, 'xml:lang': "en"
|
26
|
+
xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
|
27
|
+
xml.OrganizationURL organization_url, 'xml:lang': "en"
|
28
|
+
end
|
29
|
+
xml.ContactPerson contactType: "technical" do
|
30
|
+
xml.Company "mailto:#{contact_email}"
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
xml.instruct!
|
2
|
+
xml.Response response_options do
|
3
|
+
xml.Issuer(issuer, xmlns: Saml::Kit::Namespaces::ASSERTION)
|
4
|
+
signature_for(reference_id: id, xml: xml)
|
5
|
+
xml.Status do
|
6
|
+
xml.StatusCode Value: status_code
|
7
|
+
end
|
8
|
+
encryption_for(xml: xml) do |xml|
|
9
|
+
render assertion, xml: xml
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
xml.instruct!
|
2
|
+
xml.EntityDescriptor entity_descriptor_options do
|
3
|
+
signature_for(reference_id: id, xml: xml)
|
4
|
+
xml.SPSSODescriptor descriptor_options do
|
5
|
+
if configuration.signing_certificate_pem.present?
|
6
|
+
render configuration.signing_certificate, xml: xml
|
7
|
+
end
|
8
|
+
if configuration.encryption_certificate_pem.present?
|
9
|
+
render configuration.encryption_certificate, xml: xml
|
10
|
+
end
|
11
|
+
logout_urls.each do |item|
|
12
|
+
xml.SingleLogoutService Binding: item[:binding], Location: item[:location]
|
13
|
+
end
|
14
|
+
name_id_formats.each do |format|
|
15
|
+
xml.NameIDFormat format
|
16
|
+
end
|
17
|
+
acs_urls.each_with_index do |item, index|
|
18
|
+
xml.AssertionConsumerService Binding: item[:binding], Location: item[:location], index: index, isDefault: index == 0 ? true : false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
xml.Organization do
|
22
|
+
xml.OrganizationName organization_name, 'xml:lang': "en"
|
23
|
+
xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
|
24
|
+
xml.OrganizationURL organization_url, 'xml:lang': "en"
|
25
|
+
end
|
26
|
+
xml.ContactPerson contactType: "technical" do
|
27
|
+
xml.Company "mailto:#{contact_email}"
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
xml.EncryptedAssertion xmlns: Saml::Kit::Namespaces::ASSERTION do
|
2
|
+
xml.EncryptedData xmlns: Saml::Kit::Namespaces::XMLENC do
|
3
|
+
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#aes256-cbc"
|
4
|
+
xml.KeyInfo xmlns: Saml::Kit::Namespaces::XMLDSIG do
|
5
|
+
xml.EncryptedKey xmlns: Saml::Kit::Namespaces::XMLENC do
|
6
|
+
xml.EncryptionMethod Algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-1_5"
|
7
|
+
xml.CipherData do
|
8
|
+
xml.CipherValue Base64.encode64(public_key.public_encrypt(key))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
xml.CipherData do
|
13
|
+
xml.CipherValue Base64.encode64(iv + encrypted)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
xml.Signature "xmlns" => Saml::Kit::Namespaces::XMLDSIG do
|
2
|
+
xml.SignedInfo do
|
3
|
+
xml.CanonicalizationMethod Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
4
|
+
xml.SignatureMethod Algorithm: signature_method
|
5
|
+
xml.Reference URI: "##{reference_id}" do
|
6
|
+
xml.Transforms do
|
7
|
+
xml.Transform Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
8
|
+
xml.Transform Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
9
|
+
end
|
10
|
+
xml.DigestMethod Algorithm: digest_method
|
11
|
+
xml.DigestValue ""
|
12
|
+
end
|
13
|
+
end
|
14
|
+
xml.SignatureValue ""
|
15
|
+
xml.KeyInfo do
|
16
|
+
xml.X509Data do
|
17
|
+
xml.X509Certificate x509_certificate
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class XmlEncryption
|
5
|
+
attr_reader :public_key
|
6
|
+
attr_reader :key, :iv, :encrypted
|
7
|
+
|
8
|
+
def initialize(raw_xml, public_key)
|
9
|
+
@public_key = public_key
|
10
|
+
cipher = OpenSSL::Cipher.new('AES-256-CBC')
|
11
|
+
cipher.encrypt
|
12
|
+
@key = cipher.random_key
|
13
|
+
@iv = cipher.random_iv
|
14
|
+
@encrypted = cipher.update(raw_xml) + cipher.final
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class XmlSignature
|
5
|
+
SIGNATURE_METHODS = {
|
6
|
+
SHA1: "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
|
7
|
+
SHA224: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
|
8
|
+
SHA256: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
9
|
+
SHA384: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
|
10
|
+
SHA512: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
11
|
+
}.freeze
|
12
|
+
DIGEST_METHODS = {
|
13
|
+
SHA1: "http://www.w3.org/2000/09/xmldsig#SHA1",
|
14
|
+
SHA224: "http://www.w3.org/2001/04/xmldsig-more#sha224",
|
15
|
+
SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
|
16
|
+
SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384",
|
17
|
+
SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
|
18
|
+
}.freeze
|
19
|
+
|
20
|
+
attr_reader :sign, :configuration
|
21
|
+
attr_reader :reference_id
|
22
|
+
attr_reader :x509_certificate
|
23
|
+
|
24
|
+
def initialize(reference_id, configuration:, sign: true)
|
25
|
+
@configuration = configuration
|
26
|
+
@reference_id = reference_id
|
27
|
+
@sign = sign
|
28
|
+
@x509_certificate = configuration.signing_certificate.stripped
|
29
|
+
end
|
30
|
+
|
31
|
+
def signature_method
|
32
|
+
SIGNATURE_METHODS[configuration.signature_method]
|
33
|
+
end
|
34
|
+
|
35
|
+
def digest_method
|
36
|
+
DIGEST_METHODS[configuration.digest_method]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/saml/kit/certificate.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module Saml
|
2
2
|
module Kit
|
3
3
|
class Certificate
|
4
|
+
BEGIN_CERT=/-----BEGIN CERTIFICATE-----/
|
5
|
+
END_CERT=/-----END CERTIFICATE-----/
|
4
6
|
attr_reader :value, :use
|
5
7
|
|
6
8
|
def initialize(value, use:)
|
@@ -48,6 +50,18 @@ module Saml
|
|
48
50
|
value
|
49
51
|
end
|
50
52
|
|
53
|
+
def to_h
|
54
|
+
{ use: @use, x509: @value }
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect
|
58
|
+
to_h.inspect
|
59
|
+
end
|
60
|
+
|
61
|
+
def stripped
|
62
|
+
value.to_s.gsub(BEGIN_CERT, '').gsub(END_CERT, '').gsub(/\n/, '')
|
63
|
+
end
|
64
|
+
|
51
65
|
def self.to_x509(value)
|
52
66
|
OpenSSL::X509::Certificate.new(Base64.decode64(value))
|
53
67
|
rescue OpenSSL::X509::CertificateError => error
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
class CompositeMetadata < Metadata
|
4
|
+
attr_reader :service_provider, :identity_provider
|
5
|
+
|
6
|
+
def initialize(xml)
|
7
|
+
super("IDPSSODescriptor", xml)
|
8
|
+
@service_provider = Saml::Kit::ServiceProviderMetadata.new(xml)
|
9
|
+
@identity_provider = Saml::Kit::IdentityProviderMetadata.new(xml)
|
10
|
+
end
|
11
|
+
|
12
|
+
def services(type)
|
13
|
+
xpath = "//md:EntityDescriptor/md:SPSSODescriptor/md:#{type}|//md:EntityDescriptor/md:IDPSSODescriptor/md:#{type}"
|
14
|
+
document.find_all(xpath).map do |item|
|
15
|
+
binding = item.attribute("Binding").value
|
16
|
+
location = item.attribute("Location").value
|
17
|
+
Saml::Kit::Bindings.create_for(binding, location)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def certificates
|
22
|
+
identity_provider.certificates + service_provider.certificates
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(name, *args)
|
26
|
+
if identity_provider.respond_to?(name)
|
27
|
+
identity_provider.public_send(name, *args)
|
28
|
+
elsif service_provider.respond_to?(name)
|
29
|
+
service_provider.public_send(name, *args)
|
30
|
+
else
|
31
|
+
super
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,9 +1,6 @@
|
|
1
1
|
module Saml
|
2
2
|
module Kit
|
3
3
|
class Configuration
|
4
|
-
BEGIN_CERT=/-----BEGIN CERTIFICATE-----/
|
5
|
-
END_CERT=/-----END CERTIFICATE-----/
|
6
|
-
|
7
4
|
attr_accessor :issuer
|
8
5
|
attr_accessor :signature_method, :digest_method
|
9
6
|
attr_accessor :signing_certificate_pem, :signing_private_key_pem, :signing_private_key_password
|
@@ -23,20 +20,12 @@ module Saml
|
|
23
20
|
@logger = Logger.new(STDOUT)
|
24
21
|
end
|
25
22
|
|
26
|
-
def
|
27
|
-
|
28
|
-
end
|
29
|
-
|
30
|
-
def stripped_encryption_certificate
|
31
|
-
normalize(encryption_certificate_pem)
|
32
|
-
end
|
33
|
-
|
34
|
-
def signing_x509
|
35
|
-
Certificate.to_x509(signing_certificate_pem)
|
23
|
+
def signing_certificate
|
24
|
+
Saml::Kit::Certificate.new(signing_certificate_pem, use: :signing)
|
36
25
|
end
|
37
26
|
|
38
|
-
def
|
39
|
-
Certificate.
|
27
|
+
def encryption_certificate
|
28
|
+
Saml::Kit::Certificate.new(encryption_certificate_pem, use: :encryption)
|
40
29
|
end
|
41
30
|
|
42
31
|
def signing_private_key
|
@@ -46,12 +35,6 @@ module Saml
|
|
46
35
|
def encryption_private_key
|
47
36
|
OpenSSL::PKey::RSA.new(encryption_private_key_pem, encryption_private_key_password)
|
48
37
|
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def normalize(certificate)
|
53
|
-
certificate.to_s.gsub(BEGIN_CERT, '').gsub(END_CERT, '').gsub(/\n/, '')
|
54
|
-
end
|
55
38
|
end
|
56
39
|
end
|
57
40
|
end
|
data/lib/saml/kit/metadata.rb
CHANGED
@@ -99,7 +99,9 @@ module Saml
|
|
99
99
|
def self.from(content)
|
100
100
|
hash = Hash.from_xml(content)
|
101
101
|
entity_descriptor = hash["EntityDescriptor"]
|
102
|
-
if entity_descriptor.
|
102
|
+
if entity_descriptor.key?("SPSSODescriptor") && entity_descriptor.key?("IDPSSODescriptor")
|
103
|
+
Saml::Kit::CompositeMetadata.new(content)
|
104
|
+
elsif entity_descriptor.keys.include?("SPSSODescriptor")
|
103
105
|
Saml::Kit::ServiceProviderMetadata.new(content)
|
104
106
|
elsif entity_descriptor.keys.include?("IDPSSODescriptor")
|
105
107
|
Saml::Kit::IdentityProviderMetadata.new(content)
|
data/lib/saml/kit/requestable.rb
CHANGED
data/lib/saml/kit/signature.rb
CHANGED
@@ -1,65 +1,23 @@
|
|
1
1
|
module Saml
|
2
2
|
module Kit
|
3
3
|
class Signature
|
4
|
-
|
5
|
-
|
6
|
-
SHA224: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha224",
|
7
|
-
SHA256: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
|
8
|
-
SHA384: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
|
9
|
-
SHA512: "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
|
10
|
-
}.freeze
|
11
|
-
DIGEST_METHODS = {
|
12
|
-
SHA1: "http://www.w3.org/2000/09/xmldsig#SHA1",
|
13
|
-
SHA224: "http://www.w3.org/2001/04/xmldsig-more#sha224",
|
14
|
-
SHA256: "http://www.w3.org/2001/04/xmlenc#sha256",
|
15
|
-
SHA384: "http://www.w3.org/2001/04/xmldsig-more#sha384",
|
16
|
-
SHA512: "http://www.w3.org/2001/04/xmlenc#sha512",
|
17
|
-
}.freeze
|
18
|
-
|
19
|
-
attr_reader :configuration, :sign, :xml
|
4
|
+
attr_reader :sign, :xml
|
5
|
+
attr_reader :configuration
|
20
6
|
|
21
7
|
def initialize(xml, configuration:, sign: true)
|
22
|
-
@xml = xml
|
23
8
|
@configuration = configuration
|
24
9
|
@sign = sign
|
25
|
-
@
|
10
|
+
@xml = xml
|
26
11
|
end
|
27
12
|
|
28
13
|
def template(reference_id)
|
29
14
|
return unless sign
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
xml.Signature "xmlns" => Namespaces::XMLDSIG do
|
34
|
-
xml.SignedInfo do
|
35
|
-
xml.CanonicalizationMethod Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
36
|
-
xml.SignatureMethod Algorithm: SIGNATURE_METHODS[configuration.signature_method]
|
37
|
-
xml.Reference URI: "##{reference_id}" do
|
38
|
-
xml.Transforms do
|
39
|
-
xml.Transform Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"
|
40
|
-
xml.Transform Algorithm: "http://www.w3.org/2001/10/xml-exc-c14n#"
|
41
|
-
end
|
42
|
-
xml.DigestMethod Algorithm: DIGEST_METHODS[configuration.digest_method]
|
43
|
-
xml.DigestValue ""
|
44
|
-
end
|
45
|
-
end
|
46
|
-
xml.SignatureValue ""
|
47
|
-
xml.KeyInfo do
|
48
|
-
xml.X509Data do
|
49
|
-
xml.X509Certificate configuration.stripped_signing_certificate
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
15
|
+
signature = signatures.build(reference_id)
|
16
|
+
Template.new(signature).to_xml(xml: xml)
|
53
17
|
end
|
54
18
|
|
55
19
|
def finalize
|
56
|
-
|
57
|
-
|
58
|
-
raw_xml = xml.target!
|
59
|
-
@reference_ids.each do |reference_id|
|
60
|
-
raw_xml = Xmldsig::SignedDocument.new(raw_xml).sign(private_key)
|
61
|
-
end
|
62
|
-
raw_xml
|
20
|
+
signatures.complete(xml.target!)
|
63
21
|
end
|
64
22
|
|
65
23
|
def self.sign(sign: true, xml: ::Builder::XmlMarkup.new, configuration: Saml::Kit.configuration)
|
@@ -70,8 +28,8 @@ module Saml
|
|
70
28
|
|
71
29
|
private
|
72
30
|
|
73
|
-
def
|
74
|
-
configuration
|
31
|
+
def signatures
|
32
|
+
@signatures ||= Saml::Kit::Signatures.new(configuration: configuration, sign: sign)
|
75
33
|
end
|
76
34
|
end
|
77
35
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
class Signatures
|
4
|
+
attr_reader :sign, :configuration
|
5
|
+
|
6
|
+
def initialize(configuration:, sign: true)
|
7
|
+
@configuration = configuration
|
8
|
+
@sign = sign
|
9
|
+
end
|
10
|
+
|
11
|
+
def build(reference_id)
|
12
|
+
Saml::Kit::Builders::XmlSignature.new(reference_id, configuration: configuration, sign: sign)
|
13
|
+
end
|
14
|
+
|
15
|
+
def complete(raw_xml)
|
16
|
+
return raw_xml unless sign
|
17
|
+
|
18
|
+
Xmldsig::SignedDocument.new(raw_xml).sign(private_key)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def private_key
|
24
|
+
configuration.signing_private_key
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Templatable
|
4
|
+
def to_xml(xml: ::Builder::XmlMarkup.new)
|
5
|
+
signatures.complete(render(self, xml: xml))
|
6
|
+
end
|
7
|
+
|
8
|
+
def signature_for(reference_id:, xml:)
|
9
|
+
return unless sign
|
10
|
+
render(signatures.build(reference_id), xml: xml)
|
11
|
+
end
|
12
|
+
|
13
|
+
def signatures
|
14
|
+
@signatures ||= Saml::Kit::Signatures.new(configuration: configuration, sign: sign)
|
15
|
+
end
|
16
|
+
|
17
|
+
def encryption_for(xml:)
|
18
|
+
if encrypt && encryption_certificate
|
19
|
+
temp = ::Builder::XmlMarkup.new
|
20
|
+
yield temp
|
21
|
+
xml_encryption = Saml::Kit::Builders::XmlEncryption.new(temp.target!, encryption_certificate.public_key)
|
22
|
+
render(xml_encryption, xml: xml)
|
23
|
+
else
|
24
|
+
yield xml
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def render(model, options)
|
29
|
+
Saml::Kit::Template.new(model).to_xml(options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
class Template
|
4
|
+
attr_reader :target
|
5
|
+
|
6
|
+
def initialize(target)
|
7
|
+
@target = target
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_xml(options)
|
11
|
+
template.render(target, options)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def template_name
|
17
|
+
"#{target.class.name.split("::").last.underscore}.builder"
|
18
|
+
end
|
19
|
+
|
20
|
+
def template_path
|
21
|
+
File.join(File.expand_path(File.dirname(__FILE__)), "builders/templates/#{template_name}")
|
22
|
+
end
|
23
|
+
|
24
|
+
def template
|
25
|
+
Tilt.new(template_path)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/saml/kit/version.rb
CHANGED
@@ -8,10 +8,10 @@ module Saml
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def decrypt(data)
|
11
|
-
|
12
|
-
symmetric_key = symmetric_key_from(
|
13
|
-
cipher_text = Base64.decode64(
|
14
|
-
to_plaintext(cipher_text, symmetric_key,
|
11
|
+
encrypted_data = data['EncryptedData']
|
12
|
+
symmetric_key = symmetric_key_from(encrypted_data)
|
13
|
+
cipher_text = Base64.decode64(encrypted_data["CipherData"]["CipherValue"])
|
14
|
+
to_plaintext(cipher_text, symmetric_key, encrypted_data["EncryptionMethod"]['Algorithm'])
|
15
15
|
end
|
16
16
|
|
17
17
|
private
|
@@ -23,7 +23,7 @@ module Saml
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_plaintext(cipher_text, symmetric_key, algorithm)
|
26
|
-
|
26
|
+
Crypto.decryptor_for(algorithm, symmetric_key).decrypt(cipher_text)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/saml-kit.gemspec
CHANGED
@@ -25,6 +25,7 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency "activemodel", ">= 4.2.0"
|
26
26
|
spec.add_dependency "builder", "~> 3.2"
|
27
27
|
spec.add_dependency "nokogiri", "~> 1.8"
|
28
|
+
spec.add_dependency "tilt", "~> 2.0"
|
28
29
|
spec.add_dependency "xmldsig", "~> 0.6"
|
29
30
|
spec.add_development_dependency "bundler", "~> 1.15"
|
30
31
|
spec.add_development_dependency "ffaker", "~> 2.7"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saml-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- mo khan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-12-
|
11
|
+
date: 2017-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.8'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: tilt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: xmldsig
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -182,13 +196,27 @@ files:
|
|
182
196
|
- lib/saml/kit/bindings/url_builder.rb
|
183
197
|
- lib/saml/kit/buildable.rb
|
184
198
|
- lib/saml/kit/builders.rb
|
199
|
+
- lib/saml/kit/builders/assertion.rb
|
185
200
|
- lib/saml/kit/builders/authentication_request.rb
|
186
201
|
- lib/saml/kit/builders/identity_provider_metadata.rb
|
187
202
|
- lib/saml/kit/builders/logout_request.rb
|
188
203
|
- lib/saml/kit/builders/logout_response.rb
|
189
204
|
- lib/saml/kit/builders/response.rb
|
190
205
|
- lib/saml/kit/builders/service_provider_metadata.rb
|
206
|
+
- lib/saml/kit/builders/templates/assertion.builder
|
207
|
+
- lib/saml/kit/builders/templates/authentication_request.builder
|
208
|
+
- lib/saml/kit/builders/templates/certificate.builder
|
209
|
+
- lib/saml/kit/builders/templates/identity_provider_metadata.builder
|
210
|
+
- lib/saml/kit/builders/templates/logout_request.builder
|
211
|
+
- lib/saml/kit/builders/templates/logout_response.builder
|
212
|
+
- lib/saml/kit/builders/templates/response.builder
|
213
|
+
- lib/saml/kit/builders/templates/service_provider_metadata.builder
|
214
|
+
- lib/saml/kit/builders/templates/xml_encryption.builder
|
215
|
+
- lib/saml/kit/builders/templates/xml_signature.builder
|
216
|
+
- lib/saml/kit/builders/xml_encryption.rb
|
217
|
+
- lib/saml/kit/builders/xml_signature.rb
|
191
218
|
- lib/saml/kit/certificate.rb
|
219
|
+
- lib/saml/kit/composite_metadata.rb
|
192
220
|
- lib/saml/kit/configuration.rb
|
193
221
|
- lib/saml/kit/crypto.rb
|
194
222
|
- lib/saml/kit/crypto/oaep_cipher.rb
|
@@ -213,6 +241,9 @@ files:
|
|
213
241
|
- lib/saml/kit/serializable.rb
|
214
242
|
- lib/saml/kit/service_provider_metadata.rb
|
215
243
|
- lib/saml/kit/signature.rb
|
244
|
+
- lib/saml/kit/signatures.rb
|
245
|
+
- lib/saml/kit/templatable.rb
|
246
|
+
- lib/saml/kit/template.rb
|
216
247
|
- lib/saml/kit/trustable.rb
|
217
248
|
- lib/saml/kit/version.rb
|
218
249
|
- lib/saml/kit/xml.rb
|