saml-kit 0.2.1 → 0.2.2
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 +5 -5
- data/README.md +1 -1
- data/exe/saml-kit-create-self-signed-certificate +21 -0
- data/lib/saml/kit.rb +9 -1
- data/lib/saml/kit/authentication_request.rb +9 -47
- data/lib/saml/kit/bindings/http_post.rb +0 -1
- data/lib/saml/kit/buildable.rb +21 -0
- data/lib/saml/kit/builders.rb +13 -0
- data/lib/saml/kit/builders/authentication_request.rb +48 -0
- data/lib/saml/kit/builders/identity_provider_metadata.rb +103 -0
- data/lib/saml/kit/builders/logout_request.rb +55 -0
- data/lib/saml/kit/builders/logout_response.rb +50 -0
- data/lib/saml/kit/builders/response.rb +182 -0
- data/lib/saml/kit/builders/service_provider_metadata.rb +89 -0
- data/lib/saml/kit/document.rb +16 -0
- data/lib/saml/kit/id.rb +9 -0
- data/lib/saml/kit/identity_provider_metadata.rb +11 -96
- data/lib/saml/kit/logout_request.rb +7 -53
- data/lib/saml/kit/logout_response.rb +1 -50
- data/lib/saml/kit/metadata.rb +9 -0
- data/lib/saml/kit/response.rb +11 -181
- data/lib/saml/kit/self_signed_certificate.rb +12 -5
- data/lib/saml/kit/service_provider_metadata.rb +5 -82
- data/lib/saml/kit/signature.rb +1 -1
- data/lib/saml/kit/trustable.rb +1 -5
- data/lib/saml/kit/version.rb +1 -1
- data/lib/saml/kit/{cryptography.rb → xml_decryption.rb} +1 -1
- data/saml-kit.gemspec +2 -2
- metadata +32 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: a7bdb0c763a06da013ef3be5a99b550dfaad5a3cfa5d56cbe1c8effef7e597eb
|
4
|
+
data.tar.gz: 12d4f27c8537146a0e7eae7ffdbfcfc088673a94edcb59d2d7e04b13990b8ad9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: da590a94503473525543a63b4922673b78a56cc0fd0252b6d63ef2385aa22e38cbd0fb82833a5ef6fcbf60083d2ca38fdcba8991e12a83603759bdd0bc8b9060
|
7
|
+
data.tar.gz: e22721152e34342c8f0d9f59f7ac1596ae8bf901564e13ae7b1ca1b6311a59e86a102202d536dc253a78cc8acc71f56e3a1cd4e83d121243410ea63783baf13d
|
data/README.md
CHANGED
@@ -32,7 +32,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
32
32
|
|
33
33
|
## Contributing
|
34
34
|
|
35
|
-
Bug reports and pull requests are welcome on GitHub at https://github.com/
|
35
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/mokhan/saml-kit.
|
36
36
|
|
37
37
|
## License
|
38
38
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'saml/kit'
|
3
|
+
|
4
|
+
password = STDIN.read.strip
|
5
|
+
certificate, private_key = Saml::Kit::SelfSignedCertificate.new(password).create
|
6
|
+
|
7
|
+
puts "** BEGIN File Format **"
|
8
|
+
print certificate
|
9
|
+
puts private_key
|
10
|
+
puts "***********************"
|
11
|
+
|
12
|
+
puts
|
13
|
+
|
14
|
+
puts "*** BEGIN ENV Format **"
|
15
|
+
puts certificate.inspect
|
16
|
+
puts private_key.inspect
|
17
|
+
puts "***********************"
|
18
|
+
|
19
|
+
puts
|
20
|
+
puts "Private Key Password:"
|
21
|
+
puts password.inspect
|
data/lib/saml/kit.rb
CHANGED
@@ -5,6 +5,7 @@ require "active_support/core_ext/date/calculations"
|
|
5
5
|
require "active_support/core_ext/hash/conversions"
|
6
6
|
require "active_support/core_ext/hash/indifferent_access"
|
7
7
|
require "active_support/core_ext/numeric/time"
|
8
|
+
require "active_support/deprecation"
|
8
9
|
require "active_support/duration"
|
9
10
|
require "builder"
|
10
11
|
require "logger"
|
@@ -13,6 +14,8 @@ require "nokogiri"
|
|
13
14
|
require "securerandom"
|
14
15
|
require "xmldsig"
|
15
16
|
|
17
|
+
require "saml/kit/buildable"
|
18
|
+
require "saml/kit/builders"
|
16
19
|
require "saml/kit/namespaces"
|
17
20
|
require "saml/kit/serializable"
|
18
21
|
require "saml/kit/xsd_validatable"
|
@@ -26,19 +29,20 @@ require "saml/kit/bindings"
|
|
26
29
|
require "saml/kit/certificate"
|
27
30
|
require "saml/kit/configuration"
|
28
31
|
require "saml/kit/crypto"
|
29
|
-
require "saml/kit/cryptography"
|
30
32
|
require "saml/kit/default_registry"
|
31
33
|
require "saml/kit/fingerprint"
|
32
34
|
require "saml/kit/logout_response"
|
33
35
|
require "saml/kit/logout_request"
|
34
36
|
require "saml/kit/metadata"
|
35
37
|
require "saml/kit/response"
|
38
|
+
require "saml/kit/id"
|
36
39
|
require "saml/kit/identity_provider_metadata"
|
37
40
|
require "saml/kit/invalid_document"
|
38
41
|
require "saml/kit/self_signed_certificate"
|
39
42
|
require "saml/kit/service_provider_metadata"
|
40
43
|
require "saml/kit/signature"
|
41
44
|
require "saml/kit/xml"
|
45
|
+
require "saml/kit/xml_decryption"
|
42
46
|
|
43
47
|
I18n.load_path += Dir[File.expand_path("kit/locales/*.yml", File.dirname(__FILE__))]
|
44
48
|
|
@@ -56,6 +60,10 @@ module Saml
|
|
56
60
|
def logger
|
57
61
|
configuration.logger
|
58
62
|
end
|
63
|
+
|
64
|
+
def registry
|
65
|
+
configuration.registry
|
66
|
+
end
|
59
67
|
end
|
60
68
|
end
|
61
69
|
end
|
@@ -7,7 +7,7 @@ module Saml
|
|
7
7
|
super(xml, name: "AuthnRequest")
|
8
8
|
end
|
9
9
|
|
10
|
-
def
|
10
|
+
def assertion_consumer_service_url
|
11
11
|
to_h[name]['AssertionConsumerServiceURL']
|
12
12
|
end
|
13
13
|
|
@@ -15,54 +15,16 @@ module Saml
|
|
15
15
|
to_h[name]['NameIDPolicy']['Format']
|
16
16
|
end
|
17
17
|
|
18
|
-
def response_for(user)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
class Builder
|
25
|
-
attr_accessor :id, :now, :issuer, :acs_url, :name_id_format, :sign, :destination
|
26
|
-
attr_accessor :version
|
27
|
-
|
28
|
-
def initialize(configuration: Saml::Kit.configuration, sign: true)
|
29
|
-
@id = SecureRandom.uuid
|
30
|
-
@issuer = configuration.issuer
|
31
|
-
@name_id_format = Namespaces::PERSISTENT
|
32
|
-
@now = Time.now.utc
|
33
|
-
@version = "2.0"
|
34
|
-
@sign = sign
|
35
|
-
end
|
36
|
-
|
37
|
-
def to_xml
|
38
|
-
Signature.sign(sign: sign) do |xml, signature|
|
39
|
-
xml.tag!('samlp:AuthnRequest', request_options) do
|
40
|
-
xml.tag!('saml:Issuer', issuer)
|
41
|
-
signature.template(id)
|
42
|
-
xml.tag!('samlp:NameIDPolicy', Format: name_id_format)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def build
|
48
|
-
AuthenticationRequest.new(to_xml)
|
49
|
-
end
|
50
|
-
|
51
|
-
private
|
52
|
-
|
53
|
-
def request_options
|
54
|
-
options = {
|
55
|
-
"xmlns:samlp" => Namespaces::PROTOCOL,
|
56
|
-
"xmlns:saml" => Namespaces::ASSERTION,
|
57
|
-
ID: "_#{id}",
|
58
|
-
Version: version,
|
59
|
-
IssueInstant: now.utc.iso8601,
|
60
|
-
Destination: destination,
|
61
|
-
}
|
62
|
-
options[:AssertionConsumerServiceURL] = acs_url if acs_url.present?
|
63
|
-
options
|
18
|
+
def response_for(user, binding:, relay_state: nil)
|
19
|
+
response_binding = provider.assertion_consumer_service_for(binding: binding)
|
20
|
+
builder = Saml::Kit::Response.builder(user, self) do |x|
|
21
|
+
x.sign = provider.want_assertions_signed
|
22
|
+
yield x if block_given?
|
64
23
|
end
|
24
|
+
response_binding.serialize(builder, relay_state: relay_state)
|
65
25
|
end
|
26
|
+
|
27
|
+
Builder = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Saml::Kit::AuthenticationRequest::Builder', 'Saml::Kit::Builders::AuthenticationRequest')
|
66
28
|
end
|
67
29
|
end
|
68
30
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Buildable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
class_methods do
|
7
|
+
def build(*args)
|
8
|
+
builder(*args).tap do |x|
|
9
|
+
yield x if block_given?
|
10
|
+
end.build
|
11
|
+
end
|
12
|
+
|
13
|
+
def builder(*args)
|
14
|
+
builder_class.new(*args).tap do |builder|
|
15
|
+
yield builder if block_given?
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'saml/kit/builders/authentication_request'
|
2
|
+
require 'saml/kit/builders/identity_provider_metadata'
|
3
|
+
require 'saml/kit/builders/logout_request'
|
4
|
+
require 'saml/kit/builders/logout_response'
|
5
|
+
require 'saml/kit/builders/response'
|
6
|
+
require 'saml/kit/builders/service_provider_metadata'
|
7
|
+
|
8
|
+
module Saml
|
9
|
+
module Kit
|
10
|
+
module Builders
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class AuthenticationRequest
|
5
|
+
attr_accessor :id, :now, :issuer, :assertion_consumer_service_url, :name_id_format, :sign, :destination
|
6
|
+
attr_accessor :version
|
7
|
+
|
8
|
+
def initialize(configuration: Saml::Kit.configuration, sign: true)
|
9
|
+
@id = Id.generate
|
10
|
+
@issuer = configuration.issuer
|
11
|
+
@name_id_format = Namespaces::PERSISTENT
|
12
|
+
@now = Time.now.utc
|
13
|
+
@version = "2.0"
|
14
|
+
@sign = sign
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_xml
|
18
|
+
Signature.sign(sign: sign) do |xml, signature|
|
19
|
+
xml.tag!('samlp:AuthnRequest', request_options) do
|
20
|
+
xml.tag!('saml:Issuer', issuer)
|
21
|
+
signature.template(id)
|
22
|
+
xml.tag!('samlp:NameIDPolicy', Format: name_id_format)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def build
|
28
|
+
Saml::Kit::AuthenticationRequest.new(to_xml)
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def request_options
|
34
|
+
options = {
|
35
|
+
"xmlns:samlp" => Namespaces::PROTOCOL,
|
36
|
+
"xmlns:saml" => Namespaces::ASSERTION,
|
37
|
+
ID: id,
|
38
|
+
Version: version,
|
39
|
+
IssueInstant: now.utc.iso8601,
|
40
|
+
Destination: destination,
|
41
|
+
}
|
42
|
+
options[:AssertionConsumerServiceURL] = assertion_consumer_service_url if assertion_consumer_service_url.present?
|
43
|
+
options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class IdentityProviderMetadata
|
5
|
+
attr_accessor :id, :organization_name, :organization_url, :contact_email, :entity_id, :attributes, :name_id_formats
|
6
|
+
attr_accessor :want_authn_requests_signed, :sign
|
7
|
+
attr_reader :logout_urls, :single_sign_on_urls
|
8
|
+
|
9
|
+
def initialize(configuration = Saml::Kit.configuration)
|
10
|
+
@id = Id.generate
|
11
|
+
@entity_id = configuration.issuer
|
12
|
+
@attributes = []
|
13
|
+
@name_id_formats = [Namespaces::PERSISTENT]
|
14
|
+
@single_sign_on_urls = []
|
15
|
+
@logout_urls = []
|
16
|
+
@configuration = configuration
|
17
|
+
@sign = true
|
18
|
+
@want_authn_requests_signed = true
|
19
|
+
end
|
20
|
+
|
21
|
+
def add_single_sign_on_service(url, binding: :http_post)
|
22
|
+
@single_sign_on_urls.push(location: url, binding: Bindings.binding_for(binding))
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_single_logout_service(url, binding: :http_post)
|
26
|
+
@logout_urls.push(location: url, binding: Bindings.binding_for(binding))
|
27
|
+
end
|
28
|
+
|
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
|
+
def build
|
79
|
+
Saml::Kit::IdentityProviderMetadata.new(to_xml)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def entity_descriptor_options
|
85
|
+
{
|
86
|
+
'xmlns': Namespaces::METADATA,
|
87
|
+
'xmlns:ds': Namespaces::XMLDSIG,
|
88
|
+
'xmlns:saml': Namespaces::ASSERTION,
|
89
|
+
ID: id,
|
90
|
+
entityID: entity_id,
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def idp_sso_descriptor_options
|
95
|
+
{
|
96
|
+
WantAuthnRequestsSigned: want_authn_requests_signed,
|
97
|
+
protocolSupportEnumeration: Namespaces::PROTOCOL,
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class LogoutRequest
|
5
|
+
attr_accessor :id, :destination, :issuer, :name_id_format, :now
|
6
|
+
attr_accessor :sign, :version
|
7
|
+
attr_reader :user
|
8
|
+
|
9
|
+
def initialize(user, configuration: Saml::Kit.configuration, sign: true)
|
10
|
+
@user = user
|
11
|
+
@id = "_#{SecureRandom.uuid}"
|
12
|
+
@issuer = configuration.issuer
|
13
|
+
@name_id_format = Saml::Kit::Namespaces::PERSISTENT
|
14
|
+
@now = Time.now.utc
|
15
|
+
@version = "2.0"
|
16
|
+
@sign = sign
|
17
|
+
end
|
18
|
+
|
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
|
+
def build
|
31
|
+
Saml::Kit::LogoutRequest.new(to_xml)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def logout_request_options
|
37
|
+
{
|
38
|
+
ID: id,
|
39
|
+
Version: version,
|
40
|
+
IssueInstant: now.utc.iso8601,
|
41
|
+
Destination: destination,
|
42
|
+
xmlns: Namespaces::PROTOCOL,
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
def name_id_options
|
47
|
+
{
|
48
|
+
Format: name_id_format,
|
49
|
+
xmlns: Namespaces::ASSERTION,
|
50
|
+
}
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Saml
|
2
|
+
module Kit
|
3
|
+
module Builders
|
4
|
+
class LogoutResponse
|
5
|
+
attr_accessor :id, :issuer, :version, :status_code, :sign, :now, :destination
|
6
|
+
attr_reader :request
|
7
|
+
|
8
|
+
def initialize(user, request, configuration: Saml::Kit.configuration, sign: true)
|
9
|
+
@user = user
|
10
|
+
@now = Time.now.utc
|
11
|
+
@request = request
|
12
|
+
@id = Id.generate
|
13
|
+
@version = "2.0"
|
14
|
+
@status_code = Namespaces::SUCCESS
|
15
|
+
@sign = sign
|
16
|
+
@issuer = configuration.issuer
|
17
|
+
end
|
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
|
29
|
+
end
|
30
|
+
|
31
|
+
def build
|
32
|
+
Saml::Kit::LogoutResponse.new(to_xml, request_id: request.id)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def logout_response_options
|
38
|
+
{
|
39
|
+
xmlns: Namespaces::PROTOCOL,
|
40
|
+
ID: id,
|
41
|
+
Version: version,
|
42
|
+
IssueInstant: now.utc.iso8601,
|
43
|
+
Destination: destination,
|
44
|
+
InResponseTo: request.id,
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|