Commit 12a2aef
Changed files (66)
bin
lib
saml
kit
bindings
builders
rspec
spec
saml
builders
support
bin/console
@@ -1,7 +1,7 @@
#!/usr/bin/env ruby
-require "bundler/setup"
-require "saml/kit"
+require 'bundler/setup'
+require 'saml/kit'
# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.
@@ -10,5 +10,5 @@ require "saml/kit"
# require "pry"
# Pry.start
-require "irb"
+require 'irb'
IRB.start(__FILE__)
exe/saml-kit-create-self-signed-certificate
@@ -3,22 +3,22 @@ require 'saml/kit'
Saml::Kit.deprecate("Use the 'saml-kit-cli' gem instead. saml-kit-create-self-signed-certificate")
-puts "Enter Passphrase:"
+puts 'Enter Passphrase:'
passphrase = STDIN.read.strip
certificate, private_key = ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: passphrase)
-puts "** BEGIN File Format **"
+puts '** BEGIN File Format **'
print certificate
puts private_key
-puts "***********************"
+puts '***********************'
puts
-puts "*** BEGIN ENV Format **"
+puts '*** BEGIN ENV Format **'
puts certificate.inspect
puts private_key.inspect
-puts "***********************"
+puts '***********************'
puts
-puts "Private Key Passphrase:"
+puts 'Private Key Passphrase:'
puts passphrase.inspect
exe/saml-kit-decode-http-redirect
@@ -6,9 +6,13 @@ Saml::Kit.deprecate("Use the 'saml-kit-cli' gem instead. saml-kit-decode-http-re
input = STDIN.read
binding = Saml::Kit::Bindings::HttpRedirect.new(location: '')
-uri = URI.parse(input) rescue nil
+uri = begin
+ URI.parse(input)
+ rescue StandardError
+ nil
+ end
if uri
- query_params = Hash[uri.query.split('&').map { |x| x.split('=', 2) }]
+ query_params = Hash[uri.query.split('&').map { |x| x.split('=', 2) }]
puts binding.deserialize(query_params).to_xml(pretty: true)
else
puts binding.deserialize('SAMLRequest' => input).to_xml(pretty: true)
lib/saml/kit/bindings/binding.rb
@@ -14,12 +14,12 @@ module Saml
binding == other
end
- def serialize(builder, relay_state: nil)
+ def serialize(_builder, relay_state: nil)
[]
end
- def deserialize(params)
- raise ArgumentError.new("Unsupported binding")
+ def deserialize(_params)
+ raise ArgumentError, 'Unsupported binding'
end
def to_h
@@ -27,7 +27,7 @@ module Saml
end
def ==(other)
- self.to_s == other.to_s
+ to_s == other.to_s
end
def eql?(other)
@@ -58,7 +58,7 @@ module Saml
elsif parameters[:SAMLResponse].present?
parameters[:SAMLResponse]
else
- raise ArgumentError.new("SAMLRequest or SAMLResponse parameter is required.")
+ raise ArgumentError, 'SAMLRequest or SAMLResponse parameter is required.'
end
end
end
lib/saml/kit/bindings/http_redirect.rb
@@ -35,25 +35,25 @@ module Saml
return if document.provider.nil?
if document.provider.verify(
- algorithm_for(params[:SigAlg]),
- decode(params[:Signature]),
- canonicalize(params)
+ algorithm_for(params[:SigAlg]),
+ decode(params[:Signature]),
+ canonicalize(params)
)
document.signature_verified!
else
- raise ArgumentError.new("Invalid Signature")
+ raise ArgumentError, 'Invalid Signature'
end
end
def canonicalize(params)
- [:SAMLRequest, :SAMLResponse, :RelayState, :SigAlg].map do |key|
+ %i[SAMLRequest SAMLResponse RelayState SigAlg].map do |key|
value = params[key]
value.present? ? "#{key}=#{value}" : nil
end.compact.join('&')
end
def algorithm_for(algorithm)
- case algorithm =~ /(rsa-)?sha(.*?)$/i && $2.to_i
+ case algorithm =~ /(rsa-)?sha(.*?)$/i && Regexp.last_match(2).to_i
when 256
OpenSSL::Digest::SHA256.new
when 384
lib/saml/kit/bindings/url_builder.rb
@@ -17,7 +17,7 @@ module Saml
else
payload = to_query_string(
saml_document.query_string_parameter => serialize(saml_document.to_xml),
- 'RelayState' => relay_state,
+ 'RelayState' => relay_state
)
"#{saml_document.destination}?#{payload}"
end
@@ -34,7 +34,7 @@ module Saml
to_query_string(
saml_document.query_string_parameter => serialize(saml_document.to_xml),
'RelayState' => relay_state,
- 'SigAlg' => ::Xml::Kit::Namespaces::SHA256,
+ 'SigAlg' => ::Xml::Kit::Namespaces::SHA256
)
end
lib/saml/kit/builders/templates/assertion.builder
@@ -4,7 +4,7 @@ xml.Assertion(assertion_options) do
xml.Subject do
xml.NameID name_id, Format: name_id_format
xml.SubjectConfirmation Method: Saml::Kit::Namespaces::BEARER do
- xml.SubjectConfirmationData "", subject_confirmation_data_options
+ xml.SubjectConfirmationData '', subject_confirmation_data_options
end
end
xml.Conditions conditions_options do
lib/saml/kit/builders/templates/metadata.builder
@@ -4,11 +4,11 @@ xml.EntityDescriptor entity_descriptor_options do
render identity_provider, xml: xml
render service_provider, xml: xml
xml.Organization do
- xml.OrganizationName organization_name, 'xml:lang': "en"
- xml.OrganizationDisplayName organization_name, 'xml:lang': "en"
- xml.OrganizationURL organization_url, 'xml:lang': "en"
+ xml.OrganizationName organization_name, 'xml:lang': 'en'
+ xml.OrganizationDisplayName organization_name, 'xml:lang': 'en'
+ xml.OrganizationURL organization_url, 'xml:lang': 'en'
end
- xml.ContactPerson contactType: "technical" do
+ xml.ContactPerson contactType: 'technical' do
xml.Company "mailto:#{contact_email}"
end
end
lib/saml/kit/builders/templates/service_provider_metadata.builder
@@ -12,6 +12,6 @@ xml.SPSSODescriptor descriptor_options do
xml.NameIDFormat format
end
acs_urls.each_with_index do |item, index|
- xml.AssertionConsumerService Binding: item[:binding], Location: item[:location], index: index, isDefault: index == 0 ? true : false
+ xml.AssertionConsumerService Binding: item[:binding], Location: item[:location], index: index, isDefault: index == 0
end
end
lib/saml/kit/builders/authentication_request.rb
@@ -15,7 +15,7 @@ module Saml
@issuer = configuration.entity_id
@name_id_format = Namespaces::PERSISTENT
@now = Time.now.utc
- @version = "2.0"
+ @version = '2.0'
end
def build
@@ -26,8 +26,8 @@ module Saml
def request_options
options = {
- "xmlns:samlp" => Namespaces::PROTOCOL,
- "xmlns:saml" => Namespaces::ASSERTION,
+ 'xmlns:samlp' => Namespaces::PROTOCOL,
+ 'xmlns:saml' => Namespaces::ASSERTION,
ID: id,
Version: version,
IssueInstant: now.utc.iso8601,
lib/saml/kit/builders/logout_request.rb
@@ -16,7 +16,7 @@ module Saml
@issuer = configuration.entity_id
@name_id_format = Saml::Kit::Namespaces::PERSISTENT
@now = Time.now.utc
- @version = "2.0"
+ @version = '2.0'
end
def build
lib/saml/kit/builders/logout_response.rb
@@ -16,7 +16,7 @@ module Saml
@now = Time.now.utc
@request = request
@status_code = Namespaces::SUCCESS
- @version = "2.0"
+ @version = '2.0'
end
def build
lib/saml/kit/builders/response.rb
@@ -17,7 +17,7 @@ module Saml
@id = ::Xml::Kit::Id.generate
@reference_id = ::Xml::Kit::Id.generate
@now = Time.now.utc
- @version = "2.0"
+ @version = '2.0'
@status_code = Namespaces::SUCCESS
@issuer = configuration.entity_id
@encryption_certificate = request.try(:provider).try(:encryption_certificates).try(:last)
lib/saml/kit/rspec/have_query_param.rb
@@ -6,7 +6,7 @@ RSpec::Matchers.define :have_query_param do |key|
end
def query_params_from(url)
- Hash[query_for(url).split("&").map { |x| x.split('=', 2) }]
+ Hash[query_for(url).split('&').map { |x| x.split('=', 2) }]
end
def uri_for(url)
lib/saml/kit/assertion.rb
@@ -1,12 +1,12 @@
module Saml
module Kit
class Assertion
- XPATH=[
+ include ActiveModel::Validations
+ include Translatable
+ XPATH = [
'/samlp:Response/saml:Assertion',
'/samlp:Response/saml:EncryptedAssertion'
].join('|')
- include ActiveModel::Validations
- include Translatable
validate :must_be_decryptable
validate :must_match_issuer, if: :decryptable?
@@ -16,15 +16,15 @@ module Saml
attr_accessor :occurred_at
def initialize(node, configuration: Saml::Kit.configuration, private_keys: [])
- @name = "Assertion"
+ @name = 'Assertion'
@node = node
@xml_hash = hash_from(node)['Response'] || {}
@configuration = configuration
@occurred_at = Time.current
decrypt!(::Xml::Kit::Decryption.new(
- private_keys: (
- configuration.private_keys(use: :encryption) + private_keys
- ).uniq
+ private_keys: (
+ configuration.private_keys(use: :encryption) + private_keys
+ ).uniq
))
end
@@ -58,7 +58,7 @@ module Saml
begin
attrs = assertion.fetch('AttributeStatement', {}).fetch('Attribute', [])
items = if attrs.is_a? Hash
- [[attrs["Name"], attrs["AttributeValue"]]]
+ [[attrs['Name'], attrs['AttributeValue']]]
else
attrs.map { |item| [item['Name'], item['AttributeValue']] }
end
@@ -76,7 +76,7 @@ module Saml
def audiences
Array(assertion['Conditions']['AudienceRestriction']['Audience'])
- rescue => error
+ rescue StandardError => error
Saml::Kit.logger.error(error)
[]
end
@@ -123,7 +123,7 @@ module Saml
def parse_date(value)
DateTime.parse(value)
- rescue => error
+ rescue StandardError => error
Saml::Kit.logger.error(error)
Time.at(0).to_datetime
end
lib/saml/kit/authentication_request.rb
@@ -25,7 +25,7 @@ module Saml
# @param xml [String] the raw xml.
# @param configuration [Saml::Kit::Configuration] defaults to the global configuration.
def initialize(xml, configuration: Saml::Kit.configuration)
- super(xml, name: "AuthnRequest", configuration: configuration)
+ super(xml, name: 'AuthnRequest', configuration: configuration)
end
# Extract the AssertionConsumerServiceURL from the AuthnRequest
lib/saml/kit/bindings.rb
@@ -1,19 +1,19 @@
-require "saml/kit/bindings/binding"
-require "saml/kit/bindings/http_post"
-require "saml/kit/bindings/http_redirect"
-require "saml/kit/bindings/url_builder"
+require 'saml/kit/bindings/binding'
+require 'saml/kit/bindings/http_post'
+require 'saml/kit/bindings/http_redirect'
+require 'saml/kit/bindings/url_builder'
module Saml
module Kit
module Bindings
- HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'
- HTTP_POST = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
- HTTP_REDIRECT = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+ HTTP_ARTIFACT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact'.freeze
+ HTTP_POST = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST'.freeze
+ HTTP_REDIRECT = 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect'.freeze
ALL = {
http_post: HTTP_POST,
http_redirect: HTTP_REDIRECT,
http_artifact: HTTP_ARTIFACT,
- }
+ }.freeze
def self.binding_for(binding)
ALL[binding]
lib/saml/kit/composite_metadata.rb
@@ -5,7 +5,7 @@ module Saml
attr_reader :service_provider, :identity_provider
def initialize(xml)
- super("IDPSSODescriptor", xml)
+ super('IDPSSODescriptor', xml)
@metadatum = [
Saml::Kit::ServiceProviderMetadata.new(xml),
Saml::Kit::IdentityProviderMetadata.new(xml),
@@ -13,10 +13,10 @@ module Saml
end
def services(type)
- xpath = map { |x| "//md:EntityDescriptor/md:#{x.name}/md:#{type}" }.join("|")
+ xpath = map { |x| "//md:EntityDescriptor/md:#{x.name}/md:#{type}" }.join('|')
document.find_all(xpath).map do |item|
- binding = item.attribute("Binding").value
- location = item.attribute("Location").value
+ binding = item.attribute('Binding').value
+ location = item.attribute('Location').value
Saml::Kit::Bindings.create_for(binding, location)
end
end
lib/saml/kit/configuration.rb
@@ -20,7 +20,7 @@ module Saml
# configuration.add_key_pair(ENV["X509_CERTIFICATE"], ENV["PRIVATE_KEY"], passphrase: ENV['PRIVATE_KEY_PASSPHRASE'], use: :encryption)
# end
class Configuration
- USES = [:signing, :encryption]
+ USES = %i[signing encryption].freeze
# The issuer to use in requests or responses from this entity to use.
attr_accessor :entity_id
# The signature method to use when generating signatures (See {Saml::Kit::Builders::XmlSignature::SIGNATURE_METHODS})
@@ -98,8 +98,8 @@ module Saml
def ensure_proper_use!(use)
unless USES.include?(use)
- error_message = "Use must be either :signing or :encryption"
- raise ArgumentError.new(error_message)
+ error_message = 'Use must be either :signing or :encryption'
+ raise ArgumentError, error_message
end
end
end
lib/saml/kit/default_registry.rb
@@ -62,7 +62,7 @@ module Saml
# Yields each registered [Saml::Kit::Metadata] to the block.
def each
- @items.each do |key, value|
+ @items.each do |_key, value|
yield value
end
end
lib/saml/kit/document.rb
@@ -1,20 +1,20 @@
module Saml
module Kit
class Document
- PROTOCOL_XSD = File.expand_path("./xsd/saml-schema-protocol-2.0.xsd", File.dirname(__FILE__)).freeze
+ include ActiveModel::Validations
+ include XsdValidatable
+ include Translatable
+ include Trustable
+ include Buildable
+ PROTOCOL_XSD = File.expand_path('./xsd/saml-schema-protocol-2.0.xsd', File.dirname(__FILE__)).freeze
NAMESPACES = {
"NameFormat": ::Saml::Kit::Namespaces::ATTR_SPLAT,
"ds": ::Xml::Kit::Namespaces::XMLDSIG,
"md": ::Saml::Kit::Namespaces::METADATA,
"saml": ::Saml::Kit::Namespaces::ASSERTION,
"samlp": ::Saml::Kit::Namespaces::PROTOCOL,
- "xmlenc" => ::Xml::Kit::Namespaces::XMLENC,
+ 'xmlenc' => ::Xml::Kit::Namespaces::XMLENC,
}.freeze
- include ActiveModel::Validations
- include XsdValidatable
- include Translatable
- include Trustable
- include Buildable
validates_presence_of :content
validates_presence_of :id
validate :must_match_xsd
@@ -64,7 +64,7 @@ module Saml
pretty ? to_nokogiri.to_xml(indent: 2) : content
end
- # Returns the SAML document as an XHTML string.
+ # Returns the SAML document as an XHTML string.
# This is useful for rendering in a web page.
def to_xhtml
Nokogiri::XML(to_xml, &:noblanks).to_xhtml
@@ -91,11 +91,11 @@ module Saml
class << self
XPATH = [
- "/samlp:AuthnRequest",
- "/samlp:LogoutRequest",
- "/samlp:LogoutResponse",
- "/samlp:Response",
- ].join("|")
+ '/samlp:AuthnRequest',
+ '/samlp:LogoutRequest',
+ '/samlp:LogoutResponse',
+ '/samlp:Response',
+ ].join('|')
# Returns the raw xml as a Saml::Kit SAML document.
#
@@ -103,16 +103,16 @@ module Saml
# @param configuration [Saml::Kit::Configuration] the configuration to use for unpacking the document.
def to_saml_document(xml, configuration: Saml::Kit.configuration)
xml_document = ::Xml::Kit::Document.new(xml, namespaces: {
- "samlp": ::Saml::Kit::Namespaces::PROTOCOL
- })
+ "samlp": ::Saml::Kit::Namespaces::PROTOCOL
+ })
constructor = {
- "AuthnRequest" => Saml::Kit::AuthenticationRequest,
- "LogoutRequest" => Saml::Kit::LogoutRequest,
- "LogoutResponse" => Saml::Kit::LogoutResponse,
- "Response" => Saml::Kit::Response,
+ 'AuthnRequest' => Saml::Kit::AuthenticationRequest,
+ 'LogoutRequest' => Saml::Kit::LogoutRequest,
+ 'LogoutResponse' => Saml::Kit::LogoutResponse,
+ 'Response' => Saml::Kit::Response,
}[xml_document.find_by(XPATH).name] || InvalidDocument
constructor.new(xml, configuration: configuration)
- rescue => error
+ rescue StandardError => error
Saml::Kit.logger.error(error)
InvalidDocument.new(xml, configuration: configuration)
end
@@ -129,7 +129,7 @@ module Saml
when Saml::Kit::LogoutRequest.to_s
Saml::Kit::Builders::LogoutRequest
else
- raise ArgumentError.new("Unknown SAML Document #{name}")
+ raise ArgumentError, "Unknown SAML Document #{name}"
end
end
end
@@ -156,7 +156,7 @@ module Saml
def must_be_valid_version
return unless expected_type?
- return if "2.0" == version
+ return if version == '2.0'
errors[:version] << error_message(:invalid_version)
end
end
lib/saml/kit/identity_provider_metadata.rb
@@ -32,15 +32,15 @@ module Saml
# {include:file:spec/examples/identity_provider_metadata_spec.rb}
class IdentityProviderMetadata < Metadata
def initialize(xml)
- super("IDPSSODescriptor", xml)
+ super('IDPSSODescriptor', xml)
end
# Returns the IDPSSODescriptor/@WantAuthnRequestsSigned attribute.
def want_authn_requests_signed
xpath = "/md:EntityDescriptor/md:#{name}"
- attribute = document.find_by(xpath).attribute("WantAuthnRequestsSigned")
+ attribute = document.find_by(xpath).attribute('WantAuthnRequestsSigned')
return true if attribute.nil?
- attribute.text.downcase == "true"
+ attribute.text.casecmp('true').zero?
end
# Returns each of the SingleSignOnService elements.
@@ -59,8 +59,8 @@ module Saml
def attributes
document.find_all("/md:EntityDescriptor/md:#{name}/saml:Attribute").map do |item|
{
- format: item.attribute("NameFormat").try(:value),
- name: item.attribute("Name").value,
+ format: item.attribute('NameFormat').try(:value),
+ name: item.attribute('Name').value,
}
end
end
lib/saml/kit/invalid_document.rb
@@ -7,12 +7,12 @@ module Saml
end
def initialize(xml, configuration: nil)
- super(xml, name: "InvalidDocument")
+ super(xml, name: 'InvalidDocument')
end
def to_h
super
- rescue
+ rescue StandardError
{}
end
end
lib/saml/kit/logout_request.rb
@@ -31,7 +31,7 @@ module Saml
# @param xml [String] The raw xml string.
# @param configuration [Saml::Kit::Configuration] the configuration to use.
def initialize(xml, configuration: Saml::Kit.configuration)
- super(xml, name: "LogoutRequest", configuration: configuration)
+ super(xml, name: 'LogoutRequest', configuration: configuration)
end
# Returns the NameID value.
lib/saml/kit/logout_response.rb
@@ -10,7 +10,7 @@ module Saml
def initialize(xml, request_id: nil, configuration: Saml::Kit.configuration)
@request_id = request_id
- super(xml, name: "LogoutResponse", configuration: configuration)
+ super(xml, name: 'LogoutResponse', configuration: configuration)
end
end
end
lib/saml/kit/metadata.rb
@@ -23,7 +23,11 @@ module Saml
# for a list of options that can be specified.
# {include:file:spec/examples/metadata_spec.rb}
class Metadata
- METADATA_XSD = File.expand_path("./xsd/saml-schema-metadata-2.0.xsd", File.dirname(__FILE__)).freeze
+ include ActiveModel::Validations
+ include XsdValidatable
+ include Translatable
+ include Buildable
+ METADATA_XSD = File.expand_path('./xsd/saml-schema-metadata-2.0.xsd', File.dirname(__FILE__)).freeze
NAMESPACES = {
"NameFormat": Namespaces::ATTR_SPLAT,
"ds": ::Xml::Kit::Namespaces::XMLDSIG,
@@ -31,10 +35,6 @@ module Saml
"saml": Namespaces::ASSERTION,
"samlp": Namespaces::PROTOCOL,
}.freeze
- include ActiveModel::Validations
- include XsdValidatable
- include Translatable
- include Buildable
validates_presence_of :metadata
validate :must_contain_descriptor
@@ -50,7 +50,7 @@ module Saml
# Returns the /EntityDescriptor/@entityID
def entity_id
- document.find_by("/md:EntityDescriptor/@entityID").value
+ document.find_by('/md:EntityDescriptor/@entityID').value
end
# Returns the supported NameIDFormats.
@@ -60,23 +60,23 @@ module Saml
# Returns the Organization Name
def organization_name
- document.find_by("/md:EntityDescriptor/md:Organization/md:OrganizationName").try(:text)
+ document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationName').try(:text)
end
# Returns the Organization URL
def organization_url
- document.find_by("/md:EntityDescriptor/md:Organization/md:OrganizationURL").try(:text)
+ document.find_by('/md:EntityDescriptor/md:Organization/md:OrganizationURL').try(:text)
end
# Returns the Company
def contact_person_company
- document.find_by("/md:EntityDescriptor/md:ContactPerson/md:Company").try(:text)
+ document.find_by('/md:EntityDescriptor/md:ContactPerson/md:Company').try(:text)
end
# Returns each of the X509 certificates.
def certificates
@certificates ||= document.find_all("/md:EntityDescriptor/md:#{name}/md:KeyDescriptor").map do |item|
- cert = item.at_xpath("./ds:KeyInfo/ds:X509Data/ds:X509Certificate", NAMESPACES).text
+ cert = item.at_xpath('./ds:KeyInfo/ds:X509Data/ds:X509Certificate', NAMESPACES).text
attribute = item.attribute('use')
use = attribute.nil? ? nil : item.attribute('use').value
::Xml::Kit::Certificate.new(cert, use: use)
@@ -98,8 +98,8 @@ module Saml
# @param type [String] the type of service. .E.g. `AssertionConsumerServiceURL`
def services(type)
document.find_all("/md:EntityDescriptor/md:#{name}/md:#{type}").map do |item|
- binding = item.attribute("Binding").value
- location = item.attribute("Location").value
+ binding = item.attribute('Binding').value
+ location = item.attribute('Location').value
Saml::Kit::Bindings.create_for(binding, location)
end
end
@@ -180,7 +180,7 @@ module Saml
end
def signature
- @signature ||= Signature.new(at_xpath("/md:EntityDescriptor/ds:Signature"))
+ @signature ||= Signature.new(at_xpath('/md:EntityDescriptor/ds:Signature'))
end
class << self
@@ -190,12 +190,12 @@ module Saml
# @return [Saml::Kit::Metadata] the metadata document or subclass.
def from(content)
hash = Hash.from_xml(content)
- entity_descriptor = hash["EntityDescriptor"]
- if entity_descriptor.key?("SPSSODescriptor") && entity_descriptor.key?("IDPSSODescriptor")
+ entity_descriptor = hash['EntityDescriptor']
+ if entity_descriptor.key?('SPSSODescriptor') && entity_descriptor.key?('IDPSSODescriptor')
Saml::Kit::CompositeMetadata.new(content)
- elsif entity_descriptor.keys.include?("SPSSODescriptor")
+ elsif entity_descriptor.keys.include?('SPSSODescriptor')
Saml::Kit::ServiceProviderMetadata.new(content)
- elsif entity_descriptor.keys.include?("IDPSSODescriptor")
+ elsif entity_descriptor.keys.include?('IDPSSODescriptor')
Saml::Kit::IdentityProviderMetadata.new(content)
end
end
lib/saml/kit/namespaces.rb
@@ -1,32 +1,32 @@
module Saml
module Kit
module Namespaces
- SAML_2_0 = "urn:oasis:names:tc:SAML:2.0"
- SAML_1_1 = "urn:oasis:names:tc:SAML:1.1"
- ATTR_NAME_FORMAT = "#{SAML_2_0}:attrname-format"
- NAME_ID_FORMAT_1_1 = "#{SAML_1_1}:nameid-format"
- NAME_ID_FORMAT_2_0 = "#{SAML_2_0}:nameid-format"
- STATUS = "#{SAML_2_0}:status"
+ SAML_2_0 = 'urn:oasis:names:tc:SAML:2.0'.freeze
+ SAML_1_1 = 'urn:oasis:names:tc:SAML:1.1'.freeze
+ ATTR_NAME_FORMAT = "#{SAML_2_0}:attrname-format".freeze
+ NAME_ID_FORMAT_1_1 = "#{SAML_1_1}:nameid-format".freeze
+ NAME_ID_FORMAT_2_0 = "#{SAML_2_0}:nameid-format".freeze
+ STATUS = "#{SAML_2_0}:status".freeze
- ASSERTION = "#{SAML_2_0}:assertion"
- ATTR_SPLAT = "#{ATTR_NAME_FORMAT}:*"
- BASIC = "#{ATTR_NAME_FORMAT}:basic"
- BEARER = "#{SAML_2_0}:cm:bearer"
- EMAIL_ADDRESS = "#{NAME_ID_FORMAT_1_1}:emailAddress"
- INVALID_NAME_ID_POLICY = "#{STATUS}:InvalidNameIDPolicy"
- METADATA = "#{SAML_2_0}:metadata"
- PASSWORD = "#{SAML_2_0}:ac:classes:Password"
- PASSWORD_PROTECTED = "#{SAML_2_0}:ac:classes:PasswordProtectedTransport"
- PERSISTENT = "#{NAME_ID_FORMAT_2_0}:persistent"
- PROTOCOL = "#{SAML_2_0}:protocol"
- REQUESTER_ERROR = "#{STATUS}:Requester"
- RESPONDER_ERROR = "#{STATUS}:Responder"
- SUCCESS = "#{STATUS}:Success"
- TRANSIENT = "#{NAME_ID_FORMAT_2_0}:transient"
- UNSPECIFIED = "#{SAML_2_0}:consent:unspecified"
- UNSPECIFIED_NAMEID = "#{NAME_ID_FORMAT_1_1}:unspecified"
- URI = "#{ATTR_NAME_FORMAT}:uri"
- VERSION_MISMATCH_ERROR = "#{STATUS}:VersionMismatch"
+ ASSERTION = "#{SAML_2_0}:assertion".freeze
+ ATTR_SPLAT = "#{ATTR_NAME_FORMAT}:*".freeze
+ BASIC = "#{ATTR_NAME_FORMAT}:basic".freeze
+ BEARER = "#{SAML_2_0}:cm:bearer".freeze
+ EMAIL_ADDRESS = "#{NAME_ID_FORMAT_1_1}:emailAddress".freeze
+ INVALID_NAME_ID_POLICY = "#{STATUS}:InvalidNameIDPolicy".freeze
+ METADATA = "#{SAML_2_0}:metadata".freeze
+ PASSWORD = "#{SAML_2_0}:ac:classes:Password".freeze
+ PASSWORD_PROTECTED = "#{SAML_2_0}:ac:classes:PasswordProtectedTransport".freeze
+ PERSISTENT = "#{NAME_ID_FORMAT_2_0}:persistent".freeze
+ PROTOCOL = "#{SAML_2_0}:protocol".freeze
+ REQUESTER_ERROR = "#{STATUS}:Requester".freeze
+ RESPONDER_ERROR = "#{STATUS}:Responder".freeze
+ SUCCESS = "#{STATUS}:Success".freeze
+ TRANSIENT = "#{NAME_ID_FORMAT_2_0}:transient".freeze
+ UNSPECIFIED = "#{SAML_2_0}:consent:unspecified".freeze
+ UNSPECIFIED_NAMEID = "#{NAME_ID_FORMAT_1_1}:unspecified".freeze
+ URI = "#{ATTR_NAME_FORMAT}:uri".freeze
+ VERSION_MISMATCH_ERROR = "#{STATUS}:VersionMismatch".freeze
end
end
end
lib/saml/kit/null_assertion.rb
@@ -10,7 +10,7 @@ module Saml
end
def name
- "NullAssertion"
+ 'NullAssertion'
end
end
end
lib/saml/kit/response.rb
@@ -12,7 +12,7 @@ module Saml
def initialize(xml, request_id: nil, configuration: Saml::Kit.configuration)
@request_id = request_id
- super(xml, name: "Response", configuration: configuration)
+ super(xml, name: 'Response', configuration: configuration)
end
def assertion(private_keys = configuration.private_keys(use: :encryption))
@@ -32,8 +32,8 @@ module Saml
def must_be_valid_assertion
assertion.valid?
assertion.errors.each do |attribute, error|
- attribute = :assertion if :base == attribute
- self.errors[attribute] << error
+ attribute = :assertion if attribute == :base
+ errors[attribute] << error
end
end
lib/saml/kit/service_provider_metadata.rb
@@ -3,7 +3,7 @@ module Saml
# {include:file:spec/examples/service_provider_metadata_spec.rb}
class ServiceProviderMetadata < Metadata
def initialize(xml)
- super("SPSSODescriptor", xml)
+ super('SPSSODescriptor', xml)
end
# Returns each of the AssertionConsumerService bindings.
@@ -20,9 +20,9 @@ module Saml
# Returns true when the metadata demands that Assertions must be signed.
def want_assertions_signed
- attribute = document.find_by("/md:EntityDescriptor/md:#{name}").attribute("WantAssertionsSigned")
+ attribute = document.find_by("/md:EntityDescriptor/md:#{name}").attribute('WantAssertionsSigned')
return true if attribute.nil?
- attribute.text.downcase == "true"
+ attribute.text.casecmp('true').zero?
end
# @!visibility private
lib/saml/kit/signature.rb
@@ -10,7 +10,7 @@ module Saml
attr_reader :name
def initialize(node)
- @name = "Signature"
+ @name = 'Signature'
@node = node
end
@@ -28,32 +28,32 @@ module Saml
end
def digest_value
- at_xpath("./ds:SignedInfo/ds:Reference/ds:DigestValue").try(:text)
+ at_xpath('./ds:SignedInfo/ds:Reference/ds:DigestValue').try(:text)
end
def digest_method
- at_xpath("./ds:SignedInfo/ds:Reference/ds:DigestMethod/@Algorithm").try(:value)
+ at_xpath('./ds:SignedInfo/ds:Reference/ds:DigestMethod/@Algorithm').try(:value)
end
def signature_value
- at_xpath("./ds:SignatureValue").try(:text)
+ at_xpath('./ds:SignatureValue').try(:text)
end
def signature_method
- at_xpath("./ds:SignedInfo/ds:SignatureMethod/@Algorithm").try(:value)
+ at_xpath('./ds:SignedInfo/ds:SignatureMethod/@Algorithm').try(:value)
end
def canonicalization_method
- at_xpath("./ds:SignedInfo/ds:CanonicalizationMethod/@Algorithm").try(:value)
+ at_xpath('./ds:SignedInfo/ds:CanonicalizationMethod/@Algorithm').try(:value)
end
def transforms
- node.search("./ds:SignedInfo/ds:Reference/ds:Transforms/ds:Transform/@Algorithm", Saml::Kit::Document::NAMESPACES).try(:map, &:value)
+ node.search('./ds:SignedInfo/ds:Reference/ds:Transforms/ds:Transform/@Algorithm', Saml::Kit::Document::NAMESPACES).try(:map, &:value)
end
# Returns the XML Hash.
def to_h
- @xml_hash ||= present? ? Hash.from_xml(to_xml)["Signature"] : {}
+ @xml_hash ||= present? ? Hash.from_xml(to_xml)['Signature'] : {}
end
def present?
@@ -82,9 +82,8 @@ module Saml
def validate_certificate(now = Time.now.utc)
if certificate.present? && !certificate.active?(now)
errors.add(:certificate, error_message(:certificate,
- not_before: certificate.not_before,
- not_after: certificate.not_after
- ))
+ not_before: certificate.not_before,
+ not_after: certificate.not_after))
end
end
lib/saml/kit/version.rb
@@ -1,5 +1,5 @@
module Saml
module Kit
- VERSION = "1.0.7"
+ VERSION = '1.0.7'.freeze
end
end
lib/saml/kit/xml_templatable.rb
@@ -4,9 +4,9 @@ module Saml
include ::Xml::Kit::Templatable
def template_path
- root_path = File.expand_path(File.dirname(__FILE__))
- template_name = "#{self.class.name.split("::").last.underscore}.builder"
- File.join(root_path, "builders/templates/", template_name)
+ root_path = __dir__
+ template_name = "#{self.class.name.split('::').last.underscore}.builder"
+ File.join(root_path, 'builders/templates/', template_name)
end
# Returns true if an embedded signature is requested and at least one signing certificate is available via the configuration.
lib/saml/kit.rb
@@ -1,48 +1,48 @@
-require "saml/kit/version"
+require 'saml/kit/version'
-require "active_model"
-require "active_support/core_ext/date/calculations"
-require "active_support/core_ext/hash/conversions"
-require "active_support/core_ext/hash/indifferent_access"
-require "active_support/core_ext/numeric/time"
-require "active_support/deprecation"
-require "active_support/duration"
-require "forwardable"
-require "logger"
-require "net/http"
-require "nokogiri"
-require "securerandom"
-require "uri"
-require "xml/kit"
+require 'active_model'
+require 'active_support/core_ext/date/calculations'
+require 'active_support/core_ext/hash/conversions'
+require 'active_support/core_ext/hash/indifferent_access'
+require 'active_support/core_ext/numeric/time'
+require 'active_support/deprecation'
+require 'active_support/duration'
+require 'forwardable'
+require 'logger'
+require 'net/http'
+require 'nokogiri'
+require 'securerandom'
+require 'uri'
+require 'xml/kit'
-require "saml/kit/buildable"
-require "saml/kit/builders"
-require "saml/kit/namespaces"
-require "saml/kit/serializable"
-require "saml/kit/xsd_validatable"
-require "saml/kit/respondable"
-require "saml/kit/requestable"
-require "saml/kit/trustable"
-require "saml/kit/translatable"
-require "saml/kit/document"
+require 'saml/kit/buildable'
+require 'saml/kit/builders'
+require 'saml/kit/namespaces'
+require 'saml/kit/serializable'
+require 'saml/kit/xsd_validatable'
+require 'saml/kit/respondable'
+require 'saml/kit/requestable'
+require 'saml/kit/trustable'
+require 'saml/kit/translatable'
+require 'saml/kit/document'
-require "saml/kit/assertion"
-require "saml/kit/authentication_request"
-require "saml/kit/bindings"
-require "saml/kit/configuration"
-require "saml/kit/default_registry"
-require "saml/kit/logout_response"
-require "saml/kit/logout_request"
-require "saml/kit/metadata"
-require "saml/kit/null_assertion"
-require "saml/kit/composite_metadata"
-require "saml/kit/response"
-require "saml/kit/identity_provider_metadata"
-require "saml/kit/invalid_document"
-require "saml/kit/service_provider_metadata"
-require "saml/kit/signature"
+require 'saml/kit/assertion'
+require 'saml/kit/authentication_request'
+require 'saml/kit/bindings'
+require 'saml/kit/configuration'
+require 'saml/kit/default_registry'
+require 'saml/kit/logout_response'
+require 'saml/kit/logout_request'
+require 'saml/kit/metadata'
+require 'saml/kit/null_assertion'
+require 'saml/kit/composite_metadata'
+require 'saml/kit/response'
+require 'saml/kit/identity_provider_metadata'
+require 'saml/kit/invalid_document'
+require 'saml/kit/service_provider_metadata'
+require 'saml/kit/signature'
-I18n.load_path += Dir[File.expand_path("kit/locales/*.yml", File.dirname(__FILE__))]
+I18n.load_path += Dir[File.expand_path('kit/locales/*.yml', File.dirname(__FILE__))]
module Saml
module Kit
spec/saml/bindings/binding_spec.rb
@@ -1,17 +1,18 @@
RSpec.describe Saml::Kit::Bindings::Binding do
- let(:location) { FFaker::Internet.http_url }
subject { described_class.new(binding: Saml::Kit::Bindings::HTTP_ARTIFACT, location: location) }
- describe "#serialize" do
+ let(:location) { FFaker::Internet.http_url }
+
+ describe '#serialize' do
it 'ignores other bindings' do
expect(subject.serialize(Saml::Kit::AuthenticationRequest)).to be_empty
end
end
- describe "#deserialize" do
+ describe '#deserialize' do
it 'raises an error' do
expect do
- subject.deserialize('SAMLRequest' => "CORRUPT")
+ subject.deserialize('SAMLRequest' => 'CORRUPT')
end.to raise_error(/Unsupported binding/)
end
end
spec/saml/bindings/http_post_spec.rb
@@ -1,27 +1,28 @@
RSpec.describe Saml::Kit::Bindings::HttpPost do
- let(:location) { FFaker::Internet.uri("https") }
subject { described_class.new(location: location) }
- describe "equality" do
+ let(:location) { FFaker::Internet.uri('https') }
+
+ describe 'equality' do
it 'is referentially equal' do
expect(subject).to eql(subject)
end
it 'is equal by value' do
expect(subject).to eql(
- Saml::Kit::Bindings::HttpPost.new(location: location)
+ described_class.new(location: location)
)
end
it 'is not equal' do
- expect(subject).to_not eql(
- described_class.new(location: FFaker::Internet.uri("https"))
+ expect(subject).not_to eql(
+ described_class.new(location: FFaker::Internet.uri('https'))
)
end
end
- describe "#serialize" do
- let(:relay_state) { "ECHO" }
+ describe '#serialize' do
+ let(:relay_state) { 'ECHO' }
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
@@ -74,11 +75,11 @@ RSpec.describe Saml::Kit::Bindings::HttpPost do
url, saml_params = subject.serialize(builder)
expect(url).to eql(location)
- expect(saml_params.keys).to_not include('RelayState')
+ expect(saml_params.keys).not_to include('RelayState')
end
end
- describe "#deserialize" do
+ describe '#deserialize' do
it 'deserializes to an AuthnRequest' do
builder = Saml::Kit::AuthenticationRequest.builder_class.new
_, params = subject.serialize(builder)
spec/saml/bindings/http_redirect_spec.rb
@@ -1,9 +1,10 @@
RSpec.describe Saml::Kit::Bindings::HttpRedirect do
- let(:location) { FFaker::Internet.http_url }
subject { described_class.new(location: location) }
- describe "#serialize" do
- let(:relay_state) { "ECHO" }
+ let(:location) { FFaker::Internet.http_url }
+
+ describe '#serialize' do
+ let(:relay_state) { 'ECHO' }
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
@@ -12,7 +13,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
it 'encodes the request using the HTTP-Redirect encoding' do
builder = Saml::Kit::AuthenticationRequest.builder(configuration: configuration)
- url, _ = subject.serialize(builder, relay_state: relay_state)
+ url, = subject.serialize(builder, relay_state: relay_state)
expect(url).to start_with(location)
expect(url).to have_query_param('SAMLRequest')
expect(url).to have_query_param('SigAlg')
@@ -20,23 +21,23 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
end
- describe "#deserialize" do
+ describe '#deserialize' do
let(:entity_id) { FFaker::Internet.http_url }
let(:provider) { Saml::Kit::IdentityProviderMetadata.build }
- before :each do
+ before do
allow(Saml::Kit.configuration.registry).to receive(:metadata_for).with(entity_id).and_return(provider)
allow(Saml::Kit.configuration).to receive(:entity_id).and_return(entity_id)
end
it 'deserializes the SAMLRequest to an AuthnRequest' do
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
it 'deserializes the raw query_string to an AuthnRequest' do
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder, relay_state: "HELLO")
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder, relay_state: 'HELLO')
result = subject.deserialize(url)
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
@@ -47,7 +48,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
config.generate_key_pair_for(use: :signing)
end
provider = Saml::Kit::IdentityProviderMetadata.build(configuration: configuration)
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
allow(configuration.registry).to receive(:metadata_for).with(entity_id).and_return(provider)
result = subject.deserialize(query_params_from(url).symbolize_keys, configuration: configuration)
@@ -57,7 +58,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
it 'deserializes the SAMLRequest to an AuthnRequest with symbols for keys' do
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url).symbolize_keys)
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
@@ -72,48 +73,48 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
@params[key]
end
end
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(Parameters.new(query_params_from(url)))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
end
it 'deserializes the SAMLRequest to a LogoutRequest' do
user = double(:user, name_id_for: SecureRandom.uuid)
- url, _ = subject.serialize(Saml::Kit::LogoutRequest.builder(user))
+ url, = subject.serialize(Saml::Kit::LogoutRequest.builder(user))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::LogoutRequest)
end
it 'returns an invalid request when the SAMLRequest is invalid' do
expect do
- subject.deserialize({ 'SAMLRequest' => "nonsense" })
+ subject.deserialize('SAMLRequest' => 'nonsense')
end.to raise_error(Zlib::DataError)
end
it 'deserializes the SAMLResponse to a Response' do
user = double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: [])
request = double(:request, id: SecureRandom.uuid, provider: nil, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, issuer: entity_id, signed?: true, trusted?: true)
- url, _ = subject.serialize(Saml::Kit::Response.builder(user, request))
+ url, = subject.serialize(Saml::Kit::Response.builder(user, request))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::Response)
end
it 'deserializes the SAMLResponse to a LogoutResponse' do
request = double(:request, id: SecureRandom.uuid, provider: provider, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, issuer: FFaker::Internet.http_url)
- url, _ = subject.serialize(Saml::Kit::LogoutResponse.builder(request))
+ url, = subject.serialize(Saml::Kit::LogoutResponse.builder(request))
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::LogoutResponse)
end
it 'raises an error when the content is invalid' do
expect do
- subject.deserialize('SAMLResponse' => "nonsense")
+ subject.deserialize('SAMLResponse' => 'nonsense')
end.to raise_error(Zlib::DataError)
end
it 'raises an error when a saml parameter is not specified' do
expect do
- subject.deserialize({ })
+ subject.deserialize({})
end.to raise_error(ArgumentError)
end
@@ -122,7 +123,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
config.entity_id = entity_id
config.generate_key_pair_for(use: :signing)
end
- url, _ = subject.serialize(
+ url, = subject.serialize(
Saml::Kit::AuthenticationRequest.builder(configuration: configuration) do |x|
x.embed_signature = true
end
@@ -140,7 +141,7 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
end
allow(Saml::Kit.configuration.registry).to receive(:metadata_for).with(entity_id).and_return(provider)
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder)
result = subject.deserialize(query_params_from(url))
expect(result).to be_instance_of(Saml::Kit::AuthenticationRequest)
expect(result).to be_valid
@@ -150,14 +151,14 @@ RSpec.describe Saml::Kit::Bindings::HttpRedirect do
configuration = Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
end
- url, _ = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
+ url, = subject.serialize(Saml::Kit::AuthenticationRequest.builder(configuration: configuration))
other_configuration = Saml::Kit::Configuration.new
allow(other_configuration.registry).to receive(:metadata_for).and_return(nil)
result = subject.deserialize(query_params_from(url), configuration: other_configuration)
- expect(result).to_not be_signed
- expect(result).to_not be_trusted
+ expect(result).not_to be_signed
+ expect(result).not_to be_trusted
end
end
end
spec/saml/bindings/url_builder_spec.rb
@@ -1,6 +1,6 @@
RSpec.describe Saml::Kit::Bindings::UrlBuilder do
- describe "#build" do
- let(:xml) { "<xml></xml>" }
+ describe '#build' do
+ let(:xml) { '<xml></xml>' }
let(:destination) { FFaker::Internet.http_url }
let(:relay_state) { FFaker::Movie.title }
@@ -12,6 +12,7 @@ RSpec.describe Saml::Kit::Bindings::UrlBuilder do
].each do |(response_type, query_string_parameter)|
describe response_type.to_s do
subject { described_class.new(configuration: configuration) }
+
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
@@ -21,12 +22,12 @@ RSpec.describe Saml::Kit::Bindings::UrlBuilder do
let(:response) { instance_double(response_type, destination: destination, to_xml: xml, query_string_parameter: query_string_parameter) }
def to_query_params(url)
- Hash[URI.parse(url).query.split("&").map { |x| x.split('=', 2) }]
+ Hash[URI.parse(url).query.split('&').map { |x| x.split('=', 2) }]
end
it 'returns a url containing the target location' do
result_uri = URI.parse(subject.build(response))
- expect(result_uri.scheme).to eql("http")
+ expect(result_uri.scheme).to eql('http')
expect(result_uri.host).to eql(URI.parse(destination).host)
end
@@ -34,7 +35,7 @@ RSpec.describe Saml::Kit::Bindings::UrlBuilder do
result = subject.build(response, relay_state: relay_state)
query_params = to_query_params(result)
level = Zlib::BEST_COMPRESSION
- expected = CGI.escape(Base64.encode64(Zlib::Deflate.deflate(xml, level)[2..-5]).gsub(/\n/, ''))
+ expected = CGI.escape(Base64.encode64(Zlib::Deflate.deflate(xml, level)[2..-5]).delete("\n"))
expect(result).to include("#{query_string_parameter}=#{expected}")
expect(query_params[query_string_parameter]).to eql(expected)
end
spec/saml/builders/authentication_request_spec.rb
@@ -1,14 +1,15 @@
RSpec.describe Saml::Kit::Builders::AuthenticationRequest do
subject { described_class.new(configuration: configuration) }
+
let(:configuration) do
config = Saml::Kit::Configuration.new
config.entity_id = issuer
config
end
- describe "#to_xml" do
+ describe '#to_xml' do
let(:issuer) { FFaker::Movie.title }
- let(:assertion_consumer_service_url) { "https://airport.dev/session/acs" }
+ let(:assertion_consumer_service_url) { 'https://airport.dev/session/acs' }
it 'returns a valid authentication request' do
travel_to 1.second.from_now
spec/saml/builders/identity_provider_metadata_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::Builders::IdentityProviderMetadata do
subject { described_class.new(configuration: configuration) }
+
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
@@ -8,7 +9,7 @@ RSpec.describe Saml::Kit::Builders::IdentityProviderMetadata do
end
let(:email) { FFaker::Internet.email }
let(:org_name) { FFaker::Movie.title }
- let(:url) { FFaker::Internet.uri("https") }
+ let(:url) { FFaker::Internet.uri('https') }
let(:entity_id) { FFaker::Movie.title }
it 'builds a proper metadata' do
@@ -21,9 +22,9 @@ RSpec.describe Saml::Kit::Builders::IdentityProviderMetadata do
Saml::Kit::Namespaces::TRANSIENT,
Saml::Kit::Namespaces::EMAIL_ADDRESS,
]
- subject.add_single_sign_on_service("https://www.example.com/login", binding: :http_redirect)
- subject.add_single_logout_service("https://www.example.com/logout", binding: :http_post)
- subject.attributes << "id"
+ subject.add_single_sign_on_service('https://www.example.com/login', binding: :http_redirect)
+ subject.add_single_logout_service('https://www.example.com/logout', binding: :http_post)
+ subject.attributes << 'id'
result = Hash.from_xml(subject.build.to_xml)
@@ -32,22 +33,22 @@ RSpec.describe Saml::Kit::Builders::IdentityProviderMetadata do
expect(result['EntityDescriptor']['IDPSSODescriptor']['protocolSupportEnumeration']).to eql(Saml::Kit::Namespaces::PROTOCOL)
expect(result['EntityDescriptor']['IDPSSODescriptor']['WantAuthnRequestsSigned']).to eql('true')
expect(result['EntityDescriptor']['IDPSSODescriptor']['NameIDFormat']).to match_array([
- Saml::Kit::Namespaces::PERSISTENT,
- Saml::Kit::Namespaces::TRANSIENT,
- Saml::Kit::Namespaces::EMAIL_ADDRESS,
- ])
+ Saml::Kit::Namespaces::PERSISTENT,
+ Saml::Kit::Namespaces::TRANSIENT,
+ Saml::Kit::Namespaces::EMAIL_ADDRESS,
+ ])
expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_REDIRECT)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Location']).to eql("https://www.example.com/login")
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleSignOnService']['Location']).to eql('https://www.example.com/login')
expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Binding']).to eql(Saml::Kit::Bindings::HTTP_POST)
- expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Location']).to eql("https://www.example.com/logout")
- expect(result['EntityDescriptor']['IDPSSODescriptor']['Attribute']['Name']).to eql("id")
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['SingleLogoutService']['Location']).to eql('https://www.example.com/logout')
+ expect(result['EntityDescriptor']['IDPSSODescriptor']['Attribute']['Name']).to eql('id')
certificates = result['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor'].map { |x| x['KeyInfo']['X509Data']['X509Certificate'] }
expected_certificates = configuration.certificates.map(&:stripped)
expect(certificates).to match_array(expected_certificates)
expect(result['EntityDescriptor']['Organization']['OrganizationName']).to eql(org_name)
expect(result['EntityDescriptor']['Organization']['OrganizationDisplayName']).to eql(org_name)
expect(result['EntityDescriptor']['Organization']['OrganizationURL']).to eql(url)
- expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql("technical")
+ expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql('technical')
expect(result['EntityDescriptor']['ContactPerson']['Company']).to eql("mailto:#{email}")
end
end
spec/saml/builders/logout_request_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::Builders::LogoutRequest do
subject { described_class.new(user, configuration: configuration) }
+
let(:user) { double(:user, name_id_for: name_id) }
let(:name_id) { SecureRandom.uuid }
let(:configuration) do
@@ -19,7 +20,7 @@ RSpec.describe Saml::Kit::Builders::LogoutRequest do
xml_hash = Hash.from_xml(result)
expect(xml_hash['LogoutRequest']['ID']).to eql(subject.id)
- expect(xml_hash['LogoutRequest']['Version']).to eql("2.0")
+ expect(xml_hash['LogoutRequest']['Version']).to eql('2.0')
expect(xml_hash['LogoutRequest']['IssueInstant']).to eql(Time.now.utc.iso8601)
expect(xml_hash['LogoutRequest']['Destination']).to eql(subject.destination)
spec/saml/builders/logout_response_spec.rb
@@ -1,11 +1,12 @@
RSpec.describe Saml::Kit::Builders::LogoutResponse do
subject { described_class.new(request) }
+
let(:user) { double(:user, name_id_for: SecureRandom.uuid) }
let(:request) { Saml::Kit::Builders::LogoutRequest.new(user).build }
let(:issuer) { FFaker::Internet.http_url }
let(:destination) { FFaker::Internet.http_url }
- describe "#build" do
+ describe '#build' do
it 'builds a logout response' do
travel_to 1.second.from_now
@@ -14,7 +15,7 @@ RSpec.describe Saml::Kit::Builders::LogoutResponse do
result = subject.build
expect(result.id).to be_present
expect(result.issue_instant).to eql(Time.now.utc)
- expect(result.version).to eql("2.0")
+ expect(result.version).to eql('2.0')
expect(result.issuer).to eql(issuer)
expect(result.status_code).to eql(Saml::Kit::Namespaces::SUCCESS)
expect(result.in_response_to).to eql(request.id)
spec/saml/builders/metadata_spec.rb
@@ -1,7 +1,8 @@
RSpec.describe Saml::Kit::Builders::Metadata do
- describe ".build" do
+ describe '.build' do
subject { Saml::Kit::Metadata }
- let(:url) { FFaker::Internet.uri("https") }
+
+ let(:url) { FFaker::Internet.uri('https') }
it 'builds metadata for a service provider' do
result = subject.build do |builder|
@@ -57,7 +58,7 @@ RSpec.describe Saml::Kit::Builders::Metadata do
3.times { config.generate_key_pair_for(use: :signing) }
end
metadata = Saml::Kit::Metadata.build(configuration: configuration) do |builder|
- builder.entity_id = FFaker::Internet.uri("https")
+ builder.entity_id = FFaker::Internet.uri('https')
builder.build_identity_provider do |x|
x.embed_signature = true
x.add_single_sign_on_service(url, binding: :http_post)
spec/saml/builders/response_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::Builders::Response do
subject { described_class.new(user, request, configuration: configuration) }
+
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.entity_id = issuer
@@ -8,13 +9,13 @@ RSpec.describe Saml::Kit::Builders::Response do
end
end
let(:email) { FFaker::Internet.email }
- let(:assertion_consumer_service_url) { FFaker::Internet.uri("https") }
+ let(:assertion_consumer_service_url) { FFaker::Internet.uri('https') }
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { email: email, created_at: Time.now.utc.iso8601 }) }
let(:request) { double(:request, id: Xml::Kit::Id.generate, assertion_consumer_service_url: assertion_consumer_service_url, issuer: issuer, name_id_format: Saml::Kit::Namespaces::EMAIL_ADDRESS, provider: provider, trusted?: true, signed?: true) }
- let(:provider) { double(:provider, want_assertions_signed: false, encryption_certificates: [configuration.certificates(use: :encryption).last] ) }
- let(:issuer) { FFaker::Internet.uri("https") }
+ let(:provider) { double(:provider, want_assertions_signed: false, encryption_certificates: [configuration.certificates(use: :encryption).last]) }
+ let(:issuer) { FFaker::Internet.uri('https') }
- describe "#build" do
+ describe '#build' do
it 'builds a response with the request_id' do
expect(subject.build.request_id).to eql(request.id)
end
@@ -37,7 +38,7 @@ RSpec.describe Saml::Kit::Builders::Response do
end
end
- describe "#to_xml" do
+ describe '#to_xml' do
it 'returns a proper response for the user' do
travel_to 1.second.from_now
allow(Saml::Kit.configuration).to receive(:entity_id).and_return(issuer)
@@ -51,15 +52,15 @@ RSpec.describe Saml::Kit::Builders::Response do
expect(hash['Response']['Destination']).to eql(assertion_consumer_service_url)
expect(hash['Response']['InResponseTo']).to eql(request.id)
expect(hash['Response']['Issuer']).to eql(issuer)
- expect(hash['Response']['Status']['StatusCode']['Value']).to eql("urn:oasis:names:tc:SAML:2.0:status:Success")
+ expect(hash['Response']['Status']['StatusCode']['Value']).to eql('urn:oasis:names:tc:SAML:2.0:status:Success')
expect(hash['Response']['Assertion']['ID']).to be_present
expect(hash['Response']['Assertion']['IssueInstant']).to eql(Time.now.utc.iso8601)
- expect(hash['Response']['Assertion']['Version']).to eql("2.0")
+ expect(hash['Response']['Assertion']['Version']).to eql('2.0')
expect(hash['Response']['Assertion']['Issuer']).to eql(issuer)
expect(hash['Response']['Assertion']['Subject']['NameID']).to eql(user.name_id_for)
- expect(hash['Response']['Assertion']['Subject']['SubjectConfirmation']['Method']).to eql("urn:oasis:names:tc:SAML:2.0:cm:bearer")
+ expect(hash['Response']['Assertion']['Subject']['SubjectConfirmation']['Method']).to eql('urn:oasis:names:tc:SAML:2.0:cm:bearer')
expect(hash['Response']['Assertion']['Subject']['SubjectConfirmation']['SubjectConfirmationData']['NotOnOrAfter']).to eql(3.hours.from_now.utc.iso8601)
expect(hash['Response']['Assertion']['Subject']['SubjectConfirmation']['SubjectConfirmationData']['Recipient']).to eql(assertion_consumer_service_url)
expect(hash['Response']['Assertion']['Subject']['SubjectConfirmation']['SubjectConfirmationData']['InResponseTo']).to eql(request.id)
@@ -145,13 +146,13 @@ RSpec.describe Saml::Kit::Builders::Response do
subject.embed_signature = false
result = Saml::Kit::Response.new(subject.to_xml, configuration: configuration)
- expect(result).to_not be_signed
- expect(result.assertion).to_not be_signed
+ expect(result).not_to be_signed
+ expect(result.assertion).not_to be_signed
expect(result.assertion).to be_encrypted
end
end
- describe ".build" do
+ describe '.build' do
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.entity_id = issuer
spec/saml/builders/service_provider_metadata_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::Builders::ServiceProviderMetadata do
subject { described_class.new(configuration: configuration) }
+
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
@@ -9,8 +10,8 @@ RSpec.describe Saml::Kit::Builders::ServiceProviderMetadata do
let(:assertion_consumer_service_url) { FFaker::Internet.http_url }
let(:email) { FFaker::Internet.email }
let(:org_name) { FFaker::Movie.title }
- let(:url) { FFaker::Internet.uri("https") }
- let(:entity_id) { FFaker::Internet.uri("https") }
+ let(:url) { FFaker::Internet.uri('https') }
+ let(:entity_id) { FFaker::Internet.uri('https') }
it 'builds the service provider metadata' do
subject.contact_email = email
@@ -25,29 +26,29 @@ RSpec.describe Saml::Kit::Builders::ServiceProviderMetadata do
]
result = Hash.from_xml(subject.build.to_xml)
- expect(result['EntityDescriptor']['xmlns']).to eql("urn:oasis:names:tc:SAML:2.0:metadata")
+ expect(result['EntityDescriptor']['xmlns']).to eql('urn:oasis:names:tc:SAML:2.0:metadata')
expect(result['EntityDescriptor']['ID']).to be_present
expect(result['EntityDescriptor']['entityID']).to eql(entity_id)
expect(result['EntityDescriptor']['SPSSODescriptor']['AuthnRequestsSigned']).to eql('true')
expect(result['EntityDescriptor']['SPSSODescriptor']['WantAssertionsSigned']).to eql('true')
expect(result['EntityDescriptor']['SPSSODescriptor']['protocolSupportEnumeration']).to eql('urn:oasis:names:tc:SAML:2.0:protocol')
expect(result['EntityDescriptor']['SPSSODescriptor']['NameIDFormat']).to match_array([
- Saml::Kit::Namespaces::PERSISTENT,
- Saml::Kit::Namespaces::TRANSIENT,
- Saml::Kit::Namespaces::EMAIL_ADDRESS,
- ])
- expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['Binding']).to eql("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST")
+ Saml::Kit::Namespaces::PERSISTENT,
+ Saml::Kit::Namespaces::TRANSIENT,
+ Saml::Kit::Namespaces::EMAIL_ADDRESS,
+ ])
+ expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['Binding']).to eql('urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST')
expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['Location']).to eql(assertion_consumer_service_url)
expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['isDefault']).to eql('true')
expect(result['EntityDescriptor']['SPSSODescriptor']['AssertionConsumerService']['index']).to eql('0')
expect(result['EntityDescriptor']['Signature']).to be_present
- expect(result['EntityDescriptor']['SPSSODescriptor']['KeyDescriptor'].map { |x| x['use'] }).to match_array(['signing', 'encryption'])
+ expect(result['EntityDescriptor']['SPSSODescriptor']['KeyDescriptor'].map { |x| x['use'] }).to match_array(%w[signing encryption])
expected_certificates = configuration.certificates.map(&:stripped)
expect(result['EntityDescriptor']['SPSSODescriptor']['KeyDescriptor'].map { |x| x['KeyInfo']['X509Data']['X509Certificate'] }).to match_array(expected_certificates)
expect(result['EntityDescriptor']['Organization']['OrganizationName']).to eql(org_name)
expect(result['EntityDescriptor']['Organization']['OrganizationDisplayName']).to eql(org_name)
expect(result['EntityDescriptor']['Organization']['OrganizationURL']).to eql(url)
- expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql("technical")
+ expect(result['EntityDescriptor']['ContactPerson']['contactType']).to eql('technical')
expect(result['EntityDescriptor']['ContactPerson']['Company']).to eql("mailto:#{email}")
end
end
spec/saml/assertion_spec.rb
@@ -1,5 +1,5 @@
RSpec.describe Saml::Kit::Assertion do
- describe "#active?" do
+ describe '#active?' do
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.session_timeout = 30.minutes
@@ -14,16 +14,16 @@ RSpec.describe Saml::Kit::Assertion do
xml = <<-XML
<Response>
<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri("https")}</Issuer>
+ <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
<Subject>
<NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
<SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
- <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_on_or_after}" Recipient="#{FFaker::Internet.uri("https")}"/>
+ <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_on_or_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="#{now.utc.iso8601}" NotOnOrAfter="#{not_on_or_after}">
<AudienceRestriction>
- <Audience>#{FFaker::Internet.uri("https")}</Audience>
+ <Audience>#{FFaker::Internet.uri('https')}</Audience>
</AudienceRestriction>
</Conditions>
<AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_on_or_after}">
@@ -37,7 +37,7 @@ XML
subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
travel_to (configuration.clock_drift - 1.second).before(now)
expect(subject).to be_active
- expect(subject).to_not be_expired
+ expect(subject).not_to be_expired
end
it 'interprets integers correctly' do
@@ -49,16 +49,16 @@ XML
xml = <<-XML
<Response>
<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri("https")}</Issuer>
+ <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
<Subject>
<NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
<SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
- <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri("https")}"/>
+ <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
<AudienceRestriction>
- <Audience>#{FFaker::Internet.uri("https")}</Audience>
+ <Audience>#{FFaker::Internet.uri('https')}</Audience>
</AudienceRestriction>
</Conditions>
<AuthnStatement AuthnInstant="#{now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
@@ -71,14 +71,14 @@ XML
XML
subject = described_class.new(Nokogiri::XML(xml), configuration: configuration)
expect(subject).to be_active
- expect(subject).to_not be_expired
+ expect(subject).not_to be_expired
end
end
- describe "#present?" do
+ describe '#present?' do
it 'returns false when the assertion is empty' do
subject = described_class.new(nil)
- expect(subject).to_not be_present
+ expect(subject).not_to be_present
end
it 'returns true when the assertion is present' do
@@ -87,16 +87,16 @@ XML
xml = <<-XML
<Response>
<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{Xml::Kit::Id.generate}" IssueInstant="#{Time.now.iso8601}" Version="2.0">
- <Issuer>#{FFaker::Internet.uri("https")}</Issuer>
+ <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
<Subject>
<NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
<SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
- <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri("https")}"/>
+ <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="#{not_after}" Recipient="#{FFaker::Internet.uri('https')}"/>
</SubjectConfirmation>
</Subject>
<Conditions NotBefore="#{not_before}" NotOnOrAfter="#{not_after}">
<AudienceRestriction>
- <Audience>#{FFaker::Internet.uri("https")}</Audience>
+ <Audience>#{FFaker::Internet.uri('https')}</Audience>
</AudienceRestriction>
</Conditions>
<AuthnStatement AuthnInstant="#{Time.now.utc.iso8601}" SessionIndex="#{Xml::Kit::Id.generate}" SessionNotOnOrAfter="#{not_after}">
@@ -112,7 +112,7 @@ XML
end
end
- describe "#signed?" do
+ describe '#signed?' do
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.http_url, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { id: SecureRandom.uuid }) }
@@ -128,7 +128,7 @@ XML
end
end
- describe "#to_xml" do
+ describe '#to_xml' do
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.http_url, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { id: SecureRandom.uuid }) }
@@ -139,13 +139,13 @@ XML
x.encrypt_with(encryption_key_pair)
end
assertion = response.assertion([encryption_key_pair.private_key])
- expect(assertion.to_xml).to_not include("EncryptedAssertion")
- expect(assertion.to_xml).to include("Assertion")
+ expect(assertion.to_xml).not_to include('EncryptedAssertion')
+ expect(assertion.to_xml).to include('Assertion')
end
end
- describe "#valid?" do
- let(:entity_id) { FFaker::Internet.uri("https") }
+ describe '#valid?' do
+ let(:entity_id) { FFaker::Internet.uri('https') }
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: entity_id, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
let(:name_id) { SecureRandom.uuid }
let(:user) { double(:user, name_id_for: name_id, assertion_attributes_for: { id: SecureRandom.uuid }) }
@@ -158,7 +158,7 @@ XML
end
end
- before :each do
+ before do
allow(configuration.registry).to receive(:metadata_for).with(entity_id).and_return(idp)
end
@@ -166,7 +166,7 @@ XML
xml = Saml::Kit::Response.build_xml(user, request, configuration: configuration)
altered = xml.gsub(name_id, 'altered')
document = Nokogiri::XML(altered)
- assertion = document.at_xpath("/samlp:Response/saml:Assertion", Saml::Kit::Document::NAMESPACES)
+ assertion = document.at_xpath('/samlp:Response/saml:Assertion', Saml::Kit::Document::NAMESPACES)
key_pair = Xml::Kit::KeyPair.generate(use: :encryption)
encrypted = Xml::Kit::Encryption.new(assertion.to_xml, key_pair.public_key).to_xml
response = Saml::Kit::Response.new(encrypted, configuration: configuration)
spec/saml/authentication_request_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::AuthenticationRequest do
subject { described_class.new(raw_xml, configuration: configuration) }
+
let(:id) { Xml::Kit::Id.generate }
let(:assertion_consumer_service_url) { "https://#{FFaker::Internet.domain_name}/acs" }
let(:issuer) { FFaker::Movie.title }
@@ -27,11 +28,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
it { expect(subject.name_id_format).to eql(name_id_format) }
it { expect(subject.destination).to eql(destination) }
- describe "#valid?" do
+ describe '#valid?' do
let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
let(:metadata) { Saml::Kit::ServiceProviderMetadata.build(configuration: configuration) }
- before :each do
+ before do
allow(configuration).to receive(:registry).and_return(registry)
allow(registry).to receive(:metadata_for).and_return(metadata)
end
@@ -82,10 +83,10 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
id = Xml::Kit::Id.generate
key_pair = ::Xml::Kit::KeyPair.generate(use: :signing)
signed_xml = ::Xml::Kit::Signatures.sign(key_pair: key_pair) do |xml, signature|
- xml.tag!('samlp:AuthnRequest', "xmlns:samlp" => Saml::Kit::Namespaces::PROTOCOL, AssertionConsumerServiceURL: assertion_consumer_service_url, ID: id) do
+ xml.tag!('samlp:AuthnRequest', 'xmlns:samlp' => Saml::Kit::Namespaces::PROTOCOL, AssertionConsumerServiceURL: assertion_consumer_service_url, ID: id) do
signature.template(id)
xml.Fake do
- xml.NotAllowed "Huh?"
+ xml.NotAllowed 'Huh?'
end
end
end
@@ -134,7 +135,7 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
expect(subject).to be_invalid
end
- context "when the certificate is expired" do
+ context 'when the certificate is expired' do
let(:expired_certificate) do
certificate = OpenSSL::X509::Certificate.new
certificate.public_key = private_key.public_key
@@ -145,7 +146,7 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
let(:private_key) { OpenSSL::PKey::RSA.new(2048) }
let(:digest_algorithm) { OpenSSL::Digest::SHA256.new }
- before :each do
+ before do
expired_certificate.sign(private_key, digest_algorithm)
end
@@ -162,7 +163,7 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
end
end
- describe "#assertion_consumer_service_url" do
+ describe '#assertion_consumer_service_url' do
let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
let(:metadata) { instance_double(Saml::Kit::ServiceProviderMetadata) }
@@ -182,9 +183,9 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
end
end
- describe ".build" do
- let(:url) { FFaker::Internet.uri("https") }
- let(:entity_id) { FFaker::Internet.uri("https") }
+ describe '.build' do
+ let(:url) { FFaker::Internet.uri('https') }
+ let(:entity_id) { FFaker::Internet.uri('https') }
it 'provides a nice API for building metadata' do
result = described_class.build do |builder|
@@ -198,11 +199,11 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
end
end
- describe "#response_for" do
+ describe '#response_for' do
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: []) }
let(:provider) do
Saml::Kit::ServiceProviderMetadata.build do |x|
- x.add_assertion_consumer_service(FFaker::Internet.uri("https"), binding: :http_post)
+ x.add_assertion_consumer_service(FFaker::Internet.uri('https'), binding: :http_post)
end
end
@@ -229,7 +230,7 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
end
end
- describe "#signature.valid?" do
+ describe '#signature.valid?' do
it 'returns true when the signature is valid' do
expect(subject.signature).to be_valid
end
@@ -237,7 +238,7 @@ RSpec.describe Saml::Kit::AuthenticationRequest do
it 'returns false when the signature does not match' do
raw_xml.gsub!(issuer, 'corrupt')
subject = described_class.new(raw_xml, configuration: configuration)
- expect(subject.signature).to_not be_valid
+ expect(subject.signature).not_to be_valid
end
end
end
spec/saml/bindings_spec.rb
@@ -1,15 +1,16 @@
RSpec.describe Saml::Kit::Bindings do
- describe ".to_symbol" do
+ describe '.to_symbol' do
subject { described_class }
- it { expect(subject.to_symbol(Saml::Kit::Bindings::HTTP_POST)).to eql(:http_post) }
- it { expect(subject.to_symbol(Saml::Kit::Bindings::HTTP_REDIRECT)).to eql(:http_redirect) }
+ it { expect(subject.to_symbol(Saml::Kit::Bindings::HTTP_POST)).to be(:http_post) }
+ it { expect(subject.to_symbol(Saml::Kit::Bindings::HTTP_REDIRECT)).to be(:http_redirect) }
it { expect(subject.to_symbol('unknown')).to eql('unknown') }
end
- describe ".create_for" do
+ describe '.create_for' do
subject { described_class }
- let(:location) { FFaker::Internet.uri("https") }
+
+ let(:location) { FFaker::Internet.uri('https') }
it 'returns an HTTP redirect binding' do
expect(
spec/saml/composite_metadata_spec.rb
@@ -1,12 +1,13 @@
RSpec.describe Saml::Kit::CompositeMetadata do
subject { described_class.new(xml) }
- let(:post_binding) { Saml::Kit::Bindings::HTTP_POST }
+
+ let(:post_binding) { Saml::Kit::Bindings::HTTP_POST }
let(:redirect_binding) { Saml::Kit::Bindings::HTTP_REDIRECT }
- let(:sign_on_service) { FFaker::Internet.uri("https") }
- let(:assertion_consumer_service) { FFaker::Internet.uri("https") }
- let(:sp_logout_service) { FFaker::Internet.uri("https") }
- let(:idp_logout_service) { FFaker::Internet.uri("https") }
- let(:entity_id) { FFaker::Internet.uri("https") }
+ let(:sign_on_service) { FFaker::Internet.uri('https') }
+ let(:assertion_consumer_service) { FFaker::Internet.uri('https') }
+ let(:sp_logout_service) { FFaker::Internet.uri('https') }
+ let(:idp_logout_service) { FFaker::Internet.uri('https') }
+ let(:entity_id) { FFaker::Internet.uri('https') }
let(:sp_signing_certificate) { ::Xml::Kit::KeyPair.generate(use: :signing).certificate }
let(:sp_encryption_certificate) { ::Xml::Kit::KeyPair.generate(use: :encryption).certificate }
let(:idp_signing_certificate) { ::Xml::Kit::KeyPair.generate(use: :signing).certificate }
@@ -66,16 +67,16 @@ RSpec.describe Saml::Kit::CompositeMetadata do
XML
end
- describe "#single_sign_on_services" do
+ describe '#single_sign_on_services' do
it 'returns the single sign on services from the idp' do
expect(subject.single_sign_on_services).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: sign_on_service),
- Saml::Kit::Bindings::HttpRedirect.new(location: sign_on_service),
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: sign_on_service),
+ Saml::Kit::Bindings::HttpRedirect.new(location: sign_on_service),
+ ])
end
end
- describe "#single_sign_on_service_for" do
+ describe '#single_sign_on_service_for' do
it 'returns the post binding' do
expect(subject.single_sign_on_service_for(binding: :http_post)).to eql(
Saml::Kit::Bindings::HttpPost.new(location: sign_on_service)
@@ -88,8 +89,8 @@ RSpec.describe Saml::Kit::CompositeMetadata do
it { expect(subject.login_request_for(binding: :http_post)).to be_present }
it do
expect(subject.assertion_consumer_services).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service)
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service)
+ ])
end
it do
expect(subject.assertion_consumer_service_for(binding: :http_post)).to eql(
@@ -101,30 +102,30 @@ RSpec.describe Saml::Kit::CompositeMetadata do
it { expect(subject.name_id_formats).to match_array([Saml::Kit::Namespaces::PERSISTENT]) }
it do
expect(subject.certificates).to match_array([
- sp_signing_certificate,
- sp_encryption_certificate,
- idp_signing_certificate,
- idp_encryption_certificate,
- ])
+ sp_signing_certificate,
+ sp_encryption_certificate,
+ idp_signing_certificate,
+ idp_encryption_certificate,
+ ])
end
it do
expect(subject.encryption_certificates).to match_array([
- sp_encryption_certificate,
- idp_encryption_certificate,
- ])
+ sp_encryption_certificate,
+ idp_encryption_certificate,
+ ])
end
it do
expect(subject.signing_certificates).to match_array([
- sp_signing_certificate,
- idp_signing_certificate,
- ])
+ sp_signing_certificate,
+ idp_signing_certificate,
+ ])
end
it do
expect(subject.services('SingleLogoutService')).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: sp_logout_service),
- Saml::Kit::Bindings::HttpPost.new(location: idp_logout_service),
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: sp_logout_service),
+ Saml::Kit::Bindings::HttpPost.new(location: idp_logout_service),
+ ])
end
it do
expect(subject.service_for(type: 'SingleLogoutService', binding: :http_post)).to eql(
@@ -133,31 +134,31 @@ RSpec.describe Saml::Kit::CompositeMetadata do
end
it do
expect(subject.services('AssertionConsumerService')).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service),
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service),
+ ])
end
it do
expect(subject.service_for(type: 'AssertionConsumerService', binding: :http_post)).to eql(
- Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service),
+ Saml::Kit::Bindings::HttpPost.new(location: assertion_consumer_service)
)
end
it do
expect(subject.services('SingleSignOnService')).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: sign_on_service),
- Saml::Kit::Bindings::HttpRedirect.new(location: sign_on_service),
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: sign_on_service),
+ Saml::Kit::Bindings::HttpRedirect.new(location: sign_on_service),
+ ])
end
it do
expect(subject.service_for(type: 'SingleSignOnService', binding: :http_post)).to eql(
- Saml::Kit::Bindings::HttpPost.new(location: sign_on_service),
+ Saml::Kit::Bindings::HttpPost.new(location: sign_on_service)
)
end
it do
expect(subject.single_logout_services).to match_array([
- Saml::Kit::Bindings::HttpPost.new(location: sp_logout_service),
- Saml::Kit::Bindings::HttpPost.new(location: idp_logout_service),
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: sp_logout_service),
+ Saml::Kit::Bindings::HttpPost.new(location: idp_logout_service),
+ ])
end
it do
spec/saml/configuration_spec.rb
@@ -1,5 +1,5 @@
RSpec.describe Saml::Kit::Configuration do
- describe "#generate_key_pair_for" do
+ describe '#generate_key_pair_for' do
subject { described_class.new }
it 'raises an error when the use is not known' do
@@ -10,17 +10,18 @@ RSpec.describe Saml::Kit::Configuration do
it 'generates a signing key pair' do
subject.generate_key_pair_for(use: :signing)
- expect(subject.key_pairs(use: :signing).count).to eql(1)
+ expect(subject.key_pairs(use: :signing).count).to be(1)
end
it 'generates an encryption key pair' do
subject.generate_key_pair_for(use: :encryption)
- expect(subject.key_pairs(use: :encryption).count).to eql(1)
+ expect(subject.key_pairs(use: :encryption).count).to be(1)
end
end
- describe "#add_key_pair" do
+ describe '#add_key_pair' do
subject { described_class.new }
+
let(:certificate) do
certificate = OpenSSL::X509::Certificate.new
certificate.public_key = private_key.public_key
@@ -36,12 +37,12 @@ RSpec.describe Saml::Kit::Configuration do
it 'adds a signing key pair' do
subject.add_key_pair(certificate.to_pem, private_key.export, use: :signing)
- expect(subject.key_pairs(use: :signing).count).to eql(1)
+ expect(subject.key_pairs(use: :signing).count).to be(1)
end
it 'adds an encryption key pair' do
subject.add_key_pair(certificate.to_pem, private_key.export, use: :encryption)
- expect(subject.key_pairs(use: :encryption).count).to eql(1)
+ expect(subject.key_pairs(use: :encryption).count).to be(1)
end
end
end
spec/saml/default_registry_spec.rb
@@ -1,5 +1,6 @@
RSpec.describe Saml::Kit::DefaultRegistry do
subject { described_class.new }
+
let(:entity_id) { FFaker::Internet.http_url }
let(:service_provider_metadata) do
Saml::Kit::ServiceProviderMetadata.build do |builder|
@@ -12,19 +13,19 @@ RSpec.describe Saml::Kit::DefaultRegistry do
end
end
- describe "#metadata_for" do
+ describe '#metadata_for' do
it 'returns the metadata for the entity_id' do
subject.register(service_provider_metadata)
expect(subject.metadata_for(entity_id)).to eql(service_provider_metadata)
end
end
- describe "#register_url" do
+ describe '#register_url' do
let(:url) { FFaker::Internet.http_url }
it 'fetches the SP metadata from a remote url and registers it' do
- stub_request(:get, url).
- to_return(status: 200, body: service_provider_metadata.to_xml)
+ stub_request(:get, url)
+ .to_return(status: 200, body: service_provider_metadata.to_xml)
subject.register_url(url)
result = subject.metadata_for(entity_id)
@@ -33,8 +34,8 @@ RSpec.describe Saml::Kit::DefaultRegistry do
end
it 'fetches the IDP metadata from a remote url' do
- stub_request(:get, url).
- to_return(status: 200, body: identity_provider_metadata.to_xml)
+ stub_request(:get, url)
+ .to_return(status: 200, body: identity_provider_metadata.to_xml)
subject.register_url(url)
result = subject.metadata_for(entity_id)
@@ -46,15 +47,15 @@ RSpec.describe Saml::Kit::DefaultRegistry do
xml = <<-XML
<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
- <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
<NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
- <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}" index="0" isDefault="true"/>
+ <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
</SPSSODescriptor>
<IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
- <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
<NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
- <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
- <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+ <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
</IDPSSODescriptor>
<Organization>
<OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
@@ -75,13 +76,13 @@ RSpec.describe Saml::Kit::DefaultRegistry do
end
end
- describe "#each" do
+ describe '#each' do
it 'yields each registered metadata' do
idp = Saml::Kit::IdentityProviderMetadata.build do |config|
- config.entity_id = "idp"
+ config.entity_id = 'idp'
end
sp = Saml::Kit::ServiceProviderMetadata.build do |config|
- config.entity_id = "sp"
+ config.entity_id = 'sp'
end
subject.register(idp)
spec/saml/document_spec.rb
@@ -1,6 +1,7 @@
RSpec.describe Saml::Kit::Document do
- describe ".to_saml_document" do
+ describe '.to_saml_document' do
subject { described_class }
+
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { id: SecureRandom.uuid }) }
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: Xml::Kit::Id.generate, issuer: FFaker::Internet.http_url, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
@@ -40,7 +41,7 @@ RSpec.describe Saml::Kit::Document do
end
it 'returns an invalid document when the xml is not XML' do
- result = subject.to_saml_document("NOT XML")
+ result = subject.to_saml_document('NOT XML')
expect(result).to be_instance_of(Saml::Kit::InvalidDocument)
end
spec/saml/identity_provider_metadata_spec.rb
@@ -1,32 +1,32 @@
RSpec.describe Saml::Kit::IdentityProviderMetadata do
subject { described_class.new(raw_metadata) }
- context "okta metadata" do
- let(:raw_metadata) { IO.read("spec/fixtures/metadata/okta.xml") }
+ context 'okta metadata' do
+ let(:raw_metadata) { IO.read('spec/fixtures/metadata/okta.xml') }
let(:certificate) do
Hash.from_xml(raw_metadata)['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor']['KeyInfo']['X509Data']['X509Certificate']
end
- it { expect(subject.entity_id).to eql("http://www.okta.com/1") }
- it { expect(subject.name_id_formats).to match_array([ Saml::Kit::Namespaces::EMAIL_ADDRESS, Saml::Kit::Namespaces::UNSPECIFIED_NAMEID ]) }
+ it { expect(subject.entity_id).to eql('http://www.okta.com/1') }
+ it { expect(subject.name_id_formats).to match_array([Saml::Kit::Namespaces::EMAIL_ADDRESS, Saml::Kit::Namespaces::UNSPECIFIED_NAMEID]) }
it do
- location = "https://dev.oktapreview.com/app/example/1/sso/saml"
+ location = 'https://dev.oktapreview.com/app/example/1/sso/saml'
expect(subject.single_sign_on_services.map(&:to_h)).to match_array([
- { binding: Saml::Kit::Bindings::HTTP_POST, location: location },
- { binding: Saml::Kit::Bindings::HTTP_REDIRECT, location: location },
- ])
+ { binding: Saml::Kit::Bindings::HTTP_POST, location: location },
+ { binding: Saml::Kit::Bindings::HTTP_REDIRECT, location: location },
+ ])
end
it { expect(subject.single_logout_services).to be_empty }
it do
- fingerprint = "9F:74:13:3B:BC:5A:7B:8B:2D:4F:8B:EF:1E:88:EB:D1:AE:BC:19:BF:CA:19:C6:2F:0F:4B:31:1D:68:98:B0:1B"
+ fingerprint = '9F:74:13:3B:BC:5A:7B:8B:2D:4F:8B:EF:1E:88:EB:D1:AE:BC:19:BF:CA:19:C6:2F:0F:4B:31:1D:68:98:B0:1B'
expect(subject.certificates).to match_array([::Xml::Kit::Certificate.new(certificate, use: :signing)])
expect(subject.certificates.first.fingerprint.to_s).to eql(fingerprint)
end
it { expect(subject.attributes).to be_empty }
end
- context "active directory" do
- let(:raw_metadata) { IO.read("spec/fixtures/metadata/ad_2012.xml") }
+ context 'active directory' do
+ let(:raw_metadata) { IO.read('spec/fixtures/metadata/ad_2012.xml') }
let(:xml_hash) { Hash.from_xml(raw_metadata) }
let(:signing_certificate) do
xml_hash['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor'].find { |x| x['use'] == 'signing' }['KeyInfo']['X509Data']['X509Certificate']
@@ -35,38 +35,38 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
xml_hash['EntityDescriptor']['IDPSSODescriptor']['KeyDescriptor'].find { |x| x['use'] == 'encryption' }['KeyInfo']['X509Data']['X509Certificate']
end
- it { expect(subject.entity_id).to eql("http://www.example.com/adfs/services/trust") }
+ it { expect(subject.entity_id).to eql('http://www.example.com/adfs/services/trust') }
it do
expect(subject.name_id_formats).to match_array([
- Saml::Kit::Namespaces::EMAIL_ADDRESS,
- Saml::Kit::Namespaces::PERSISTENT,
- Saml::Kit::Namespaces::TRANSIENT,
- ])
+ Saml::Kit::Namespaces::EMAIL_ADDRESS,
+ Saml::Kit::Namespaces::PERSISTENT,
+ Saml::Kit::Namespaces::TRANSIENT,
+ ])
end
it do
- location = "https://www.example.com/adfs/ls/"
+ location = 'https://www.example.com/adfs/ls/'
expect(subject.single_sign_on_services.map(&:to_h)).to match_array([
- { location: location, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
- { location: location, binding: Saml::Kit::Bindings::HTTP_POST },
- ])
+ { location: location, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
+ { location: location, binding: Saml::Kit::Bindings::HTTP_POST },
+ ])
end
it do
- location = "https://www.example.com/adfs/ls/"
+ location = 'https://www.example.com/adfs/ls/'
expect(subject.single_logout_services.map(&:to_h)).to match_array([
- { location: location, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
- { location: location, binding: Saml::Kit::Bindings::HTTP_POST },
- ])
+ { location: location, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
+ { location: location, binding: Saml::Kit::Bindings::HTTP_POST },
+ ])
end
it do
expect(subject.certificates).to match_array([
- ::Xml::Kit::Certificate.new(signing_certificate, use: :signing),
- ::Xml::Kit::Certificate.new(encryption_certificate, use: :encryption),
- ])
+ ::Xml::Kit::Certificate.new(signing_certificate, use: :signing),
+ ::Xml::Kit::Certificate.new(encryption_certificate, use: :encryption),
+ ])
end
it { expect(subject.attributes).to be_present }
end
- describe "#validate" do
+ describe '#validate' do
it 'valid when given valid identity provider metadata' do
subject = described_class.build do |builder|
builder.attributes = [:email]
@@ -81,13 +81,13 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
it 'is invalid, when given service provider metadata' do
service_provider_metadata = Saml::Kit::ServiceProviderMetadata.build.to_xml
subject = described_class.new(service_provider_metadata)
- expect(subject).to_not be_valid
- expect(subject.errors[:base]).to include(I18n.translate("saml/kit.errors.IDPSSODescriptor.invalid"))
+ expect(subject).not_to be_valid
+ expect(subject.errors[:base]).to include(I18n.translate('saml/kit.errors.IDPSSODescriptor.invalid'))
end
it 'is invalid, when the metadata is nil' do
subject = described_class.new(nil)
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
expect(subject.errors[:metadata]).to include("can't be blank")
end
@@ -100,27 +100,24 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
end
subject = described_class.new(xml.target!)
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
expect(subject.errors[:base][0]).to include("1:0: ERROR: Element '{urn:oasis:names:tc:SAML:2.0:metadata}EntityDescriptor'")
end
it 'is invalid, when the signature is invalid' do
old_url = 'https://www.example.com/adfs/ls/'
new_url = 'https://myserver.com/hacked'
- metadata_xml = IO.read("spec/fixtures/metadata/ad_2012.xml").gsub(old_url, new_url)
+ metadata_xml = IO.read('spec/fixtures/metadata/ad_2012.xml').gsub(old_url, new_url)
subject = described_class.new(metadata_xml)
expect(subject).to be_invalid
expect(subject.errors[:base]).to be_empty
- expect(subject.errors[:digest_value]).to match_array(["is invalid."])
- expect(subject.errors[:signature]).to match_array(["is invalid."])
+ expect(subject.errors[:digest_value]).to match_array(['is invalid.'])
+ expect(subject.errors[:signature]).to match_array(['is invalid.'])
end
end
- describe "#single_sign_on_service_for" do
- let(:post_url) { FFaker::Internet.http_url }
- let(:redirect_url) { FFaker::Internet.http_url }
-
+ describe '#single_sign_on_service_for' do
subject do
described_class.build do |builder|
builder.add_single_sign_on_service(redirect_url, binding: :http_redirect)
@@ -128,6 +125,9 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
end
+ let(:post_url) { FFaker::Internet.http_url }
+ let(:redirect_url) { FFaker::Internet.http_url }
+
it 'returns the POST binding' do
result = subject.single_sign_on_service_for(binding: :http_post)
expect(result.location).to eql(post_url)
@@ -145,7 +145,7 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
end
- describe "#want_authn_requests_signed" do
+ describe '#want_authn_requests_signed' do
it 'returns true when enabled' do
subject = described_class.build do |builder|
builder.want_authn_requests_signed = true
@@ -163,15 +163,15 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
it 'returns true when the attribute is missing' do
xml = described_class.build do |builder|
builder.want_authn_requests_signed = false
- end.to_xml.gsub("WantAuthnRequestsSigned=\"false\"", "")
+ end.to_xml.gsub('WantAuthnRequestsSigned="false"', '')
subject = described_class.new(xml)
expect(subject.want_authn_requests_signed).to be(true)
end
end
- describe "#single_logout_service_for" do
- let(:redirect_url) { FFaker::Internet.uri("https") }
- let(:post_url) { FFaker::Internet.uri("https") }
+ describe '#single_logout_service_for' do
+ let(:redirect_url) { FFaker::Internet.uri('https') }
+ let(:post_url) { FFaker::Internet.uri('https') }
let(:subject) do
described_class.build do |builder|
builder.add_single_logout_service(redirect_url, binding: :http_redirect)
@@ -189,9 +189,9 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
end
- describe ".build" do
- let(:url) { FFaker::Internet.uri("https") }
- let(:entity_id) { FFaker::Internet.uri("https") }
+ describe '.build' do
+ let(:url) { FFaker::Internet.uri('https') }
+ let(:entity_id) { FFaker::Internet.uri('https') }
it 'provides a nice API for building metadata' do
result = described_class.build do |builder|
@@ -205,10 +205,10 @@ RSpec.describe Saml::Kit::IdentityProviderMetadata do
end
end
- describe "#login_request_for" do
+ describe '#login_request_for' do
it 'returns a serialized login request' do
subject = described_class.build do |x|
- x.add_single_sign_on_service(FFaker::Internet.uri("https"), binding: :http_post)
+ x.add_single_sign_on_service(FFaker::Internet.uri('https'), binding: :http_post)
end
url, saml_params = subject.login_request_for(binding: :http_post, relay_state: FFaker::Movie.title)
result = subject.single_sign_on_service_for(binding: :http_post).deserialize(saml_params)
spec/saml/invalid_document_spec.rb
@@ -1,14 +1,13 @@
RSpec.describe Saml::Kit::InvalidDocument do
it 'is invalid' do
- subject = described_class.new("<xml></xml>")
+ subject = described_class.new('<xml></xml>')
expect(subject).to be_invalid
expect(subject.errors[:base]).to be_present
end
it 'is invalid with something that not xml' do
- subject = described_class.new("NOT XML")
+ subject = described_class.new('NOT XML')
expect(subject).to be_invalid
expect(subject.errors[:base]).to be_present
end
end
-
spec/saml/kit_spec.rb
@@ -1,5 +1,5 @@
RSpec.describe Saml::Kit do
- it "has a version number" do
+ it 'has a version number' do
expect(Saml::Kit::VERSION).not_to be nil
end
end
spec/saml/logout_request_spec.rb
@@ -1,8 +1,9 @@
RSpec.describe Saml::Kit::LogoutRequest do
subject { described_class.build(user, configuration: configuration) }
+
let(:user) { double(:user, name_id_for: name_id) }
let(:name_id) { SecureRandom.uuid }
- let(:entity_id) { FFaker::Internet.uri("https") }
+ let(:entity_id) { FFaker::Internet.uri('https') }
let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
let(:configuration) do
Saml::Kit::Configuration.new do |config|
@@ -25,11 +26,11 @@ RSpec.describe Saml::Kit::LogoutRequest do
end
it 'parses the version' do
- expect(subject.version).to eql("2.0")
+ expect(subject.version).to eql('2.0')
end
it 'parses the destination' do
- destination = FFaker::Internet.uri("https")
+ destination = FFaker::Internet.uri('https')
subject = described_class.build(user, configuration: configuration) do |builder|
builder.destination = destination
end
@@ -40,15 +41,15 @@ RSpec.describe Saml::Kit::LogoutRequest do
expect(subject.name_id).to eql(name_id)
end
- describe "#valid?" do
+ describe '#valid?' do
let(:metadata) do
Saml::Kit::ServiceProviderMetadata.build(configuration: configuration) do |builder|
builder.entity_id = entity_id
- builder.add_single_logout_service(FFaker::Internet.uri("https"), binding: :http_post)
+ builder.add_single_logout_service(FFaker::Internet.uri('https'), binding: :http_post)
end
end
- before :each do
+ before do
allow(registry).to receive(:metadata_for).and_return(metadata)
end
@@ -57,7 +58,7 @@ RSpec.describe Saml::Kit::LogoutRequest do
end
it 'is invalid if the document has been tampered with' do
- issuer = FFaker::Internet.uri("https")
+ issuer = FFaker::Internet.uri('https')
raw_xml = described_class.build(user, configuration: configuration) do |builder|
builder.issuer = issuer
end.to_xml.gsub(issuer, 'corrupt')
@@ -98,12 +99,12 @@ RSpec.describe Saml::Kit::LogoutRequest do
end
it 'is valid when a single logout service url is available via the registry' do
- issuer = FFaker::Internet.uri("https")
+ issuer = FFaker::Internet.uri('https')
allow(registry).to receive(:metadata_for).with(issuer).and_return(metadata)
allow(metadata).to receive(:matches?).and_return(true)
allow(metadata).to receive(:single_logout_services).and_return([
- Saml::Kit::Bindings::HttpPost.new(location: FFaker::Internet.uri("https"))
- ])
+ Saml::Kit::Bindings::HttpPost.new(location: FFaker::Internet.uri('https'))
+ ])
subject = described_class.build(user, configuration: configuration) do |builder|
builder.issuer = issuer
@@ -118,7 +119,7 @@ RSpec.describe Saml::Kit::LogoutRequest do
xml.LogoutRequest ID: id do
signature.template(id)
xml.Fake do
- xml.NotAllowed "Huh?"
+ xml.NotAllowed 'Huh?'
end
end
end
@@ -126,10 +127,10 @@ RSpec.describe Saml::Kit::LogoutRequest do
end
end
- describe "#response_for" do
+ describe '#response_for' do
let(:provider) do
Saml::Kit::IdentityProviderMetadata.build do |builder|
- builder.add_single_logout_service(FFaker::Internet.uri("https"), binding: :http_post)
+ builder.add_single_logout_service(FFaker::Internet.uri('https'), binding: :http_post)
end
end
spec/saml/metadata_spec.rb
@@ -1,5 +1,5 @@
RSpec.describe Saml::Kit::Metadata do
- describe ".from" do
+ describe '.from' do
subject { described_class }
it 'returns an identity provider metadata' do
@@ -14,17 +14,17 @@ RSpec.describe Saml::Kit::Metadata do
it 'returns a composite' do
xml = <<-XML
-<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{Xml::Kit::Id.generate}" entityID="#{FFaker::Internet.uri("https")}">
+<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{Xml::Kit::Id.generate}" entityID="#{FFaker::Internet.uri('https')}">
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
- <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
<NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
- <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}" index="0" isDefault="true"/>
+ <AssertionConsumerService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}" index="0" isDefault="true"/>
</SPSSODescriptor>
<IDPSSODescriptor WantAuthnRequestsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
- <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
<NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
- <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
- <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
+ <SingleSignOnService Binding="#{Saml::Kit::Bindings::HTTP_REDIRECT}" Location="#{FFaker::Internet.uri('https')}"/>
</IDPSSODescriptor>
<Organization>
<OrganizationName xml:lang="en">Acme, Inc</OrganizationName>
@@ -39,33 +39,33 @@ RSpec.describe Saml::Kit::Metadata do
result = subject.from(xml)
expect(result).to be_present
- expect(result.single_sign_on_services.count).to eql(2)
- expect(result.assertion_consumer_services.count).to eql(1)
- expect(result.single_logout_services.count).to eql(2)
- expect(result.organization_name).to eql("Acme, Inc")
- expect(result.organization_url).to eql("http://localhost:5000/")
- expect(result.contact_person_company).to eql("mailto:hi@example.com")
+ expect(result.single_sign_on_services.count).to be(2)
+ expect(result.assertion_consumer_services.count).to be(1)
+ expect(result.single_logout_services.count).to be(2)
+ expect(result.organization_name).to eql('Acme, Inc')
+ expect(result.organization_url).to eql('http://localhost:5000/')
+ expect(result.contact_person_company).to eql('mailto:hi@example.com')
end
end
- describe "#certificates" do
+ describe '#certificates' do
it 'returns each certificate when missing a "use"' do
configuration = Saml::Kit::Configuration.new do |config|
config.generate_key_pair_for(use: :signing)
end
- xml = Saml::Kit::Metadata.build_xml(configuration: configuration) do |x|
+ xml = described_class.build_xml(configuration: configuration) do |x|
x.embed_signature = false
x.build_identity_provider
end
modified_xml = xml.gsub(/use/, 'misuse')
subject = described_class.from(modified_xml)
- expect(subject.certificates.count).to eql(1)
+ expect(subject.certificates.count).to be(1)
end
end
- describe "#signature" do
+ describe '#signature' do
it 'returns the signature' do
- subject = Saml::Kit::Metadata.build do |x|
+ subject = described_class.build do |x|
x.sign_with(::Xml::Kit::KeyPair.generate(use: :signing))
x.build_identity_provider
end
spec/saml/response_spec.rb
@@ -1,10 +1,12 @@
RSpec.describe Saml::Kit::Response do
- describe "#valid?" do
+ describe '#valid?' do
+ subject { described_class.build(user, request, configuration: configuration) }
+
let(:request) { instance_double(Saml::Kit::AuthenticationRequest, id: ::Xml::Kit::Id.generate, issuer: FFaker::Internet.http_url, assertion_consumer_service_url: FFaker::Internet.http_url, name_id_format: Saml::Kit::Namespaces::PERSISTENT, provider: nil, signed?: true, trusted?: true) }
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: { id: SecureRandom.uuid }) }
let(:registry) { instance_double(Saml::Kit::DefaultRegistry) }
let(:metadata) { instance_double(Saml::Kit::IdentityProviderMetadata) }
- subject { described_class.build(user, request, configuration: configuration) }
+
let(:configuration) do
Saml::Kit::Configuration.new do |config|
config.entity_id = request.issuer
@@ -21,10 +23,10 @@ RSpec.describe Saml::Kit::Response do
it 'is invalid when blank' do
allow(registry).to receive(:metadata_for).and_return(nil)
- subject = described_class.new("")
+ subject = described_class.new('')
expect(subject).to be_invalid
expect(subject.errors[:content]).to be_present
- expect(subject.errors[:assertion]).to match_array(["is missing."])
+ expect(subject.errors[:assertion]).to match_array(['is missing.'])
end
it 'is invalid if the document has been tampered with' do
@@ -33,7 +35,7 @@ RSpec.describe Saml::Kit::Response do
status_code = FFaker::Movie.title
xml = described_class.build(user, request) do |builder|
builder.status_code = status_code
- end.to_xml.gsub(status_code, "TAMPERED")
+ end.to_xml.gsub(status_code, 'TAMPERED')
subject = described_class.new(xml)
expect(subject).to be_invalid
end
@@ -58,10 +60,10 @@ RSpec.describe Saml::Kit::Response do
id = Xml::Kit::Id.generate
key_pair = ::Xml::Kit::KeyPair.generate(use: :signing)
signed_xml = ::Xml::Kit::Signatures.sign(key_pair: key_pair) do |xml, signature|
- xml.tag! "samlp:Response", "xmlns:samlp" => Saml::Kit::Namespaces::PROTOCOL, ID: id do
+ xml.tag! 'samlp:Response', 'xmlns:samlp' => Saml::Kit::Namespaces::PROTOCOL, ID: id do
signature.template(id)
xml.Fake do
- xml.NotAllowed "Huh?"
+ xml.NotAllowed 'Huh?'
end
end
end
@@ -74,7 +76,7 @@ RSpec.describe Saml::Kit::Response do
allow(registry).to receive(:metadata_for).and_return(metadata)
allow(metadata).to receive(:matches?).and_return(true)
subject = described_class.build(user, request) do |builder|
- builder.version = "1.1"
+ builder.version = '1.1'
end
expect(subject).to be_invalid
expect(subject.errors[:version]).to be_present
@@ -116,8 +118,8 @@ RSpec.describe Saml::Kit::Response do
subject = described_class.build(user, request)
travel_to Saml::Kit.configuration.session_timeout.from_now + 5.seconds
- expect(subject).to_not be_valid
- expect(subject.errors[:assertion]).to match_array(["must not be expired."])
+ expect(subject).not_to be_valid
+ expect(subject.errors[:assertion]).to match_array(['must not be expired.'])
end
it 'is invalid before the valid session window' do
@@ -127,15 +129,15 @@ RSpec.describe Saml::Kit::Response do
subject = described_class.build(user, request)
travel_to (Saml::Kit.configuration.clock_drift + 1.second).before(Time.now)
expect(subject).to be_invalid
- expect(subject.errors[:assertion]).to match_array(["must not be expired."])
+ expect(subject.errors[:assertion]).to match_array(['must not be expired.'])
end
it 'is invalid when the audience does not match the expected issuer' do
allow(registry).to receive(:metadata_for).and_return(metadata)
allow(metadata).to receive(:matches?).and_return(true)
- allow(configuration).to receive(:issuer).and_return(FFaker::Internet.uri("https"))
- allow(request).to receive(:issuer).and_return(FFaker::Internet.uri("https"))
+ allow(configuration).to receive(:issuer).and_return(FFaker::Internet.uri('https'))
+ allow(request).to receive(:issuer).and_return(FFaker::Internet.uri('https'))
expect(subject).to be_invalid
expect(subject.errors[:audience]).to be_present
@@ -143,7 +145,7 @@ RSpec.describe Saml::Kit::Response do
it 'is invalid' do
now = Time.now.utc
- destination = FFaker::Internet.uri("https")
+ destination = FFaker::Internet.uri('https')
raw_xml = <<-XML
<?xml version="1.0"?>
<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" ID="#{Xml::Kit::Id.generate}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{destination}" Consent="#{Saml::Kit::Namespaces::UNSPECIFIED}" InResponseTo="#{request.id}">
@@ -161,11 +163,11 @@ RSpec.describe Saml::Kit::Response do
it 'is invalid when there are 2 assertions' do
id = Xml::Kit::Id.generate
- issuer = FFaker::Internet.uri("https")
+ issuer = FFaker::Internet.uri('https')
key_pair = ::Xml::Kit::KeyPair.generate(use: :signing)
response_options = {
ID: id,
- Version: "2.0",
+ Version: '2.0',
IssueInstant: Time.now.iso8601,
Consent: Saml::Kit::Namespaces::UNSPECIFIED,
InResponseTo: request.id,
@@ -174,7 +176,7 @@ RSpec.describe Saml::Kit::Response do
assertion_options = {
ID: Xml::Kit::Id.generate,
IssueInstant: Time.now.iso8601,
- Version: "2.0",
+ Version: '2.0',
xmlns: Saml::Kit::Namespaces::ASSERTION,
}
xml = ::Xml::Kit::Signatures.sign(key_pair: key_pair) do |xml, signature|
@@ -190,7 +192,7 @@ RSpec.describe Saml::Kit::Response do
xml.Subject do
xml.NameID FFaker::Internet.email, Format: Saml::Kit::Namespaces::EMAIL_ADDRESS
xml.SubjectConfirmation Method: Saml::Kit::Namespaces::BEARER do
- xml.SubjectConfirmationData "", InResponseTo: request.id, NotOnOrAfter: 3.hours.from_now.utc.iso8601, Recipient: FFaker::Internet.uri("https")
+ xml.SubjectConfirmationData '', InResponseTo: request.id, NotOnOrAfter: 3.hours.from_now.utc.iso8601, Recipient: FFaker::Internet.uri('https')
end
end
xml.Conditions NotBefore: Time.now.utc.iso8601, NotOnOrAfter: 3.hours.from_now.utc.iso8601 do
@@ -210,7 +212,7 @@ RSpec.describe Saml::Kit::Response do
xml.Subject do
xml.NameID FFaker::Internet.email, Format: Saml::Kit::Namespaces::EMAIL_ADDRESS
xml.SubjectConfirmation Method: Saml::Kit::Namespaces::BEARER do
- xml.SubjectConfirmationData "", InResponseTo: request.id, NotOnOrAfter: 3.hours.from_now.utc.iso8601, Recipient: FFaker::Internet.uri("https")
+ xml.SubjectConfirmationData '', InResponseTo: request.id, NotOnOrAfter: 3.hours.from_now.utc.iso8601, Recipient: FFaker::Internet.uri('https')
end
end
xml.Conditions NotBefore: Time.now.utc.iso8601, NotOnOrAfter: 3.hours.from_now.utc.iso8601 do
@@ -227,8 +229,8 @@ RSpec.describe Saml::Kit::Response do
end
end
subject = described_class.new(xml)
- expect(subject).to_not be_valid
- expect(subject.errors.full_messages).to include("must contain a single Assertion.")
+ expect(subject).not_to be_valid
+ expect(subject.errors.full_messages).to include('must contain a single Assertion.')
end
it 'is invalid when the assertion has a signature and has been tampered with' do
@@ -241,7 +243,7 @@ RSpec.describe Saml::Kit::Response do
altered_xml = document.to_xml.gsub(/token/, 'heck')
subject = described_class.new(altered_xml)
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
expect(subject.errors[:digest_value]).to be_present
end
@@ -252,14 +254,14 @@ RSpec.describe Saml::Kit::Response do
subject = described_class.new(xml)
expect(subject).to be_invalid
- expect(subject.errors[:assertion]).to match_array(["cannot be decrypted."])
+ expect(subject.errors[:assertion]).to match_array(['cannot be decrypted.'])
end
end
- describe "#signed?" do
+ describe '#signed?' do
let(:now) { Time.now.utc }
let(:id) { Xml::Kit::Id.generate }
- let(:url) { FFaker::Internet.uri("https") }
+ let(:url) { FFaker::Internet.uri('https') }
it 'returns true when the Assertion is signed' do
xml = <<-XML
@@ -290,7 +292,7 @@ RSpec.describe Saml::Kit::Response do
</samlp:Response>
XML
subject = described_class.new(xml)
- expect(subject).to_not be_signed
+ expect(subject).not_to be_signed
expect(subject.assertion).to be_signed
end
@@ -333,17 +335,17 @@ RSpec.describe Saml::Kit::Response do
</samlp:Response>
XML
subject = described_class.new(xml)
- expect(subject).to_not be_signed
+ expect(subject).not_to be_signed
end
end
- describe "#certificate" do
+ describe '#certificate' do
let(:now) { Time.now.utc }
let(:id) { Xml::Kit::Id.generate }
- let(:url) { FFaker::Internet.uri("https") }
+ let(:url) { FFaker::Internet.uri('https') }
let(:certificate) do
::Xml::Kit::Certificate.new(
- ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: "password")[0],
+ ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: 'password')[0],
use: :signing
)
end
@@ -377,7 +379,7 @@ RSpec.describe Saml::Kit::Response do
</samlp:Response>
XML
subject = described_class.new(xml)
- expect(subject.signature).to_not be_present
+ expect(subject.signature).not_to be_present
expect(subject.assertion.signature).to be_present
expect(subject.assertion.signature.certificate.stripped).to eql(certificate.stripped)
end
@@ -421,21 +423,21 @@ RSpec.describe Saml::Kit::Response do
</samlp:Response>
XML
subject = described_class.new(xml)
- expect(subject.signature).to_not be_present
+ expect(subject.signature).not_to be_present
end
end
- describe "encrypted assertion" do
+ describe 'encrypted assertion' do
let(:id) { Xml::Kit::Id.generate }
let(:now) { Time.now.utc }
- let(:assertion_consumer_service_url) { FFaker::Internet.uri("https") }
+ let(:assertion_consumer_service_url) { FFaker::Internet.uri('https') }
let(:password) { FFaker::Movie.title }
let(:email) { FFaker::Internet.email }
let(:created_at) { DateTime.now }
let(:assertion) do
<<-XML
<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="2017-11-23T04:33:58Z" Version="2.0">
- <Issuer>#{FFaker::Internet.uri("https")}</Issuer>
+ <Issuer>#{FFaker::Internet.uri('https')}</Issuer>
<Subject>
<NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
<SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
@@ -479,7 +481,7 @@ XML
xml = <<-XML
<samlp:Response xmlns:samlp="#{Saml::Kit::Namespaces::PROTOCOL}" xmlns:saml="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" Version="2.0" IssueInstant="#{now.iso8601}" Destination="#{assertion_consumer_service_url}" InResponseTo="#{Xml::Kit::Id.generate}">
- <saml:Issuer>#{FFaker::Internet.uri("https")}</saml:Issuer>
+ <saml:Issuer>#{FFaker::Internet.uri('https')}</saml:Issuer>
<samlp:Status>
<samlp:StatusCode Value="#{Saml::Kit::Namespaces::SUCCESS}"/>
</samlp:Status>
@@ -504,15 +506,15 @@ XML
subject = described_class.new(xml)
expect(subject.attributes).to match_array([
- ["created_at", created_at.iso8601],
- ["email", email]
- ])
+ ['created_at', created_at.iso8601],
+ ['email', email]
+ ])
end
end
- describe "parsing" do
+ describe 'parsing' do
let(:user) { double(:user, name_id_for: SecureRandom.uuid, assertion_attributes_for: attributes) }
- let(:request) { double(:request, id: Xml::Kit::Id.generate, signed?: true, trusted?: true, provider: nil, assertion_consumer_service_url: FFaker::Internet.uri("https"), name_id_format: '', issuer: FFaker::Internet.uri("https")) }
+ let(:request) { double(:request, id: Xml::Kit::Id.generate, signed?: true, trusted?: true, provider: nil, assertion_consumer_service_url: FFaker::Internet.uri('https'), name_id_format: '', issuer: FFaker::Internet.uri('https')) }
let(:attributes) { { name: 'mo' } }
it 'returns the name id' do
spec/saml/service_provider_metadata_spec.rb
@@ -1,9 +1,9 @@
RSpec.describe Saml::Kit::ServiceProviderMetadata do
- let(:entity_id) { FFaker::Internet.uri("https") }
- let(:acs_post_url) { FFaker::Internet.uri("https") }
- let(:acs_redirect_url) { FFaker::Internet.uri("https") }
- let(:logout_post_url) { FFaker::Internet.uri("https") }
- let(:logout_redirect_url) { FFaker::Internet.uri("https") }
+ let(:entity_id) { FFaker::Internet.uri('https') }
+ let(:acs_post_url) { FFaker::Internet.uri('https') }
+ let(:acs_redirect_url) { FFaker::Internet.uri('https') }
+ let(:logout_post_url) { FFaker::Internet.uri('https') }
+ let(:logout_redirect_url) { FFaker::Internet.uri('https') }
describe described_class do
subject do
@@ -25,22 +25,22 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
it 'returns each acs url and binding' do
expect(subject.assertion_consumer_services.map(&:to_h)).to match_array([
- { location: acs_post_url, binding: Saml::Kit::Bindings::HTTP_POST },
- { location: acs_redirect_url, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
- ])
+ { location: acs_post_url, binding: Saml::Kit::Bindings::HTTP_POST },
+ { location: acs_redirect_url, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
+ ])
end
it 'returns each logout url and binding' do
expect(subject.single_logout_services.map(&:to_h)).to match_array([
- { location: logout_post_url, binding: Saml::Kit::Bindings::HTTP_POST },
- { location: logout_redirect_url, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
- ])
+ { location: logout_post_url, binding: Saml::Kit::Bindings::HTTP_POST },
+ { location: logout_redirect_url, binding: Saml::Kit::Bindings::HTTP_REDIRECT },
+ ])
end
it 'returns each of the nameid formats' do
expect(subject.name_id_formats).to match_array([
- Saml::Kit::Namespaces::PERSISTENT
- ])
+ Saml::Kit::Namespaces::PERSISTENT
+ ])
end
it 'returns the entity id' do
@@ -48,7 +48,7 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
end
end
- describe "#validate" do
+ describe '#validate' do
let(:service_provider_metadata) do
described_class.build(configuration: configuration) do |builder|
builder.entity_id = entity_id
@@ -69,9 +69,9 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
end
it 'is invalid, when given identity provider metadata' do
- subject = described_class.new(IO.read("spec/fixtures/metadata/okta.xml"))
+ subject = described_class.new(IO.read('spec/fixtures/metadata/okta.xml'))
expect(subject).to be_invalid
- expect(subject.errors[:base]).to include(I18n.translate("saml/kit.errors.SPSSODescriptor.invalid"))
+ expect(subject.errors[:base]).to include(I18n.translate('saml/kit.errors.SPSSODescriptor.invalid'))
end
it 'is invalid, when the metadata is nil' do
@@ -89,7 +89,7 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
end
end
subject = described_class.new(xml.target!)
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
expect(subject.errors[:base][0]).to include("1:0: ERROR: Element '{urn:oasis:names:tc:SAML:2.0:metadata}EntityDescriptor'")
end
@@ -98,7 +98,7 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
metadata_xml = service_provider_metadata.gsub(acs_post_url, new_url)
subject = described_class.new(metadata_xml)
expect(subject).to be_invalid
- expect(subject.errors[:digest_value]).to include("is invalid.")
+ expect(subject.errors[:digest_value]).to include('is invalid.')
end
it 'is invalid when 0 ACS endpoints are specified' do
@@ -106,7 +106,7 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
<?xml version="1.0" encoding="UTF-8"?>
<EntityDescriptor xmlns="#{Saml::Kit::Namespaces::METADATA}" ID="#{::Xml::Kit::Id.generate}" entityID="#{entity_id}">
<SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="true" protocolSupportEnumeration="#{Saml::Kit::Namespaces::PROTOCOL}">
- <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri("https")}"/>
+ <SingleLogoutService Binding="#{Saml::Kit::Bindings::HTTP_POST}" Location="#{FFaker::Internet.uri('https')}"/>
<NameIDFormat>#{Saml::Kit::Namespaces::PERSISTENT}</NameIDFormat>
</SPSSODescriptor>
</EntityDescriptor>
@@ -115,29 +115,30 @@ RSpec.describe Saml::Kit::ServiceProviderMetadata do
end
end
- describe "#matches?" do
+ describe '#matches?' do
+ subject { described_class.build(configuration: configuration) }
+
let(:configuration) do
config = Saml::Kit::Configuration.new
config.generate_key_pair_for(use: :signing)
config
end
- subject { Saml::Kit::ServiceProviderMetadata.build(configuration: configuration) }
it 'returns true when the fingerprint matches one of the signing certificates' do
certificate = Hash.from_xml(subject.to_xml)['EntityDescriptor']['Signature']['KeyInfo']['X509Data']['X509Certificate']
fingerprint = ::Xml::Kit::Fingerprint.new(certificate)
- expect(subject.matches?(fingerprint)).to be_truthy
+ expect(subject).to be_matches(fingerprint)
end
it 'returns false when the fingerprint does not match one of the signing certificates' do
- certificate, _ = ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: 'password')
+ certificate, = ::Xml::Kit::SelfSignedCertificate.new.create(passphrase: 'password')
fingerprint = ::Xml::Kit::Fingerprint.new(certificate)
- expect(subject.matches?(fingerprint)).to be_falsey
+ expect(subject).not_to be_matches(fingerprint)
end
end
- describe ".build" do
- let(:assertion_consumer_service_url) { FFaker::Internet.uri("https") }
+ describe '.build' do
+ let(:assertion_consumer_service_url) { FFaker::Internet.uri('https') }
it 'provides a nice API for building metadata' do
result = described_class.build do |builder|
spec/saml/signature_spec.rb
@@ -1,4 +1,6 @@
RSpec.describe Saml::Kit::Signature do
+ subject { described_class.new(signed_document.at_xpath('//ds:Signature')) }
+
let(:key_pair) { ::Xml::Kit::KeyPair.generate(use: :signing) }
let(:signed_document) do
Saml::Kit::AuthenticationRequest.build do |x|
@@ -6,7 +8,6 @@ RSpec.describe Saml::Kit::Signature do
end
end
let(:xml_hash) { Hash.from_xml(subject.to_xml) }
- subject { described_class.new(signed_document.at_xpath('//ds:Signature')) }
specify { expect(subject.digest_value).to eql(xml_hash['Signature']['SignedInfo']['Reference']['DigestValue']) }
specify { expect(subject.digest_method).to eql(xml_hash['Signature']['SignedInfo']['Reference']['DigestMethod']['Algorithm']) }
@@ -19,24 +20,24 @@ RSpec.describe Saml::Kit::Signature do
expect(subject.certificate).to eql(expected)
end
- describe "#valid?" do
+ describe '#valid?' do
it 'returns true when the signature is valid' do
expect(subject).to be_valid
end
it 'is invalid when the xml has been tampered' do
- signed_document.at_xpath('//saml:Issuer').content = "INVALID"
- expect(subject).to_not be_valid
+ signed_document.at_xpath('//saml:Issuer').content = 'INVALID'
+ expect(subject).not_to be_valid
expect(subject.errors[:digest_value]).to be_present
end
it 'is invalid when the signature is missing' do
subject = described_class.new(nil)
- expect(subject).to_not be_valid
+ expect(subject).not_to be_valid
expect(subject.errors[:base]).to match_array(['is missing.'])
end
- describe "certificate validation" do
+ describe 'certificate validation' do
let(:key_pair) { ::Xml::Kit::KeyPair.new(expired_certificate, private_key, nil, :signing) }
let(:private_key) { OpenSSL::PKey::RSA.new(2048) }
let(:expired_certificate) do
@@ -48,47 +49,47 @@ RSpec.describe Saml::Kit::Signature do
certificate
end
- context "when the certificate is expired" do
+ context 'when the certificate is expired' do
let(:not_before) { 10.minutes.ago }
let(:not_after) { 1.minute.ago }
it 'is invalid' do
expect(subject).to be_invalid
expect(subject.errors[:certificate]).to match_array([
- "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
- ])
+ "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
+ ])
end
end
- context "when the certificate is not active yet" do
+ context 'when the certificate is not active yet' do
let(:not_before) { 10.minutes.from_now }
let(:not_after) { 20.minute.from_now }
- it 'it invalid' do
+ it 'invalid' do
expect(subject).to be_invalid
expect(subject.errors[:certificate]).to match_array([
- "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
- ])
+ "Not valid before #{expired_certificate.not_before}. Not valid after #{expired_certificate.not_after}."
+ ])
end
end
end
end
- describe "#to_h" do
+ describe '#to_h' do
it 'returns a hash representation of the signature' do
expected = Hash.from_xml(signed_document.to_s)['AuthnRequest']['Signature']
expect(subject.to_h).to eql(expected)
end
end
- describe "#present?" do
- context "when a signature is not present" do
+ describe '#present?' do
+ context 'when a signature is not present' do
it 'return false' do
- expect(described_class.new(nil)).to_not be_present
+ expect(described_class.new(nil)).not_to be_present
end
end
- context "when a signature is present" do
+ context 'when a signature is present' do
it 'returns true' do
expect(subject).to be_present
end
spec/support/test_helpers.rb
@@ -1,6 +1,6 @@
module TestHelpers
def query_params_from(url)
- Hash[query_for(url).split("&").map { |x| x.split('=', 2) }]
+ Hash[query_for(url).split('&').map { |x| x.split('=', 2) }]
end
def uri_for(url)
spec/spec_helper.rb
@@ -2,12 +2,12 @@ require 'simplecov'
SimpleCov.start do
add_filter '/spec/'
end
-require "bundler/setup"
-require "saml/kit"
-require "saml/kit/rspec"
-require "active_support/testing/time_helpers"
-require "ffaker"
-require "webmock/rspec"
+require 'bundler/setup'
+require 'saml/kit'
+require 'saml/kit/rspec'
+require 'active_support/testing/time_helpers'
+require 'ffaker'
+require 'webmock/rspec'
Saml::Kit.configuration.logger.level = Xml::Kit.logger.level = Logger::FATAL
@@ -15,7 +15,7 @@ Dir[File.join(Dir.pwd, 'spec/support/**/*.rb')].each { |f| require f }
RSpec.configure do |config|
config.include ActiveSupport::Testing::TimeHelpers
# Enable flags like --only-failures and --next-failure
- config.example_status_persistence_file_path = ".rspec_status"
+ config.example_status_persistence_file_path = '.rspec_status'
# Disable RSpec exposing methods globally on `Module` and `main`
config.disable_monkey_patching!
@@ -23,7 +23,7 @@ RSpec.configure do |config|
config.expect_with :rspec do |c|
c.syntax = :expect
end
- config.after :each do
+ config.after do
travel_back
end
end
.rubocop.yml
@@ -54,7 +54,7 @@ Metrics/LineLength:
- 'spec/**/*.rb'
Style/StringLiterals:
- EnforcedStyle: 'double_quotes'
+ EnforcedStyle: 'single_quotes'
Style/TrailingCommaInLiteral:
Enabled: false
Gemfile
@@ -1,6 +1,6 @@
-source "https://rubygems.org"
+source 'https://rubygems.org'
-git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
+git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
# Specify your gem's dependencies in saml-kit.gemspec
gemspec
Rakefile
@@ -1,8 +1,8 @@
-require "bundler/gem_tasks"
-require "rspec/core/rake_task"
+require 'bundler/gem_tasks'
+require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
task default: :spec
-require "rubocop/rake_task"
+require 'rubocop/rake_task'
RuboCop::RakeTask.new(:rubocop)
saml-kit.gemspec
@@ -1,36 +1,36 @@
-# coding: utf-8
-lib = File.expand_path("../lib", __FILE__)
+
+lib = File.expand_path('../lib', __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
-require "saml/kit/version"
+require 'saml/kit/version'
Gem::Specification.new do |spec|
- spec.name = "saml-kit"
+ spec.name = 'saml-kit'
spec.version = Saml::Kit::VERSION
- spec.authors = ["mo khan"]
- spec.email = ["mo@mokhan.ca"]
+ spec.authors = ['mo khan']
+ spec.email = ['mo@mokhan.ca']
- spec.summary = %q{A simple toolkit for working with SAML.}
- spec.description = %q{A simple toolkit for working with SAML.}
- spec.homepage = "https://github.com/saml-kit/saml-kit"
- spec.license = "MIT"
+ spec.summary = 'A simple toolkit for working with SAML.'
+ spec.description = 'A simple toolkit for working with SAML.'
+ spec.homepage = 'https://github.com/saml-kit/saml-kit'
+ spec.license = 'MIT'
spec.required_ruby_version = '>= 2.2.0'
- spec.files = `git ls-files -z`.split("\x0").reject do |f|
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
f.match(%r{^(test|spec|features)/})
end
- spec.metadata["yard.run"] = "yri"
- spec.bindir = "exe"
+ spec.metadata['yard.run'] = 'yri'
+ spec.bindir = 'exe'
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
- spec.require_paths = ["lib"]
+ spec.require_paths = ['lib']
- spec.add_dependency "activemodel", ">= 4.2.0"
- spec.add_dependency "xml-kit", ">= 0.1.10", "<= 1.0.0"
- spec.add_development_dependency "bundler", "~> 1.15"
- spec.add_development_dependency "ffaker", "~> 2.7"
- spec.add_development_dependency "rake", "~> 10.0"
- spec.add_development_dependency "rspec", "~> 3.0"
- spec.add_development_dependency "simplecov", "~> 0.15"
- spec.add_development_dependency "webmock", "~> 3.1"
- spec.add_development_dependency "rubocop", "~> 0.52"
- spec.add_development_dependency "rubocop-rspec", "~> 1.22"
+ spec.add_dependency 'activemodel', '>= 4.2.0'
+ spec.add_dependency 'xml-kit', '>= 0.1.10', '<= 1.0.0'
+ spec.add_development_dependency 'bundler', '~> 1.15'
+ spec.add_development_dependency 'ffaker', '~> 2.7'
+ spec.add_development_dependency 'rake', '~> 10.0'
+ spec.add_development_dependency 'rspec', '~> 3.0'
+ spec.add_development_dependency 'rubocop', '~> 0.52'
+ spec.add_development_dependency 'rubocop-rspec', '~> 1.22'
+ spec.add_development_dependency 'simplecov', '~> 0.15'
+ spec.add_development_dependency 'webmock', '~> 3.1'
end