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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0a54e04d0c915cf2ed6df1ffa201fca9abea800e
4
- data.tar.gz: f38bb36f287bc9f9b7c185eb00b7c87641f99f23
2
+ SHA256:
3
+ metadata.gz: a7bdb0c763a06da013ef3be5a99b550dfaad5a3cfa5d56cbe1c8effef7e597eb
4
+ data.tar.gz: 12d4f27c8537146a0e7eae7ffdbfcfc088673a94edcb59d2d7e04b13990b8ad9
5
5
  SHA512:
6
- metadata.gz: 9bf0e3a075afb0fb4b1038b265a39382a3463cf4b4c490d45cd605534341a4b2227fdf09709af556da2b94e25ca0d50fecd440b5e0ff2e68076fd2584010b110
7
- data.tar.gz: ed750eb4bf73f1f631b83c4b17d2ddb1e15907955ce686b9ddaaa591a27c22a79fcac0b76a86ac3898e7c59b2d23e12616965286de614e1cd2b7f118ffd96f0f
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/[USERNAME]/saml-kit.
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 acs_url
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
- Response::Builder.new(user, self)
20
- end
21
-
22
- private
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
@@ -9,7 +9,6 @@ module Saml
9
9
  end
10
10
 
11
11
  def serialize(builder, relay_state: nil)
12
- builder.sign = true
13
12
  builder.destination = location
14
13
  document = builder.build
15
14
  saml_params = {
@@ -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