Skip to content

Commit

Permalink
Add remaining specs
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyshields committed Nov 25, 2023
1 parent 0cc9702 commit fed7a15
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 26 deletions.
4 changes: 2 additions & 2 deletions lib/onelogin/ruby-saml/settings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ def get_sp_decryption_keys
pairs.select! { |cert, _| !cert || OneLogin::RubySaml::Utils.is_cert_active(cert) }
end

keys = pairs.map { |pair| pair[1] }.compact.uniq
keys = pairs.map { |pair| pair[1] }.compact.uniq(&:to_pem)

if security[:check_sp_cert_expiration] && keys.empty?
raise OneLogin::RubySaml::ValidationError.new("The SP certificate expired.")
Expand Down Expand Up @@ -359,7 +359,7 @@ def get_sp_certs_multi
key = pair[:private_key] || pair['private_key'] || pair[:key] || pair['key']

unless cert && key
raise ArgumentError.new("sp_cert_multi :#{type} node Hashes must contain keys :certificate and :private_key")
raise ArgumentError.new("sp_cert_multi :#{type} node Hashes must specify keys :certificate and :private_key")
end

certs[type] << [
Expand Down
155 changes: 131 additions & 24 deletions test/settings_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -442,14 +442,16 @@ class SettingsTest < Minitest::Test
describe "#get_sp_certs" do
let(:cert_text1) { ruby_saml_cert_text }
let(:cert_text2) { ruby_saml_cert2.to_pem }
let(:key_text) { ruby_saml_key_text }
let(:cert_text3) { CertificateHelper.generate_cert.to_pem }
let(:key_text1) { ruby_saml_key_text }
let(:key_text2) { CertificateHelper.generate_key.to_pem }

it "returns certs for single case" do
@settings.certificate = cert_text1
@settings.private_key = key_text
@settings.private_key = key_text1

actual = @settings.get_sp_certs
expected = [[cert_text1, key_text]]
expected = [[cert_text1, key_text1]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal expected, actual[:encryption].map {|ary| ary.map(&:to_pem) }
Expand All @@ -458,29 +460,44 @@ class SettingsTest < Minitest::Test
it "returns certs for single case with new cert" do
@settings.certificate = cert_text1
@settings.certificate_new = cert_text2
@settings.private_key = key_text
@settings.private_key = key_text1

actual = @settings.get_sp_certs
expected = [[cert_text1, key_text], [cert_text2, key_text]]
expected = [[cert_text1, key_text1], [cert_text2, key_text1]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal expected, actual[:encryption].map {|ary| ary.map(&:to_pem) }
end

it "returns certs for multi case" do
@settings.sp_cert_multi = {
signing: [{ certificate: cert_text1, private_key: key_text }],
encryption: [{ certificate: cert_text2, private_key: key_text }]
signing: [{ certificate: cert_text1, private_key: key_text1 },
{ certificate: cert_text2, private_key: key_text1 }],
encryption: [{ certificate: cert_text2, private_key: key_text1 },
{ certificate: cert_text3, private_key: key_text2 }]
}

actual = @settings.get_sp_certs
expected_signing = [[cert_text1, key_text]]
expected_encryption = [[cert_text2, key_text]]
expected_signing = [[cert_text1, key_text1], [cert_text2, key_text1]]
expected_encryption = [[cert_text2, key_text1], [cert_text3, key_text2]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected_signing, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal expected_encryption, actual[:encryption].map {|ary| ary.map(&:to_pem) }
end

it "sp_cert_multi allows sending only signing" do
@settings.sp_cert_multi = {
signing: [{ certificate: cert_text1, private_key: key_text1 },
{ certificate: cert_text2, private_key: key_text1 }]
}

actual = @settings.get_sp_certs
expected_signing = [[cert_text1, key_text1], [cert_text2, key_text1]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected_signing, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal [], actual[:encryption]
end

it "raises error when sp_cert_multi is not a Hash" do
@settings.sp_cert_multi = 'invalid_type'

Expand All @@ -500,9 +517,9 @@ class SettingsTest < Minitest::Test
end

it "raises error when sp_cert_multi inner node missing :certificate" do
@settings.sp_cert_multi = { signing: [{ private_key: key_text }] }
@settings.sp_cert_multi = { signing: [{ private_key: key_text1 }] }

error_message = 'sp_cert_multi :signing node Hashes must contain keys :certificate and :private_key'
error_message = 'sp_cert_multi :signing node Hashes must specify keys :certificate and :private_key'
assert_raises ArgumentError, error_message do
@settings.get_sp_certs
end
Expand All @@ -511,42 +528,42 @@ class SettingsTest < Minitest::Test
it "raises error when sp_cert_multi inner node missing :private_key" do
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1 }] }

error_message = 'sp_cert_multi :signing node Hashes must contain keys :certificate and :private_key'
error_message = 'sp_cert_multi :signing node Hashes must specify keys :certificate and :private_key'
assert_raises ArgumentError, error_message do
@settings.get_sp_certs
end
end

it "handles sp_cert_multi with string keys" do
@settings.sp_cert_multi = {
'signing' => [{ 'certificate' => cert_text1, 'private_key' => key_text }],
'encryption' => [{ 'certificate' => cert_text2, 'private_key' => key_text }]
'signing' => [{ 'certificate' => cert_text1, 'private_key' => key_text1 }],
'encryption' => [{ 'certificate' => cert_text2, 'private_key' => key_text1 }]
}

actual = @settings.get_sp_certs
expected_signing = [[cert_text1, key_text]]
expected_encryption = [[cert_text2, key_text]]
expected_signing = [[cert_text1, key_text1]]
expected_encryption = [[cert_text2, key_text1]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected_signing, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal expected_encryption, actual[:encryption].map {|ary| ary.map(&:to_pem) }
end

it "handles sp_cert_multi with alternate inner keys :cert and :key" do
@settings.sp_cert_multi = {
signing: [{ cert: cert_text1, key: key_text }],
encryption: [{ 'cert' => cert_text2, 'key' => key_text }]
signing: [{ cert: cert_text1, key: key_text1 }],
encryption: [{ 'cert' => cert_text2, 'key' => key_text1 }]
}

actual = @settings.get_sp_certs
expected_signing = [[cert_text1, key_text]]
expected_encryption = [[cert_text2, key_text]]
expected_signing = [[cert_text1, key_text1]]
expected_encryption = [[cert_text2, key_text1]]
assert_equal [:signing, :encryption], actual.keys
assert_equal expected_signing, actual[:signing].map {|ary| ary.map(&:to_pem) }
assert_equal expected_encryption, actual[:encryption].map {|ary| ary.map(&:to_pem) }
end

it "raises error when both sp_cert_multi and certificate are specified" do
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text }] }
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text1 }] }
@settings.certificate = cert_text1

error_message = 'Cannot specify both sp_cert_multi and certificate, certificate_new, private_key parameters'
Expand All @@ -556,7 +573,7 @@ class SettingsTest < Minitest::Test
end

it "raises error when both sp_cert_multi and certificate_new are specified" do
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text }] }
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text1 }] }
@settings.certificate_new = cert_text2

error_message = 'Cannot specify both sp_cert_multi and certificate, certificate_new, private_key parameters'
Expand All @@ -566,14 +583,104 @@ class SettingsTest < Minitest::Test
end

it "raises error when both sp_cert_multi and private_key are specified" do
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text }] }
@settings.private_key = key_text
@settings.sp_cert_multi = { signing: [{ certificate: cert_text1, private_key: key_text1 }] }
@settings.private_key = key_text1

error_message = 'Cannot specify both sp_cert_multi and certificate, certificate_new, private_key parameters'
assert_raises ArgumentError, error_message do
@settings.get_sp_certs
end
end
end

describe "#get_sp_signing_pair and #get_sp_signing_key" do
let(:valid_pair) { CertificateHelper.generate_pair_hash }
let(:early_pair) { CertificateHelper.generate_pair_hash(not_before: Time.now + 60) }
let(:expired) { CertificateHelper.generate_pair_hash(not_after: Time.now - 60) }

it "returns nil when no signing pairs are present" do
@settings.sp_cert_multi = { signing: [] }

assert_nil @settings.get_sp_signing_pair
assert_nil @settings.get_sp_signing_key
end

it "returns the first pair if check_sp_cert_expiration is false" do
@settings.security = { check_sp_cert_expiration: false }
@settings.sp_cert_multi = { signing: [early_pair, expired, valid_pair] }

assert_equal early_pair.values, @settings.get_sp_signing_pair.map(&:to_pem)
assert_equal early_pair[:private_key], @settings.get_sp_signing_key.to_pem
end

it "returns the first active pair when check_sp_cert_expiration is true" do
@settings.security = { check_sp_cert_expiration: true }
@settings.sp_cert_multi = { signing: [early_pair, expired, valid_pair] }

assert_equal valid_pair.values, @settings.get_sp_signing_pair.map(&:to_pem)
assert_equal valid_pair[:private_key], @settings.get_sp_signing_key.to_pem
end

it "raises error when all certificates are expired and check_sp_cert_expiration is true" do
@settings.security = { check_sp_cert_expiration: true }
@settings.sp_cert_multi = { signing: [early_pair, expired] }

assert_raises OneLogin::RubySaml::ValidationError do
@settings.get_sp_signing_pair
end

assert_raises OneLogin::RubySaml::ValidationError do
@settings.get_sp_signing_key
end
end
end

describe "#get_sp_decryption_keys" do
let(:valid_pair) { CertificateHelper.generate_pair_hash }
let(:early_pair) { CertificateHelper.generate_pair_hash(not_before: Time.now + 60) }
let(:expired_pair) { CertificateHelper.generate_pair_hash(not_after: Time.now - 60) }

it "returns an empty array when no decryption pairs are present" do
@settings.sp_cert_multi = { encryption: [] }

assert_empty @settings.get_sp_decryption_keys
end

it "returns all keys when check_sp_cert_expiration is false" do
@settings.security = { check_sp_cert_expiration: false }
@settings.sp_cert_multi = { encryption: [early_pair, expired_pair, valid_pair] }

expected_keys = [early_pair, expired_pair, valid_pair].map { |pair| pair[:private_key] }
actual_keys = @settings.get_sp_decryption_keys.map(&:to_pem)
assert_equal expected_keys, actual_keys
end

it "returns only keys of active certificates when check_sp_cert_expiration is true" do
@settings.security = { check_sp_cert_expiration: true }
@settings.sp_cert_multi = { encryption: [early_pair, expired_pair, valid_pair] }

expected_keys = [valid_pair[:private_key]]
actual_keys = @settings.get_sp_decryption_keys.map(&:to_pem)
assert_equal expected_keys, actual_keys
end

it "raises error when all certificates are expired and check_sp_cert_expiration is true" do
@settings.security = { check_sp_cert_expiration: true }
@settings.sp_cert_multi = { encryption: [early_pair, expired_pair] }

assert_raises OneLogin::RubySaml::ValidationError do
@settings.get_sp_decryption_keys
end
end

it "removes duplicates" do
@settings.sp_cert_multi = { encryption: [early_pair, valid_pair, early_pair, valid_pair] }

expected_keys = [early_pair, valid_pair].map { |pair| pair[:private_key] }
actual_keys = @settings.get_sp_decryption_keys.map(&:to_pem)

assert_equal expected_keys, actual_keys
end
end
end
end

0 comments on commit fed7a15

Please sign in to comment.