spid 0.7.0 → 0.8.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/.rubocop.yml +8 -0
- data/CHANGELOG.md +11 -1
- data/README.md +1 -1
- data/lib/spid.rb +24 -12
- data/lib/spid/configuration.rb +54 -0
- data/lib/spid/identity_provider.rb +60 -0
- data/lib/spid/identity_provider_manager.rb +43 -0
- data/lib/spid/metadata.rb +14 -12
- data/lib/spid/service_provider.rb +107 -0
- data/lib/spid/slo.rb +10 -0
- data/lib/spid/slo/request.rb +50 -0
- data/lib/spid/slo/response.rb +72 -0
- data/lib/spid/slo/settings.rb +53 -0
- data/lib/spid/sso.rb +10 -0
- data/lib/spid/sso/request.rb +53 -0
- data/lib/spid/sso/response.rb +80 -0
- data/lib/spid/sso/settings.rb +78 -0
- data/lib/spid/version.rb +1 -1
- metadata +14 -12
- data/lib/spid/identity_provider_configuration.rb +0 -34
- data/lib/spid/identity_providers.rb +0 -57
- data/lib/spid/idp_metadata.rb +0 -38
- data/lib/spid/service_provider_configuration.rb +0 -73
- data/lib/spid/slo_request.rb +0 -24
- data/lib/spid/slo_response.rb +0 -27
- data/lib/spid/slo_settings.rb +0 -59
- data/lib/spid/sso_request.rb +0 -24
- data/lib/spid/sso_response.rb +0 -48
- data/lib/spid/sso_settings.rb +0 -77
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spid
|
4
|
-
class IdentityProviderConfiguration # :nodoc:
|
5
|
-
attr_reader :idp_metadata, :idp_metadata_hash
|
6
|
-
|
7
|
-
def initialize(idp_metadata:)
|
8
|
-
@idp_metadata = idp_metadata
|
9
|
-
@idp_metadata_hash = idp_metadata_parser.parse_to_hash(idp_metadata)
|
10
|
-
end
|
11
|
-
|
12
|
-
def entity_id
|
13
|
-
@entity_id ||= idp_metadata_hash[:idp_entity_id]
|
14
|
-
end
|
15
|
-
|
16
|
-
def sso_target_url
|
17
|
-
@sso_target_url ||= idp_metadata_hash[:idp_sso_target_url]
|
18
|
-
end
|
19
|
-
|
20
|
-
def slo_target_url
|
21
|
-
@slo_target_url ||= idp_metadata_hash[:idp_slo_target_url]
|
22
|
-
end
|
23
|
-
|
24
|
-
def cert_fingerprint
|
25
|
-
@cert_fingerprint ||= idp_metadata_hash[:idp_cert_fingerprint]
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def idp_metadata_parser
|
31
|
-
@idp_metadata_parser ||= ::OneLogin::RubySaml::IdpMetadataParser.new
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "faraday"
|
4
|
-
require "faraday_middleware"
|
5
|
-
|
6
|
-
module Spid
|
7
|
-
class IdentityProviders # :nodoc:
|
8
|
-
class MetadataFetchError < StandardError; end
|
9
|
-
|
10
|
-
def self.fetch_all
|
11
|
-
new.fetch_all
|
12
|
-
end
|
13
|
-
|
14
|
-
def fetch_all
|
15
|
-
spid_idp_entities.map do |idp|
|
16
|
-
metadata_url = check_for_final_metadata_url(idp["metadata_url"])
|
17
|
-
{
|
18
|
-
name: idp["entity_name"].gsub(/ ID$/, "").downcase,
|
19
|
-
metadata_url: metadata_url,
|
20
|
-
entity_id: idp["entity_id"]
|
21
|
-
}
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def check_for_final_metadata_url(metadata_url)
|
28
|
-
response = Faraday.get(metadata_url)
|
29
|
-
case response.status
|
30
|
-
when 200
|
31
|
-
metadata_url
|
32
|
-
when 301, 302
|
33
|
-
response["Location"]
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def spid_idp_entities
|
38
|
-
return [] if response.body["spidFederationRegistry"].nil?
|
39
|
-
response.body["spidFederationRegistry"]["entities"]
|
40
|
-
end
|
41
|
-
|
42
|
-
def response
|
43
|
-
connection.get do |req|
|
44
|
-
req.url "/api/identity-providers"
|
45
|
-
req.headers["Accept"] = "application/json"
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def connection
|
50
|
-
Faraday.new("https://registry.spid.gov.it") do |conn|
|
51
|
-
conn.response :json, content_type: /\bjson$/
|
52
|
-
|
53
|
-
conn.adapter Faraday.default_adapter
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/lib/spid/idp_metadata.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "singleton"
|
4
|
-
require "onelogin/ruby-saml/idp_metadata_parser"
|
5
|
-
|
6
|
-
module Spid
|
7
|
-
class IdpMetadata # :nodoc:
|
8
|
-
include Singleton
|
9
|
-
|
10
|
-
def initialize
|
11
|
-
@identity_providers = Spid::IdentityProviders.fetch_all
|
12
|
-
@metadata = {}
|
13
|
-
end
|
14
|
-
|
15
|
-
def [](idp_name)
|
16
|
-
return @metadata[idp_name] unless @metadata[idp_name].nil?
|
17
|
-
idp_hash = identity_provider_hash(idp_name)
|
18
|
-
|
19
|
-
@metadata[idp_name] = parser.parse_remote_to_hash(
|
20
|
-
idp_hash[:metadata_url],
|
21
|
-
idp_hash[:metadata_url].start_with?("https://")
|
22
|
-
)
|
23
|
-
@metadata[idp_name]
|
24
|
-
end
|
25
|
-
|
26
|
-
def identity_provider_hash(idp_name)
|
27
|
-
@identity_providers.find do |idp|
|
28
|
-
idp[:name] == idp_name.to_s
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
private
|
33
|
-
|
34
|
-
def parser
|
35
|
-
@parser ||= ::OneLogin::RubySaml::IdpMetadataParser.new
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "uri"
|
4
|
-
|
5
|
-
module Spid
|
6
|
-
class ServiceProviderConfiguration # :nodoc:
|
7
|
-
attr_reader :host,
|
8
|
-
:sso_path,
|
9
|
-
:slo_path,
|
10
|
-
:metadata_path,
|
11
|
-
:private_key_file_path,
|
12
|
-
:certificate_file_path,
|
13
|
-
:digest_method,
|
14
|
-
:signature_method
|
15
|
-
|
16
|
-
# rubocop:disable Metrics/ParameterLists
|
17
|
-
def initialize(
|
18
|
-
host:,
|
19
|
-
sso_path:,
|
20
|
-
slo_path:,
|
21
|
-
metadata_path:,
|
22
|
-
private_key_file_path:,
|
23
|
-
certificate_file_path:,
|
24
|
-
digest_method:,
|
25
|
-
signature_method:
|
26
|
-
)
|
27
|
-
@host = host
|
28
|
-
@sso_path = sso_path
|
29
|
-
@slo_path = slo_path
|
30
|
-
@metadata_path = metadata_path
|
31
|
-
@private_key_file_path = private_key_file_path
|
32
|
-
@certificate_file_path = certificate_file_path
|
33
|
-
@digest_method = digest_method
|
34
|
-
@signature_method = signature_method
|
35
|
-
validate_attributes
|
36
|
-
end
|
37
|
-
# rubocop:enable Metrics/ParameterLists
|
38
|
-
|
39
|
-
def sso_url
|
40
|
-
@sso_url ||= URI.join(host, sso_path).to_s
|
41
|
-
end
|
42
|
-
|
43
|
-
def slo_url
|
44
|
-
@slo_url ||= URI.join(host, slo_path).to_s
|
45
|
-
end
|
46
|
-
|
47
|
-
def metadata_url
|
48
|
-
@metadata_url ||= URI.join(host, metadata_path).to_s
|
49
|
-
end
|
50
|
-
|
51
|
-
def private_key
|
52
|
-
@private_key ||= File.read(private_key_file_path)
|
53
|
-
end
|
54
|
-
|
55
|
-
def certificate
|
56
|
-
@certificate ||= File.read(certificate_file_path)
|
57
|
-
end
|
58
|
-
|
59
|
-
private
|
60
|
-
|
61
|
-
def validate_attributes
|
62
|
-
if !DIGEST_METHODS.include?(digest_method)
|
63
|
-
raise UnknownDigestMethodError,
|
64
|
-
"Provided digest method is not valid:" \
|
65
|
-
" use one of #{DIGEST_METHODS.join(', ')}"
|
66
|
-
elsif !SIGNATURE_METHODS.include?(signature_method)
|
67
|
-
raise UnknownSignatureMethodError,
|
68
|
-
"Provided digest method is not valid:" \
|
69
|
-
" use one of #{SIGNATURE_METHODS.join(', ')}"
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
data/lib/spid/slo_request.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spid/logout_request"
|
4
|
-
require "onelogin/ruby-saml/settings"
|
5
|
-
|
6
|
-
module Spid
|
7
|
-
class SloRequest # :nodoc:
|
8
|
-
attr_reader :slo_settings
|
9
|
-
|
10
|
-
def initialize(slo_settings:)
|
11
|
-
@slo_settings = slo_settings
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_saml
|
15
|
-
logout_request.create(slo_settings)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def logout_request
|
21
|
-
LogoutRequest.new
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/spid/slo_response.rb
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "onelogin/ruby-saml/logoutresponse"
|
4
|
-
|
5
|
-
module Spid
|
6
|
-
class SloResponse # :nodoc:
|
7
|
-
attr_reader :body, :slo_settings
|
8
|
-
|
9
|
-
def initialize(body:, slo_settings:)
|
10
|
-
@body = body
|
11
|
-
@slo_settings = slo_settings
|
12
|
-
end
|
13
|
-
|
14
|
-
def valid?
|
15
|
-
saml_response.validate
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def saml_response
|
21
|
-
@saml_response ||= ::OneLogin::RubySaml::Logoutresponse.new(
|
22
|
-
body,
|
23
|
-
slo_settings
|
24
|
-
)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/lib/spid/slo_settings.rb
DELETED
@@ -1,59 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "onelogin/ruby-saml/settings"
|
4
|
-
|
5
|
-
module Spid
|
6
|
-
class SloSettings < ::OneLogin::RubySaml::Settings # :nodoc:
|
7
|
-
attr_reader :service_provider_configuration,
|
8
|
-
:identity_provider_configuration,
|
9
|
-
:session_index
|
10
|
-
|
11
|
-
def initialize(
|
12
|
-
service_provider_configuration:,
|
13
|
-
identity_provider_configuration:,
|
14
|
-
session_index:
|
15
|
-
)
|
16
|
-
@service_provider_configuration = service_provider_configuration
|
17
|
-
@identity_provider_configuration = identity_provider_configuration
|
18
|
-
@session_index = session_index
|
19
|
-
|
20
|
-
super(slo_attributes)
|
21
|
-
end
|
22
|
-
|
23
|
-
# rubocop:disable Metrics/MethodLength
|
24
|
-
# rubocop:disable Metrics/AbcSize
|
25
|
-
def slo_attributes
|
26
|
-
return @slo_attributes if @slo_attributes.present?
|
27
|
-
@slo_attributes = {
|
28
|
-
idp_slo_target_url: identity_provider_configuration.slo_target_url,
|
29
|
-
issuer: service_provider_configuration.host,
|
30
|
-
idp_name_qualifier: identity_provider_configuration.entity_id,
|
31
|
-
name_identifier_value: generated_name_identifier_value,
|
32
|
-
name_identifier_format: name_identifier_format_value,
|
33
|
-
private_key: service_provider_configuration.private_key,
|
34
|
-
certificate: service_provider_configuration.certificate,
|
35
|
-
idp_cert_fingerprint: identity_provider_configuration.cert_fingerprint,
|
36
|
-
sessionindex: session_index,
|
37
|
-
security: {
|
38
|
-
logout_requests_signed: true,
|
39
|
-
embed_sign: true,
|
40
|
-
digest_method: service_provider_configuration.digest_method,
|
41
|
-
signature_method: service_provider_configuration.signature_method
|
42
|
-
}
|
43
|
-
}
|
44
|
-
@slo_attributes
|
45
|
-
end
|
46
|
-
# rubocop:enable Metrics/AbcSize
|
47
|
-
# rubocop:enable Metrics/MethodLength
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def generated_name_identifier_value
|
52
|
-
::OneLogin::RubySaml::Utils.uuid
|
53
|
-
end
|
54
|
-
|
55
|
-
def name_identifier_format_value
|
56
|
-
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
data/lib/spid/sso_request.rb
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "spid/authn_request"
|
4
|
-
require "onelogin/ruby-saml/settings"
|
5
|
-
|
6
|
-
module Spid
|
7
|
-
class SsoRequest # :nodoc:
|
8
|
-
attr_reader :sso_settings
|
9
|
-
|
10
|
-
def initialize(sso_settings:)
|
11
|
-
@sso_settings = sso_settings
|
12
|
-
end
|
13
|
-
|
14
|
-
def to_saml
|
15
|
-
authn_request.create(sso_settings)
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def authn_request
|
21
|
-
AuthnRequest.new
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
data/lib/spid/sso_response.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "onelogin/ruby-saml/response"
|
4
|
-
require "active_support/inflector/methods"
|
5
|
-
|
6
|
-
module Spid
|
7
|
-
class SsoResponse # :nodoc:
|
8
|
-
attr_reader :body, :sso_settings
|
9
|
-
|
10
|
-
def initialize(body:, sso_settings:)
|
11
|
-
@body = body
|
12
|
-
@sso_settings = sso_settings
|
13
|
-
end
|
14
|
-
|
15
|
-
def valid?
|
16
|
-
saml_response.is_valid?
|
17
|
-
end
|
18
|
-
|
19
|
-
def attributes
|
20
|
-
raw_attributes.each_with_object({}) do |(key, value), acc|
|
21
|
-
acc[normalize_key(key)] = value
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def session_index
|
26
|
-
saml_response.sessionindex
|
27
|
-
end
|
28
|
-
|
29
|
-
def raw_attributes
|
30
|
-
saml_response.attributes.attributes
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def normalize_key(key)
|
36
|
-
ActiveSupport::Inflector.underscore(
|
37
|
-
key.to_s
|
38
|
-
).to_sym
|
39
|
-
end
|
40
|
-
|
41
|
-
def saml_response
|
42
|
-
@saml_response ||= ::OneLogin::RubySaml::Response.new(
|
43
|
-
body,
|
44
|
-
settings: sso_settings
|
45
|
-
)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
data/lib/spid/sso_settings.rb
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spid
|
4
|
-
class SsoSettings < ::OneLogin::RubySaml::Settings # :nodoc:
|
5
|
-
attr_reader :service_provider_configuration,
|
6
|
-
:identity_provider_configuration,
|
7
|
-
:authn_context,
|
8
|
-
:authn_context_comparison
|
9
|
-
|
10
|
-
# rubocop:disable Metrics/MethodLength
|
11
|
-
def initialize(
|
12
|
-
service_provider_configuration:,
|
13
|
-
identity_provider_configuration:,
|
14
|
-
authn_context: Spid::L1,
|
15
|
-
authn_context_comparison: Spid::EXACT_COMPARISON
|
16
|
-
)
|
17
|
-
|
18
|
-
unless AUTHN_CONTEXTS.include?(authn_context)
|
19
|
-
raise Spid::UnknownAuthnContextError,
|
20
|
-
"Provided authn_context is not valid:" \
|
21
|
-
" use one of #{AUTHN_CONTEXTS.join(', ')}"
|
22
|
-
end
|
23
|
-
|
24
|
-
unless COMPARISON_METHODS.include?(authn_context_comparison)
|
25
|
-
raise Spid::UnknownAuthnComparisonMethodError,
|
26
|
-
"Provided authn_context_comparison_method is not valid:" \
|
27
|
-
" use one of #{COMPARISON_METHODS.join(', ')}"
|
28
|
-
end
|
29
|
-
|
30
|
-
@service_provider_configuration = service_provider_configuration
|
31
|
-
@identity_provider_configuration = identity_provider_configuration
|
32
|
-
@authn_context = authn_context
|
33
|
-
@authn_context_comparison = authn_context_comparison
|
34
|
-
|
35
|
-
super(sso_attributes)
|
36
|
-
end
|
37
|
-
# rubocop:enable Metrics/MethodLength
|
38
|
-
|
39
|
-
# rubocop:disable Metrics/MethodLength
|
40
|
-
# rubocop:disable Metrics/AbcSize
|
41
|
-
def sso_attributes
|
42
|
-
return @sso_attributes if @sso_attributes.present?
|
43
|
-
@sso_attributes = {
|
44
|
-
idp_sso_target_url: identity_provider_configuration.sso_target_url,
|
45
|
-
assertion_consumer_service_url: service_provider_configuration.sso_url,
|
46
|
-
protocol_binding: protocol_binding_value,
|
47
|
-
issuer: service_provider_configuration.host,
|
48
|
-
private_key: service_provider_configuration.private_key,
|
49
|
-
certificate: service_provider_configuration.certificate,
|
50
|
-
name_identifier_format: name_identifier_format_value,
|
51
|
-
authn_context: authn_context,
|
52
|
-
authn_context_comparison: authn_context_comparison,
|
53
|
-
idp_cert_fingerprint: identity_provider_configuration.cert_fingerprint,
|
54
|
-
security: {
|
55
|
-
authn_requests_signed: true,
|
56
|
-
embed_sign: true,
|
57
|
-
digest_method: service_provider_configuration.digest_method,
|
58
|
-
signature_method: service_provider_configuration.signature_method
|
59
|
-
}
|
60
|
-
}
|
61
|
-
@sso_attributes[:force_authn] = true if authn_context > Spid::L1
|
62
|
-
@sso_attributes
|
63
|
-
end
|
64
|
-
# rubocop:enable Metrics/AbcSize
|
65
|
-
# rubocop:enable Metrics/MethodLength
|
66
|
-
|
67
|
-
private
|
68
|
-
|
69
|
-
def protocol_binding_value
|
70
|
-
"urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
|
71
|
-
end
|
72
|
-
|
73
|
-
def name_identifier_format_value
|
74
|
-
"urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|