spid 0.10.0 → 0.11.0

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
2
  SHA256:
3
- metadata.gz: 960e16fa23660bf794d8569793c49f01671883612e6e96c56d9cc9ec7584c887
4
- data.tar.gz: 18aa49e2bd0173eb7aaae0141fd199c73fc97f4f9538e04e998fd459f4406e1f
3
+ metadata.gz: 8d65f97b5bd606942de9c2bba4a7fe60fadb90de3bf8526d8c80bec3a2ce29ff
4
+ data.tar.gz: 72d85f52db6688edb9f90f3176af9889b15052b8bc7a45b3eee1c61e269cb825
5
5
  SHA512:
6
- metadata.gz: 294072c36735dd72f29e0b66a5d8df0118637079223faa7a9f8b71778cd2b871b639174267b775c6505d1723d1b5e4126b4e243941a6a6f9cecdf4a028c87394
7
- data.tar.gz: 18525e552a24740ad2f51bc73f7d7e96c1f1ab583ea96372c04f6560a6df8efe7af2cb802b0631e68b61594e010f9c6790a40d8f0b17b5575207ce4fafe5bb83
6
+ metadata.gz: 7c0ed6e05c1b45a9a395ea4f4c41c6b45279adc712546bd167ed17a0a3dfba4f28367b287394c22078e95abe561253903153e253a1a967ac4adcf669393a0448
7
+ data.tar.gz: a8f863472e7f5dcd85abbdb514b3aa8509ac42d7eab1c76eac53aa5eab9af5ae4bef44d159855a0d4cdb609f085a58d878299390243cfde3bb9d9754d96ed316
@@ -3,6 +3,7 @@ require: rubocop-rspec
3
3
  AllCops:
4
4
  Exclude:
5
5
  - bin/stubs/*
6
+ - lib/spid/saml2/idp_metadata_parser.rb
6
7
  TargetRubyVersion: 2.3
7
8
 
8
9
  Layout/DotPosition:
@@ -22,6 +23,8 @@ RSpec/FilePath:
22
23
  Exclude:
23
24
  - spec/integration/**/*.rb
24
25
  - spec/requests/**/*.rb
26
+ RSpec/MultipleExpectations:
27
+ Max: 2
25
28
  RSpec/NestedGroups:
26
29
  Enabled: false
27
30
  RSpec/SubjectStub:
@@ -2,6 +2,10 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.11.0] - 2018-08-23
6
+ ### Changed
7
+ - Use custom Saml2 library instead of ruby-saml gem
8
+
5
9
  ## [0.10.0] - 2018-08-02
6
10
  ### Added
7
11
  - Handled Relay State in sso/slo responses
@@ -89,7 +93,8 @@
89
93
  - Coveralls Integration
90
94
  - Rubygems version badge in README
91
95
 
92
- [Unreleased]: https://github.com/italia/spid-ruby/compare/v0.10.0...HEAD
96
+ [Unreleased]: https://github.com/italia/spid-ruby/compare/v0.11.0...HEAD
97
+ [0.11.0]: https://github.com/italia/spid-ruby/compare/v0.10.0...v0.11.0
93
98
  [0.10.0]: https://github.com/italia/spid-ruby/compare/v0.9.0...v0.10.0
94
99
  [0.9.0]: https://github.com/italia/spid-ruby/compare/v0.8.0...v0.9.0
95
100
  [0.8.0]: https://github.com/italia/spid-ruby/compare/v0.7.0...v0.8.0
data/Gemfile CHANGED
@@ -2,11 +2,5 @@
2
2
 
3
3
  source "https://rubygems.org"
4
4
 
5
- git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
6
-
7
5
  # Specify your gem's dependencies in spid.gemspec
8
6
  gemspec
9
-
10
- gem "ruby-saml",
11
- github: "davidlibrera/ruby-saml",
12
- ref: "4204afc2439f712db8909bccfd8d6e15f9320c34"
data/README.md CHANGED
@@ -17,9 +17,6 @@ Ruby library for SPID authentication
17
17
  Add into your Gemfile
18
18
 
19
19
  ```ruby
20
- gem "ruby-saml",
21
- github: "davidlibrera/ruby-saml",
22
- ref: "571e280031883abe3aad7c5b856353f94354fd06"
23
20
  gem "spid"
24
21
  ```
25
22
 
@@ -29,19 +26,19 @@ gem "spid"
29
26
  |<img src="https://github.com/italia/spid-graphics/blob/master/spid-logos/spid-logo-c-lb.png?raw=true" width="100" /><br />_Compliance with [SPID regulations](http://www.agid.gov.it/sites/default/files/circolari/spid-regole_tecniche_v1.pdf) (for Service Providers)_||
30
27
  |:---|:---|
31
28
  |**Metadata:**||
32
- |parsing of IdP XML metadata (1.2.2.4)||
29
+ |parsing of IdP XML metadata (1.2.2.4)|✓|
33
30
  |parsing of AA XML metadata (2.2.4)||
34
- |SP XML metadata generation (1.3.2)||
31
+ |SP XML metadata generation (1.3.2)|✓|
35
32
  |**AuthnRequest generation (1.2.2.1):**||
36
33
  |generation of AuthnRequest XML|✓|
37
- |HTTP-Redirect binding||
38
- |HTTP-POST binding|✓|
39
- |`AssertionConsumerServiceURL` customization||
34
+ |HTTP-Redirect binding|✓|
35
+ |HTTP-POST binding||
36
+ |`AssertionConsumerServiceURL` customization|✓|
40
37
  |`AssertionConsumerServiceIndex` customization||
41
38
  |`AttributeConsumingServiceIndex` customization||
42
39
  |`AuthnContextClassRef` (SPID level) customization|✓|
43
- |`RequestedAuthnContext/@Comparison` customization|✓|
44
- |`RelayState` customization (1.2.2)||
40
+ |`RequestedAuthnContext/@Comparison` customization||
41
+ |`RelayState` customization (1.2.2)|✓|
45
42
  |**Response/Assertion parsing**||
46
43
  |verification of `Response/Signature` value (if any)||
47
44
  |verification of `Response/Signature` certificate (if any) against IdP/AA metadata||
@@ -62,13 +59,13 @@ gem "spid"
62
59
  |parsing of `AuthnContextClassRef` (SPID level)||
63
60
  |parsing of attributes||
64
61
  |**Response/Assertion parsing for attribute query (2.2.2.2, 2.3.1):**||
65
- |parsing of attributes||
62
+ |parsing of attributes|✓|
66
63
  |**LogoutRequest generation (for SP-initiated logout):**||
67
- |generation of LogoutRequest XML||
68
- |HTTP-Redirect binding||
64
+ |generation of LogoutRequest XML|✓|
65
+ |HTTP-Redirect binding|✓|
69
66
  |HTTP-POST binding||
70
67
  |**LogoutResponse parsing (for SP-initiated logout):**||
71
- |parsing of LogoutResponse XML||
68
+ |parsing of LogoutResponse XML|✓|
72
69
  |verification of `Response/Signature` value (if any)||
73
70
  |verification of `Response/Signature` certificate (if any) against IdP metadata||
74
71
  |verification of `Issuer`||
@@ -1,15 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spid/authn_request"
4
- require "spid/logout_request"
3
+ require "spid/saml2"
5
4
  require "spid/sso"
6
5
  require "spid/slo"
7
6
  require "spid/rack"
8
7
  require "spid/metadata"
9
8
  require "spid/version"
10
9
  require "spid/configuration"
11
- require "spid/identity_provider"
12
- require "spid/service_provider"
13
10
  require "spid/identity_provider_manager"
14
11
 
15
12
  module Spid # :nodoc:
@@ -33,9 +30,9 @@ module Spid # :nodoc:
33
30
  MAXIMUM_COMPARISON
34
31
  ].freeze
35
32
 
36
- SHA256 = XMLSecurity::Document::SHA256
37
- SHA384 = XMLSecurity::Document::SHA384
38
- SHA512 = XMLSecurity::Document::SHA512
33
+ SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256"
34
+ SHA384 = "http://www.w3.org/2001/04/xmldsig-more#sha384"
35
+ SHA512 = "http://www.w3.org/2001/04/xmlenc#sha512"
39
36
 
40
37
  DIGEST_METHODS = [
41
38
  SHA256,
@@ -43,9 +40,9 @@ module Spid # :nodoc:
43
40
  SHA512
44
41
  ].freeze
45
42
 
46
- RSA_SHA256 = XMLSecurity::Document::RSA_SHA256
47
- RSA_SHA384 = XMLSecurity::Document::RSA_SHA384
48
- RSA_SHA512 = XMLSecurity::Document::RSA_SHA512
43
+ RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
44
+ RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
45
+ RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
49
46
 
50
47
  SIGNATURE_METHODS = [
51
48
  RSA_SHA256,
@@ -53,6 +50,15 @@ module Spid # :nodoc:
53
50
  RSA_SHA512
54
51
  ].freeze
55
52
 
53
+ SIGNATURE_ALGORITHMS = {
54
+ SHA256 => OpenSSL::Digest::SHA256.new,
55
+ SHA384 => OpenSSL::Digest::SHA384.new,
56
+ SHA512 => OpenSSL::Digest::SHA512.new,
57
+ RSA_SHA256 => OpenSSL::Digest::SHA256.new,
58
+ RSA_SHA384 => OpenSSL::Digest::SHA384.new,
59
+ RSA_SHA512 => OpenSSL::Digest::SHA512.new
60
+ }.freeze
61
+
56
62
  L1 = "https://www.spid.gov.it/SpidL1"
57
63
  L2 = "https://www.spid.gov.it/SpidL2"
58
64
  L3 = "https://www.spid.gov.it/SpidL3"
@@ -18,43 +18,51 @@ module Spid
18
18
  attr_accessor :acs_binding
19
19
  attr_accessor :slo_binding
20
20
 
21
- # rubocop:disable Metrics/MethodLength
22
21
  def initialize
23
22
  @idp_metadata_dir_path = "idp_metadata"
23
+ @attribute_service_name = nil
24
+ init_endpoint
25
+ init_bindings
26
+ init_dig_sig_methods
27
+ init_openssl_keys
28
+ end
29
+
30
+ def init_endpoint
31
+ @hostname = nil
24
32
  @metadata_path = "/spid/metadata"
25
33
  @start_sso_path = "/spid/login"
26
34
  @start_slo_path = "/spid/logout"
27
35
  @acs_path = "/spid/sso"
28
36
  @slo_path = "/spid/slo"
37
+ @default_relay_state_path = "/"
38
+ end
39
+
40
+ def init_bindings
41
+ @acs_binding = Spid::BINDINGS_HTTP_POST
42
+ @slo_binding = Spid::BINDINGS_HTTP_REDIRECT
43
+ end
44
+
45
+ def init_dig_sig_methods
29
46
  @digest_method = Spid::SHA256
30
47
  @signature_method = Spid::RSA_SHA256
31
- @attribute_service_name = nil
32
- @hostname = nil
48
+ end
49
+
50
+ def init_openssl_keys
33
51
  @private_key = nil
34
52
  @certificate = nil
35
- @default_relay_state_path = "/"
36
- @acs_binding = Spid::BINDINGS_HTTP_POST
37
- @slo_binding = Spid::BINDINGS_HTTP_REDIRECT
38
53
  end
39
- # rubocop:enable Metrics/MethodLength
40
54
 
41
- # rubocop:disable Metrics/MethodLength
42
55
  def service_provider
43
56
  @service_provider ||=
44
57
  begin
45
- Spid::ServiceProvider.new(
46
- host: hostname,
47
- acs_path: acs_path,
48
- slo_path: slo_path,
49
- metadata_path: metadata_path,
50
- private_key: private_key,
51
- certificate: certificate,
52
- digest_method: digest_method,
53
- signature_method: signature_method,
54
- attribute_service_name: attribute_service_name
58
+ Spid::Saml2::ServiceProvider.new(
59
+ acs_binding: acs_binding, acs_path: acs_path, slo_path: slo_path,
60
+ slo_binding: slo_binding, metadata_path: metadata_path,
61
+ private_key: private_key, certificate: certificate,
62
+ digest_method: digest_method, signature_method: signature_method,
63
+ attribute_service_name: attribute_service_name, host: hostname
55
64
  )
56
65
  end
57
66
  end
58
- # rubocop:enable Metrics/MethodLength
59
67
  end
60
68
  end
@@ -9,7 +9,7 @@ module Spid
9
9
  begin
10
10
  Dir.chdir(Spid.configuration.idp_metadata_dir_path) do
11
11
  Dir.glob("*.xml").map do |metadata_filepath|
12
- generate_identity_provider_from_file(
12
+ self.class.generate_identity_provider_from_file(
13
13
  File.expand_path(metadata_filepath)
14
14
  )
15
15
  end
@@ -29,12 +29,22 @@ module Spid
29
29
  end
30
30
  end
31
31
 
32
- private
32
+ def self.parse_from_xml(name:, metadata:)
33
+ idp_metadata_parser = ::Spid::Saml2::IdpMetadataParser.new
34
+ idp_settings = idp_metadata_parser.parse_to_hash(metadata)
35
+ ::Spid::Saml2::IdentityProvider.new(
36
+ name: name,
37
+ entity_id: idp_settings[:idp_entity_id],
38
+ sso_target_url: idp_settings[:idp_sso_target_url],
39
+ slo_target_url: idp_settings[:idp_slo_target_url],
40
+ cert_fingerprint: idp_settings[:idp_cert_fingerprint]
41
+ )
42
+ end
33
43
 
34
- def generate_identity_provider_from_file(metadata_filepath)
44
+ def self.generate_identity_provider_from_file(metadata_filepath)
35
45
  idp_name = File.basename(metadata_filepath, "-metadata.xml")
36
46
  metadata = File.read(metadata_filepath)
37
- IdentityProvider.parse_from_xml(
47
+ parse_from_xml(
38
48
  metadata: metadata,
39
49
  name: idp_name
40
50
  )
@@ -1,93 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "onelogin/ruby-saml/metadata"
4
- require "onelogin/ruby-saml/settings"
5
-
6
3
  module Spid
7
4
  class Metadata # :nodoc:
8
- attr_reader :metadata_attributes
9
-
10
- # rubocop:disable Metrics/MethodLength
11
- def initialize(
12
- digest_method: Spid::SHA256,
13
- signature_method: Spid::RSA_SHA256
14
- )
15
- @metadata_attributes = {
16
- issuer: issuer,
17
- private_key: private_key_content,
18
- certificate: certificate_content,
19
- assertion_consumer_service_url: assertion_consumer_service_url,
20
- assertion_consumer_service_binding: Spid.configuration.acs_binding,
21
- single_logout_service_url: single_logout_service_url,
22
- single_logout_service_binding: Spid.configuration.slo_binding,
23
- security: {
24
- authn_requests_signed: true,
25
- logout_requests_signed: false,
26
- logout_responses_signed: false,
27
- want_assertions_signed: false,
28
- want_assertions_encrypted: false,
29
- want_name_id: false,
30
- metadata_signed: true,
31
- embed_sign: false,
32
- digest_method: digest_method,
33
- signature_method: signature_method
34
- }
35
- }
36
- end
37
- # rubocop:enable Metrics/MethodLength
38
-
39
- def to_xml
40
- metadata.generate(saml_settings)
41
- end
5
+ attr_reader :sp_metadata
42
6
 
43
- def issuer
44
- service_provider.host
7
+ def initialize
8
+ @sp_metadata = Spid::Saml2::SPMetadata.new(settings: settings)
45
9
  end
46
10
 
47
- def private_key_content
48
- service_provider.private_key
11
+ def settings
12
+ @settings ||= Spid::Saml2::Settings.new(
13
+ service_provider: service_provider,
14
+ identity_provider: nil
15
+ )
49
16
  end
50
17
 
51
- def certificate_content
52
- service_provider.certificate
53
- end
54
-
55
- def assertion_consumer_service_url
56
- service_provider.acs_url
57
- end
58
-
59
- def single_logout_service_url
60
- service_provider.slo_url
61
- end
62
-
63
- def attribute_service_name
64
- service_provider.attribute_service_name
18
+ def to_xml
19
+ sp_metadata.to_saml
65
20
  end
66
21
 
67
22
  def service_provider
68
23
  @service_provider ||= Spid.configuration.service_provider
69
24
  end
70
-
71
- private
72
-
73
- def metadata
74
- ::OneLogin::RubySaml::Metadata.new
75
- end
76
-
77
- def saml_settings
78
- @saml_settings = ::OneLogin::RubySaml::Settings.new metadata_attributes
79
-
80
- outer_self = self
81
-
82
- @saml_settings.attribute_consuming_service.configure do
83
- service_index 0
84
- service_name outer_self.attribute_service_name
85
- add_attribute name: "Name",
86
- name_format: "Name Format",
87
- friendly_name: "Friendly Name"
88
- end
89
-
90
- @saml_settings
91
- end
92
25
  end
93
26
  end
@@ -38,7 +38,7 @@ module Spid
38
38
  Spid::Sso::Request.new(
39
39
  idp_name: idp_name,
40
40
  relay_state: relay_state
41
- ).to_saml
41
+ ).url
42
42
  end
43
43
 
44
44
  def valid_request?
@@ -39,7 +39,7 @@ module Spid
39
39
  idp_name: idp_name,
40
40
  relay_state: relay_state,
41
41
  session_index: spid_session["session-index"]
42
- ).to_saml
42
+ ).url
43
43
  end
44
44
 
45
45
  def valid_request?
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal:true
2
+
3
+ require "spid/saml2/service_provider"
4
+ require "spid/saml2/identity_provider"
5
+ require "spid/saml2/settings"
6
+ require "spid/saml2/authn_request"
7
+ require "spid/saml2/response"
8
+ require "spid/saml2/logout_request"
9
+ require "spid/saml2/logout_response"
10
+ require "spid/saml2/sp_metadata"
11
+ require "spid/saml2/utils"
12
+ require "spid/saml2/idp_metadata_parser"
13
+
14
+ module Spid
15
+ module Saml2 # :nodoc:
16
+ end
17
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rexml/document"
4
+
5
+ module Spid
6
+ module Saml2
7
+ class AuthnRequest # :nodoc:
8
+ attr_reader :document
9
+ attr_reader :uuid
10
+ attr_reader :settings
11
+
12
+ def initialize(uuid: nil, settings:)
13
+ @document = REXML::Document.new
14
+ @uuid = uuid || SecureRandom.uuid
15
+ @settings = settings
16
+ end
17
+
18
+ def to_saml
19
+ document.add_element(authn_request)
20
+ document.to_s
21
+ end
22
+
23
+ def authn_request
24
+ @authn_request ||=
25
+ begin
26
+ element = REXML::Element.new("samlp:AuthnRequest")
27
+ element.add_attributes(authn_request_attributes)
28
+ element.add_element(issuer)
29
+ element.add_element(name_id_policy)
30
+ element.add_element(requested_authn_context)
31
+ element
32
+ end
33
+ end
34
+
35
+ # rubocop:disable Metrics/MethodLength
36
+ def authn_request_attributes
37
+ @authn_request_attributes ||=
38
+ begin
39
+ attributes = {
40
+ "xmlns:samlp" => "urn:oasis:names:tc:SAML:2.0:protocol",
41
+ "xmlns:saml" => "urn:oasis:names:tc:SAML:2.0:assertion",
42
+ "ID" => "_#{uuid}",
43
+ "Version" => "2.0",
44
+ "IssueInstant" => issue_instant,
45
+ "Destination" => settings.idp_sso_target_url,
46
+ "AssertionConsumerServiceIndex" => settings.acs_index
47
+ }
48
+ attributes["ForceAuthn"] = true if settings.force_authn?
49
+ attributes
50
+ end
51
+ end
52
+ # rubocop:enable Metrics/MethodLength
53
+
54
+ def issuer
55
+ @issuer ||=
56
+ begin
57
+ element = REXML::Element.new("saml:Issuer")
58
+ element.add_attributes(
59
+ "Format" => "urn:oasis:names:tc:SAML:2.0:nameid-format:entity",
60
+ "NameQualifier" => settings.sp_entity_id
61
+ )
62
+ element.text = settings.sp_entity_id
63
+ element
64
+ end
65
+ end
66
+
67
+ def name_id_policy
68
+ @name_id_policy ||=
69
+ begin
70
+ element = REXML::Element.new("samlp:NameIDPolicy")
71
+ element.add_attributes(
72
+ "Format" => "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
73
+ )
74
+ element
75
+ end
76
+ end
77
+
78
+ def requested_authn_context
79
+ @requested_authn_context ||=
80
+ begin
81
+ element = REXML::Element.new("samlp:RequestedAuthnContext")
82
+ element.add_attributes(
83
+ "Comparison" => Spid::MINIMUM_COMPARISON
84
+ )
85
+ element.add_element(authn_context_class_ref)
86
+ element
87
+ end
88
+ end
89
+
90
+ def authn_context_class_ref
91
+ @authn_context_class_ref ||=
92
+ begin
93
+ element = REXML::Element.new("saml:AuthnContextClassRef")
94
+ element.text = settings.authn_context
95
+ element
96
+ end
97
+ end
98
+
99
+ def issue_instant
100
+ @issue_instant ||= Time.now.utc.iso8601
101
+ end
102
+ end
103
+ end
104
+ end