saml-kit 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
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