spid 0.12.0 → 0.13.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 +4 -4
- data/.gitignore +2 -1
- data/CHANGELOG.md +6 -1
- data/README.md +13 -13
- data/lib/spid/configuration.rb +10 -2
- data/lib/spid/identity_provider_manager.rb +5 -1
- data/lib/spid/saml2.rb +2 -0
- data/lib/spid/saml2/identity_provider.rb +6 -1
- data/lib/spid/saml2/logout_response.rb +6 -0
- data/lib/spid/saml2/logout_response_validator.rb +30 -0
- data/lib/spid/saml2/response.rb +36 -4
- data/lib/spid/saml2/response_validator.rb +56 -0
- data/lib/spid/saml2/settings.rb +4 -0
- data/lib/spid/saml2/utils.rb +5 -0
- data/lib/spid/saml2/utils/query_params_signer.rb +1 -1
- data/lib/spid/slo/response.rb +11 -1
- data/lib/spid/sso/response.rb +18 -3
- data/lib/spid/version.rb +1 -1
- data/spid.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83dc2ec01f9adb676d89eb91c160f3aacacf30cb6473514fc5c4655b1f2c0f32
|
4
|
+
data.tar.gz: ce9606fdab6a9349888111b259979269977643add8e6f68a15a26c5286d38b82
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d5b83dcc34a604397c5d60a682081d04064777cc54cf72fc1f61e3e0a6703215856715c5bd553335ad128231ac4da0a80a2bc084063bd130860566b84369e86
|
7
|
+
data.tar.gz: dcea75e1ce343c0a3e3297a02f78f889150ae0693a3a68a1258fdab1d7d24999ec99a79d1e53a1b87544fd15c144559f91f4b0f19c0633814271b35c6c0760f0
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
## [Unreleased]
|
4
4
|
|
5
|
+
## [0.13.0] - 2018-08-29
|
6
|
+
### Added
|
7
|
+
- Validation of Response and LogoutResponse
|
8
|
+
|
5
9
|
## [0.12.0] - 2018-08-27
|
6
10
|
### Added
|
7
11
|
- AttributeConsumingService management
|
@@ -97,7 +101,8 @@
|
|
97
101
|
- Coveralls Integration
|
98
102
|
- Rubygems version badge in README
|
99
103
|
|
100
|
-
[Unreleased]: https://github.com/italia/spid-ruby/compare/v0.
|
104
|
+
[Unreleased]: https://github.com/italia/spid-ruby/compare/v0.13.0...HEAD
|
105
|
+
[0.13.0]: https://github.com/italia/spid-ruby/compare/v0.12.0...v0.13.0
|
101
106
|
[0.12.0]: https://github.com/italia/spid-ruby/compare/v0.11.0...v0.12.0
|
102
107
|
[0.11.0]: https://github.com/italia/spid-ruby/compare/v0.10.0...v0.11.0
|
103
108
|
[0.10.0]: https://github.com/italia/spid-ruby/compare/v0.9.0...v0.10.0
|
data/README.md
CHANGED
@@ -35,31 +35,31 @@ gem "spid"
|
|
35
35
|
|HTTP-POST binding||
|
36
36
|
|`AssertionConsumerServiceURL` customization|✓|
|
37
37
|
|`AssertionConsumerServiceIndex` customization||
|
38
|
-
|`AttributeConsumingServiceIndex` customization
|
38
|
+
|`AttributeConsumingServiceIndex` customization|✓|
|
39
39
|
|`AuthnContextClassRef` (SPID level) customization|✓|
|
40
40
|
|`RequestedAuthnContext/@Comparison` customization||
|
41
41
|
|`RelayState` customization (1.2.2)|✓|
|
42
42
|
|**Response/Assertion parsing**||
|
43
43
|
|verification of `Response/Signature` value (if any)||
|
44
44
|
|verification of `Response/Signature` certificate (if any) against IdP/AA metadata||
|
45
|
-
|verification of `Assertion/Signature` value
|
46
|
-
|verification of `Assertion/Signature` certificate against IdP/AA metadata
|
45
|
+
|verification of `Assertion/Signature` value|✓|
|
46
|
+
|verification of `Assertion/Signature` certificate against IdP/AA metadata|✓|
|
47
47
|
|verification of `SubjectConfirmationData/@Recipient`||
|
48
48
|
|verification of `SubjectConfirmationData/@NotOnOrAfter`||
|
49
49
|
|verification of `SubjectConfirmationData/@InResponseTo`||
|
50
|
-
|verification of `Issuer
|
51
|
-
|verification of `Destination
|
52
|
-
|verification of `Conditions/@NotBefore
|
53
|
-
|verification of `Conditions/@NotOnOrAfter
|
54
|
-
|verification of `Audience
|
50
|
+
|verification of `Issuer`|✓|
|
51
|
+
|verification of `Destination`|✓|
|
52
|
+
|verification of `Conditions/@NotBefore`|✓|
|
53
|
+
|verification of `Conditions/@NotOnOrAfter`|✓|
|
54
|
+
|verification of `Audience`|✓|
|
55
55
|
|parsing of Response with no `Assertion` (authentication/query failure)||
|
56
56
|
|parsing of failure `StatusCode` (Requester/Responder)||
|
57
57
|
|**Response/Assertion parsing for SSO (1.2.1, 1.2.2.2, 1.3.1):**||
|
58
|
-
|parsing of `NameID
|
58
|
+
|parsing of `NameID`|✓|
|
59
59
|
|parsing of `AuthnContextClassRef` (SPID level)||
|
60
|
-
|parsing of attributes||
|
61
|
-
|**Response/Assertion parsing for attribute query (2.2.2.2, 2.3.1):**||
|
62
60
|
|parsing of attributes|✓|
|
61
|
+
|**Response/Assertion parsing for attribute query (2.2.2.2, 2.3.1):**||
|
62
|
+
|parsing of attributes||
|
63
63
|
|**LogoutRequest generation (for SP-initiated logout):**||
|
64
64
|
|generation of LogoutRequest XML|✓|
|
65
65
|
|HTTP-Redirect binding|✓|
|
@@ -68,8 +68,8 @@ gem "spid"
|
|
68
68
|
|parsing of LogoutResponse XML|✓|
|
69
69
|
|verification of `Response/Signature` value (if any)||
|
70
70
|
|verification of `Response/Signature` certificate (if any) against IdP metadata||
|
71
|
-
|verification of `Issuer
|
72
|
-
|verification of `Destination
|
71
|
+
|verification of `Issuer`|✓|
|
72
|
+
|verification of `Destination`|✓|
|
73
73
|
|PartialLogout detection||
|
74
74
|
|**LogoutRequest parsing (for third-party-initiated logout):**||
|
75
75
|
|parsing of LogoutRequest XML||
|
data/lib/spid/configuration.rb
CHANGED
@@ -11,12 +11,12 @@ module Spid
|
|
11
11
|
attr_accessor :slo_path
|
12
12
|
attr_accessor :digest_method
|
13
13
|
attr_accessor :signature_method
|
14
|
-
attr_accessor :private_key
|
15
|
-
attr_accessor :certificate
|
16
14
|
attr_accessor :default_relay_state_path
|
17
15
|
attr_accessor :acs_binding
|
18
16
|
attr_accessor :slo_binding
|
19
17
|
attr_accessor :attribute_services
|
18
|
+
attr_writer :private_key
|
19
|
+
attr_writer :certificate
|
20
20
|
|
21
21
|
def initialize
|
22
22
|
@idp_metadata_dir_path = "idp_metadata"
|
@@ -52,6 +52,14 @@ module Spid
|
|
52
52
|
@certificate = nil
|
53
53
|
end
|
54
54
|
|
55
|
+
def certificate
|
56
|
+
OpenSSL::X509::Certificate.new(@certificate) unless @certificate.nil?
|
57
|
+
end
|
58
|
+
|
59
|
+
def private_key
|
60
|
+
OpenSSL::PKey::RSA.new(@private_key) unless @private_key.nil?
|
61
|
+
end
|
62
|
+
|
55
63
|
def service_provider
|
56
64
|
@service_provider ||=
|
57
65
|
begin
|
@@ -1,7 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "base64"
|
4
|
+
|
3
5
|
module Spid
|
4
6
|
class IdentityProviderManager # :nodoc:
|
7
|
+
extend Spid::Saml2::Utils
|
5
8
|
include Singleton
|
6
9
|
|
7
10
|
def identity_providers
|
@@ -37,7 +40,8 @@ module Spid
|
|
37
40
|
entity_id: idp_settings[:idp_entity_id],
|
38
41
|
sso_target_url: idp_settings[:idp_sso_target_url],
|
39
42
|
slo_target_url: idp_settings[:idp_slo_target_url],
|
40
|
-
cert_fingerprint: idp_settings[:idp_cert_fingerprint]
|
43
|
+
cert_fingerprint: idp_settings[:idp_cert_fingerprint],
|
44
|
+
certificate: certificate_from_encoded_der(idp_settings[:idp_cert])
|
41
45
|
)
|
42
46
|
end
|
43
47
|
|
data/lib/spid/saml2.rb
CHANGED
@@ -10,6 +10,8 @@ require "spid/saml2/logout_response"
|
|
10
10
|
require "spid/saml2/sp_metadata"
|
11
11
|
require "spid/saml2/utils"
|
12
12
|
require "spid/saml2/idp_metadata_parser"
|
13
|
+
require "spid/saml2/response_validator"
|
14
|
+
require "spid/saml2/logout_response_validator"
|
13
15
|
|
14
16
|
module Spid
|
15
17
|
module Saml2 # :nodoc:
|
@@ -8,20 +8,25 @@ module Spid
|
|
8
8
|
attr_reader :sso_target_url
|
9
9
|
attr_reader :slo_target_url
|
10
10
|
attr_reader :cert_fingerprint
|
11
|
+
attr_reader :certificate
|
11
12
|
|
13
|
+
# rubocop:disable Metrics/ParameterLists
|
12
14
|
def initialize(
|
13
15
|
name:,
|
14
16
|
entity_id:,
|
15
17
|
sso_target_url:,
|
16
18
|
slo_target_url:,
|
17
|
-
cert_fingerprint
|
19
|
+
cert_fingerprint:,
|
20
|
+
certificate:
|
18
21
|
)
|
19
22
|
@name = name
|
20
23
|
@entity_id = entity_id
|
21
24
|
@sso_target_url = sso_target_url
|
22
25
|
@slo_target_url = slo_target_url
|
23
26
|
@cert_fingerprint = cert_fingerprint
|
27
|
+
@certificate = certificate
|
24
28
|
end
|
29
|
+
# rubocop:enable Metrics/ParameterLists
|
25
30
|
end
|
26
31
|
end
|
27
32
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Spid
|
4
|
+
module Saml2
|
5
|
+
class LogoutResponseValidator # :nodoc:
|
6
|
+
attr_reader :response
|
7
|
+
attr_reader :settings
|
8
|
+
|
9
|
+
def initialize(response:, settings:)
|
10
|
+
@response = response
|
11
|
+
@settings = settings
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
[
|
16
|
+
destination,
|
17
|
+
issuer
|
18
|
+
].all?
|
19
|
+
end
|
20
|
+
|
21
|
+
def destination
|
22
|
+
response.destination == settings.sp_slo_service_url
|
23
|
+
end
|
24
|
+
|
25
|
+
def issuer
|
26
|
+
response.issuer == settings.idp_entity_id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/spid/saml2/response.rb
CHANGED
@@ -7,13 +7,11 @@ module Spid
|
|
7
7
|
class Response # :nodoc:
|
8
8
|
include Spid::Saml2::Utils
|
9
9
|
|
10
|
-
attr_reader :body
|
11
10
|
attr_reader :saml_message
|
12
11
|
attr_reader :document
|
13
12
|
|
14
|
-
def initialize(
|
15
|
-
@
|
16
|
-
@saml_message = decode_and_inflate(body)
|
13
|
+
def initialize(saml_message:)
|
14
|
+
@saml_message = saml_message
|
17
15
|
@document = REXML::Document.new(@saml_message)
|
18
16
|
end
|
19
17
|
|
@@ -21,6 +19,22 @@ module Spid
|
|
21
19
|
document.elements["/samlp:Response/saml:Issuer/text()"]&.value
|
22
20
|
end
|
23
21
|
|
22
|
+
def name_id
|
23
|
+
document.elements[
|
24
|
+
"/samlp:Response/saml:Assertion/saml:Subject/saml:NameID/text()"
|
25
|
+
]&.value
|
26
|
+
end
|
27
|
+
|
28
|
+
def raw_certificate
|
29
|
+
xpath = "/samlp:Response/saml:Assertion/ds:Signature/ds:KeyInfo"
|
30
|
+
xpath = "#{xpath}/ds:X509Data/ds:X509Certificate/text()"
|
31
|
+
document.elements[xpath]&.value
|
32
|
+
end
|
33
|
+
|
34
|
+
def certificate
|
35
|
+
certificate_from_encoded_der(raw_certificate)
|
36
|
+
end
|
37
|
+
|
24
38
|
def assertion_issuer
|
25
39
|
document.elements[
|
26
40
|
"/samlp:Response/saml:Assertion/saml:Issuer/text()"
|
@@ -39,6 +53,24 @@ module Spid
|
|
39
53
|
]&.value
|
40
54
|
end
|
41
55
|
|
56
|
+
def conditions_not_before
|
57
|
+
document.elements[
|
58
|
+
"/samlp:Response/saml:Assertion/saml:Conditions/@NotBefore"
|
59
|
+
]&.value
|
60
|
+
end
|
61
|
+
|
62
|
+
def conditions_not_on_or_after
|
63
|
+
document.elements[
|
64
|
+
"/samlp:Response/saml:Assertion/saml:Conditions/@NotOnOrAfter"
|
65
|
+
]&.value
|
66
|
+
end
|
67
|
+
|
68
|
+
def audience
|
69
|
+
xpath = "/samlp:Response/saml:Assertion/saml:Conditions"
|
70
|
+
xpath = "#{xpath}/saml:AudienceRestriction/saml:Audience/text()"
|
71
|
+
document.elements[xpath]&.value
|
72
|
+
end
|
73
|
+
|
42
74
|
def attributes
|
43
75
|
main_xpath = "/samlp:Response/saml:Assertion/saml:AttributeStatement"
|
44
76
|
main_xpath = "#{main_xpath}/saml:Attribute"
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "xmldsig"
|
4
|
+
|
5
|
+
module Spid
|
6
|
+
module Saml2
|
7
|
+
class ResponseValidator # :nodoc:
|
8
|
+
attr_reader :response
|
9
|
+
attr_reader :settings
|
10
|
+
|
11
|
+
def initialize(response:, settings:)
|
12
|
+
@response = response
|
13
|
+
@settings = settings
|
14
|
+
end
|
15
|
+
|
16
|
+
def call
|
17
|
+
[
|
18
|
+
issuer,
|
19
|
+
certificate,
|
20
|
+
destination,
|
21
|
+
conditions,
|
22
|
+
audience,
|
23
|
+
signature
|
24
|
+
].all?
|
25
|
+
end
|
26
|
+
|
27
|
+
def issuer
|
28
|
+
response.assertion_issuer == settings.idp_entity_id
|
29
|
+
end
|
30
|
+
|
31
|
+
def certificate
|
32
|
+
response.certificate.to_der == settings.idp_certificate.to_der
|
33
|
+
end
|
34
|
+
|
35
|
+
def destination
|
36
|
+
response.destination == settings.sp_acs_url
|
37
|
+
end
|
38
|
+
|
39
|
+
def conditions
|
40
|
+
time = Time.now.iso8601
|
41
|
+
|
42
|
+
response.conditions_not_before <= time &&
|
43
|
+
response.conditions_not_on_or_after > time
|
44
|
+
end
|
45
|
+
|
46
|
+
def audience
|
47
|
+
response.audience == settings.sp_entity_id
|
48
|
+
end
|
49
|
+
|
50
|
+
def signature
|
51
|
+
signed_document = Xmldsig::SignedDocument.new(response.saml_message)
|
52
|
+
signed_document.validate(response.certificate)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/spid/saml2/settings.rb
CHANGED
data/lib/spid/saml2/utils.rb
CHANGED
data/lib/spid/slo/response.rb
CHANGED
@@ -14,7 +14,10 @@ module Spid
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def valid?
|
17
|
-
|
17
|
+
Spid::Saml2::LogoutResponseValidator.new(
|
18
|
+
response: saml_response,
|
19
|
+
settings: settings
|
20
|
+
).call
|
18
21
|
end
|
19
22
|
|
20
23
|
def errors
|
@@ -35,6 +38,13 @@ module Spid
|
|
35
38
|
saml_response.issuer
|
36
39
|
end
|
37
40
|
|
41
|
+
def settings
|
42
|
+
@settings ||= Spid::Saml2::Settings.new(
|
43
|
+
service_provider: service_provider,
|
44
|
+
identity_provider: identity_provider
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
38
48
|
def saml_response
|
39
49
|
@saml_response ||= Spid::Saml2::LogoutResponse.new(
|
40
50
|
body: body
|
data/lib/spid/sso/response.rb
CHANGED
@@ -1,22 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "spid/saml2/utils"
|
3
4
|
require "active_support/inflector/methods"
|
4
5
|
|
5
6
|
module Spid
|
6
7
|
module Sso
|
7
8
|
class Response # :nodoc:
|
9
|
+
include Spid::Saml2::Utils
|
10
|
+
|
8
11
|
attr_reader :body
|
12
|
+
attr_reader :saml_message
|
9
13
|
|
10
14
|
def initialize(body:)
|
11
15
|
@body = body
|
16
|
+
@saml_message = decode_and_inflate(body)
|
12
17
|
end
|
13
18
|
|
14
19
|
def valid?
|
15
|
-
|
20
|
+
Spid::Saml2::ResponseValidator.new(
|
21
|
+
response: saml_response,
|
22
|
+
settings: settings
|
23
|
+
).call
|
16
24
|
end
|
17
25
|
|
18
26
|
def issuer
|
19
|
-
saml_response.
|
27
|
+
saml_response.assertion_issuer
|
20
28
|
end
|
21
29
|
|
22
30
|
def attributes
|
@@ -44,7 +52,14 @@ module Spid
|
|
44
52
|
end
|
45
53
|
|
46
54
|
def saml_response
|
47
|
-
@saml_response ||= Spid::Saml2::Response.new(
|
55
|
+
@saml_response ||= Spid::Saml2::Response.new(saml_message: saml_message)
|
56
|
+
end
|
57
|
+
|
58
|
+
def settings
|
59
|
+
@settings ||= Spid::Saml2::Settings.new(
|
60
|
+
identity_provider: identity_provider,
|
61
|
+
service_provider: service_provider
|
62
|
+
)
|
48
63
|
end
|
49
64
|
|
50
65
|
private
|
data/lib/spid/version.rb
CHANGED
data/spid.gemspec
CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |spec|
|
|
26
26
|
|
27
27
|
spec.add_runtime_dependency "activesupport", ">= 3.0.0", "< 5.3"
|
28
28
|
spec.add_runtime_dependency "rack", ">= 1", "< 3"
|
29
|
+
spec.add_runtime_dependency "xmldsig", ">= 0.6.6"
|
29
30
|
|
30
31
|
spec.add_development_dependency "bundler", "~> 1.16"
|
31
32
|
spec.add_development_dependency "bundler-audit", "~> 0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spid
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Librera
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-08-
|
11
|
+
date: 2018-08-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -50,6 +50,20 @@ dependencies:
|
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '3'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: xmldsig
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.6.6
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.6.6
|
53
67
|
- !ruby/object:Gem::Dependency
|
54
68
|
name: bundler
|
55
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -313,7 +327,9 @@ files:
|
|
313
327
|
- lib/spid/saml2/idp_metadata_parser.rb
|
314
328
|
- lib/spid/saml2/logout_request.rb
|
315
329
|
- lib/spid/saml2/logout_response.rb
|
330
|
+
- lib/spid/saml2/logout_response_validator.rb
|
316
331
|
- lib/spid/saml2/response.rb
|
332
|
+
- lib/spid/saml2/response_validator.rb
|
317
333
|
- lib/spid/saml2/service_provider.rb
|
318
334
|
- lib/spid/saml2/settings.rb
|
319
335
|
- lib/spid/saml2/sp_metadata.rb
|