Module: Samlr::Tools

Defined in:
lib/samlr/tools.rb,
lib/samlr/tools/timestamp.rb,
lib/samlr/tools/request_builder.rb,
lib/samlr/tools/metadata_builder.rb,
lib/samlr/tools/response_builder.rb,
lib/samlr/tools/certificate_builder.rb,
lib/samlr/tools/logout_request_builder.rb

Defined Under Namespace

Modules: LogoutRequestBuilder, RequestBuilder, ResponseBuilder, Timestamp Classes: CertificateBuilder, MetadataBuilder

Constant Summary collapse

SHA_MAP =
{
  1    => OpenSSL::Digest::SHA1,
  256  => OpenSSL::Digest::SHA256,
  384  => OpenSSL::Digest::SHA384,
  512  => OpenSSL::Digest::SHA512
}

Class Method Summary collapse

Class Method Details

.algorithm(value) ⇒ Object

Convert algorithm attribute value to Ruby implementation



24
25
26
27
28
29
30
# File 'lib/samlr/tools.rb', line 24

def self.algorithm(value)
  if value =~ /sha(\d+)$/
    implementation = SHA_MAP[$1.to_i]
  end

  implementation || OpenSSL::Digest::SHA1
end

.canonicalize(xml, options = {}) ⇒ Object

Accepts a document and optionally :path => xpath, :c14n_mode => c14n_mode



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/samlr/tools.rb', line 33

def self.canonicalize(xml, options = {})
  options  = { :c14n_mode => C14N }.merge(options)
  document = Nokogiri::XML(xml) { |c| c.strict.noblanks }

  if path = options[:path]
    node = document.at(path, NS_MAP)
  else
    node = document
  end

  node.canonicalize(options[:c14n_mode], options[:namespaces])
end

.decode(string) ⇒ Object

CGI unescapes, Base64 decodes and inflates a string



60
61
62
63
64
65
66
67
68
69
70
# File 'lib/samlr/tools.rb', line 60

def self.decode(string)
  unescaped = CGI.unescape(string)
  decoded   = Base64.decode64(unescaped)
  inflater  = Zlib::Inflate.new(-Zlib::MAX_WBITS)
  inflated  = inflater.inflate(decoded)

  inflater.finish
  inflater.close

  inflated
end

.encode(string) ⇒ Object

Deflates, Base64 encodes and CGI escapes a string



52
53
54
55
56
57
# File 'lib/samlr/tools.rb', line 52

def self.encode(string)
  deflated = Zlib::Deflate.deflate(string, 9)[2..-5]
  encoded  = Base64.encode64(deflated)
  escaped  = CGI.escape(encoded)
  escaped
end

.uuidObject

Generate an xs:NCName conforming UUID



47
48
49
# File 'lib/samlr/tools.rb', line 47

def self.uuid
  "samlr-#{UUIDTools::UUID.timestamp_create}"
end

.validate(options = {}) ⇒ Object

Validate a SAML request or response against an XSD. Supply either :path or :document in the options and a :schema (defaults to SAML validation)



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/samlr/tools.rb', line 78

def self.validate(options = {})
  document = options[:document] || File.read(options[:path])
  schema   = options.fetch(:schema, SAML_SCHEMA)
  bang     = options.fetch(:bang, false)

  if document.is_a?(Nokogiri::XML::Document)
    xml = document
  else
    xml = Nokogiri::XML(document) { |c| c.strict }
  end

  # All bundled schemas are using relative schemaLocation. This means we'll have to
  # change working directory to find them during validation.
  Dir.chdir(Samlr.schema_location) do
    if schema.is_a?(Nokogiri::XML::Schema)
      xsd = schema
    else
      xsd = Nokogiri::XML::Schema(File.read(schema))
    end

    result = xsd.validate(xml)

    if bang && result.length != 0
      raise Samlr::FormatError.new("Schema validation failed", "XSD validation errors: #{result.join(", ")}")
    else
      result.length == 0
    end
  end
end

.validate!(options = {}) ⇒ Object



72
73
74
# File 'lib/samlr/tools.rb', line 72

def self.validate!(options = {})
  validate(options.merge(:bang => true))
end