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