Comparing changes

v1.0.4 v1.0.5
9 commits 7 files changed

Commits

a77e893 log the http connections. mo 2018-02-12 17:46:36
b8fcff0 fix typo. mo 2018-02-10 02:17:03
667d69a add spec to validate signature. mo 2018-02-10 02:07:35
5973a84 extract common namespaces. mo 2018-02-10 01:56:38
385f2ac extract let mo 2018-02-10 01:42:49
507713e generate the email address. mo 2018-02-10 01:37:50
lib/saml/kit/assertion.rb
@@ -36,7 +36,8 @@ module Saml
       end
 
       def active?(now = Time.current)
-        now > configuration.clock_drift.seconds.before(started_at) && !expired?
+        drifted_started_at = started_at - configuration.clock_drift.to_i.seconds
+        now > drifted_started_at && !expired?
       end
 
       def attributes
lib/saml/kit/default_registry.rb
@@ -90,6 +90,7 @@ module Saml
           http.read_timeout = 30
           http.use_ssl = uri.is_a?(URI::HTTPS)
           http.verify_mode = OpenSSL::SSL::VERIFY_NONE unless verify_ssl
+          http.set_debug_output(Saml::Kit.logger)
           http
         end
       end
lib/saml/kit/namespaces.rb
@@ -1,25 +1,32 @@
 module Saml
   module Kit
     module Namespaces
-      ASSERTION = "urn:oasis:names:tc:SAML:2.0:assertion"
-      ATTR_SPLAT = "urn:oasis:names:tc:SAML:2.0:attrname-format:*"
-      BASIC = "urn:oasis:names:tc:SAML:2.0:attrname-format:basic"
-      BEARER = "urn:oasis:names:tc:SAML:2.0:cm:bearer"
-      EMAIL_ADDRESS = "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"
-      INVALID_NAME_ID_POLICY = "urn:oasis:names:tc:SAML:2.0:status:InvalidNameIDPolicy"
-      METADATA = "urn:oasis:names:tc:SAML:2.0:metadata"
-      PASSWORD = "urn:oasis:names:tc:SAML:2.0:ac:classes:Password"
-      PASSWORD_PROTECTED = "urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"
-      PERSISTENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"
-      PROTOCOL = "urn:oasis:names:tc:SAML:2.0:protocol"
-      REQUESTER_ERROR = "urn:oasis:names:tc:SAML:2.0:status:Requester"
-      RESPONDER_ERROR = "urn:oasis:names:tc:SAML:2.0:status:Responder"
-      SUCCESS = "urn:oasis:names:tc:SAML:2.0:status:Success"
-      TRANSIENT = "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
-      UNSPECIFIED = "urn:oasis:names:tc:SAML:2.0:consent:unspecified"
-      UNSPECIFIED_NAMEID = "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
-      URI = "urn:oasis:names:tc:SAML:2.0:attrname-format:uri"
-      VERSION_MISMATCH_ERROR = "urn:oasis:names:tc:SAML:2.0:status:VersionMismatch"
+      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"
+
+      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"
     end
   end
 end
lib/saml/kit/signature.rb
@@ -1,6 +1,8 @@
 module Saml
   module Kit
     class Signature
+      include ActiveModel::Validations
+
       def initialize(xml_hash)
         @xml_hash = xml_hash
       end
lib/saml/kit/version.rb
@@ -1,5 +1,5 @@
 module Saml
   module Kit
-    VERSION = "1.0.4"
+    VERSION = "1.0.5"
   end
 end
spec/saml/response_spec.rb
@@ -419,15 +419,16 @@ RSpec.describe Saml::Kit::Response do
     let(:now) { Time.now.utc }
     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
-      FFaker::Movie.title
       <<-XML
-<Assertion xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="#{id}" IssueInstant="2017-11-23T04:33:58Z" Version="2.0">
+<Assertion xmlns="#{Saml::Kit::Namespaces::ASSERTION}" ID="#{id}" IssueInstant="2017-11-23T04:33:58Z" Version="2.0">
  <Issuer>#{FFaker::Internet.uri("https")}</Issuer>
  <Subject>
-   <NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress">fdddf7ad-c4a4-443c-b96d-c953913b7b4e</NameID>
-   <SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
-     <SubjectConfirmationData InResponseTo="cc8c4131-9336-4d1a-82f2-4ad92abeee22" NotOnOrAfter="2017-11-23T07:33:58Z" Recipient="https://westyundt.ca/acs"/>
+   <NameID Format="#{Saml::Kit::Namespaces::PERSISTENT}">#{SecureRandom.uuid}</NameID>
+   <SubjectConfirmation Method="#{Saml::Kit::Namespaces::BEARER}">
+     <SubjectConfirmationData InResponseTo="#{SecureRandom.uuid}" NotOnOrAfter="2017-11-23T07:33:58Z" Recipient="https://westyundt.ca/acs"/>
    </SubjectConfirmation>
  </Subject>
  <Conditions NotBefore="2017-11-23T04:33:58Z" NotOnOrAfter="2017-11-23T07:33:58Z">
@@ -437,15 +438,15 @@ RSpec.describe Saml::Kit::Response do
  </Conditions>
  <AuthnStatement AuthnInstant="2017-11-23T04:33:58Z" SessionIndex="_11d39a7f-1b86-43ed-90d7-68090a857ca8" SessionNotOnOrAfter="2017-11-23T07:33:58Z">
    <AuthnContext>
-     <AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:Password</AuthnContextClassRef>
+     <AuthnContextClassRef>#{Saml::Kit::Namespaces::PASSWORD}</AuthnContextClassRef>
    </AuthnContext>
  </AuthnStatement>
  <AttributeStatement>
-   <Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="email">
-     <AttributeValue>sidney_bayer@nienowemmerich.com</AttributeValue>
+   <Attribute Name="email" NameFormat="#{Saml::Kit::Namespaces::URI}">
+     <AttributeValue>#{email}</AttributeValue>
    </Attribute>
-   <Attribute Name="created_at" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri" FriendlyName="created_at">
-     <AttributeValue>2017-11-23T04:33:58Z</AttributeValue>
+   <Attribute Name="created_at" NameFormat="#{Saml::Kit::Namespaces::URI}">
+     <AttributeValue>#{created_at.iso8601}</AttributeValue>
    </Attribute>
  </AttributeStatement>
 </Assertion>
@@ -492,8 +493,8 @@ XML
 
       subject = described_class.new(xml)
       expect(subject.attributes).to match_array([
-        ["created_at", "2017-11-23T04:33:58Z"],
-        ["email", "sidney_bayer@nienowemmerich.com"]
+        ["created_at", created_at.iso8601],
+        ["email", email]
       ])
     end
   end
spec/saml/signature_spec.rb
@@ -0,0 +1,22 @@
+RSpec.describe Saml::Kit::Signature do
+  describe "#valid?" do
+    let(:key_pair) { ::Xml::Kit::KeyPair.generate(use: :signing) }
+
+    it 'returns true when the signature is valid' do
+      signed_document = Saml::Kit::AuthenticationRequest.build do |x|
+        x.sign_with(key_pair)
+      end
+      subject = described_class.new(Hash.from_xml(signed_document.to_xml))
+      expect(subject).to be_valid
+    end
+
+    xit 'is invalid when the xml has been tampered' do
+      signed_document = Saml::Kit::AuthenticationRequest.build do |x|
+        x.sign_with(key_pair)
+      end
+      tampered_xml = signed_document.to_xml.gsub("Issuer", "Hacked")
+      subject = described_class.new(Hash.from_xml(tampered_xml))
+      expect(subject).to_not be_valid
+    end
+  end
+end