diff --git a/README.rst b/README.rst
index 7315991a..af8ccc73 100644
--- a/README.rst
+++ b/README.rst
@@ -125,12 +125,15 @@ of the public certificate originally obtained from OneLogin::
def do_POST(self):
...
+ request_data = self.prepare_request()
length = int(self.headers['Content-Length'])
data = self.rfile.read(length)
query = urlparse.parse_qs(data)
res = Response(
+ request_data,
query['SAMLResponse'].pop(),
self.settings['idp_cert_fingerprint'],
+ issuer=self.settings['issuer']
)
valid = res.is_valid()
name_id = res.name_id
@@ -145,6 +148,10 @@ of the public certificate originally obtained from OneLogin::
)
self._serve_msg(401, msg)
+The request_data must be used to build the Response due is_valid method checks Destination, Recipient, etc
+and need to know info like SERVER_NAME, SERVER_PORT, PATH_INFO, SCRIPT_NAME, REQUEST_URI. If you using a
+python framework be sure to build a dict with those indexs and provide it to the Response constructor
+
Once again, the self.settings variable is populated from an entry in
the configuration file. You can find the public certificate under Security->SAML
after you login to OneLogin.
diff --git a/onelogin/saml/Response.py b/onelogin/saml/Response.py
index 1cbba110..45759655 100644
--- a/onelogin/saml/Response.py
+++ b/onelogin/saml/Response.py
@@ -174,8 +174,6 @@ def is_valid(self, _clock=None, _verifier=None):
if not self.validate_num_assertions():
raise ResponseFormatError('Only 1 Assertion in the SAMLResponse is supported')
-
-
if _clock is None:
_clock = datetime.utcnow
if _verifier is None:
@@ -189,10 +187,10 @@ def is_valid(self, _clock=None, _verifier=None):
now = _clock()
for condition in conditions:
-
+
not_before = condition.attrib.get('NotBefore', None)
not_on_or_after = condition.attrib.get('NotOnOrAfter', None)
-
+
if not_before is None:
not_before = (now - timedelta(0, 5, 0)).strftime('%Y-%m-%dT%H:%M:%SZ')
if not_on_or_after is None:
@@ -256,7 +254,6 @@ def is_valid(self, _clock=None, _verifier=None):
if not any_subject_confirmation:
raise ResponseSubjectConfirmationError('A valid SubjectConfirmation was not found on this Response')
-
return _verifier(
self._document,
self._signature,
diff --git a/onelogin/saml/test/TestAuthRequest.py b/onelogin/saml/test/TestAuthRequest.py
index e9837905..0da8a0cb 100644
--- a/onelogin/saml/test/TestAuthRequest.py
+++ b/onelogin/saml/test/TestAuthRequest.py
@@ -5,6 +5,7 @@
from onelogin.saml import AuthRequest
+
class TestAuthRequest(object):
def setUp(self):
fudge.clear_expectations()
@@ -23,7 +24,6 @@ def fake_clock():
fake_zlib = fudge.Fake('zlib')
fake_zlib.remember_order()
fake_compress = fake_zlib.expects('compress')
- uncompressed_req = """foo_issuerurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport"""
fake_compress.returns('HDfoo_compressedCHCK')
fake_base64 = fudge.Fake('base64')
@@ -37,7 +37,7 @@ def fake_clock():
fake_urlencode = fake_urllib.expects('urlencode')
fake_urlencode.with_args(
[('SAMLRequest', 'foo_encoded')],
- )
+ )
fake_urlencode.returns('foo_urlencoded')
req = AuthRequest.create(
@@ -52,6 +52,6 @@ def fake_clock():
+ 'emailAddress'
),
idp_sso_target_url='http://foo.idp.bar',
- )
+ )
eq(req, 'http://foo.idp.bar?foo_urlencoded')
diff --git a/onelogin/saml/test/TestResponse.py b/onelogin/saml/test/TestResponse.py
index a1db2015..7a4db955 100644
--- a/onelogin/saml/test/TestResponse.py
+++ b/onelogin/saml/test/TestResponse.py
@@ -11,7 +11,7 @@
ResponseValidationError,
ResponseNameIDError,
ResponseConditionError,
- )
+)
test_response = """
"""
+
class TestResponse(object):
+
def setUp(self):
fudge.clear_expectations()
@@ -89,12 +91,18 @@ def test__init__(self):
from_string.with_args('foo decoded response', parser=fake_xmlparser)
from_string.returns('foo document')
+ request_data = {
+ 'http_host': 'example.com',
+ 'script_name': 'index.html'
+ }
+
res = Response(
+ request_data=request_data,
response='foo response',
signature='foo signature',
_base64=fake_base64,
_etree=fake_etree,
- )
+ )
eq(res._document, 'foo document')
eq(res._signature, 'foo signature')
@@ -105,7 +113,7 @@ def test_get_name_id_simple(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
name_id = res.name_id
eq('3f7b3dcf-1674-4ecd-92c8-1544f346baf8', name_id)
@@ -173,18 +181,16 @@ def test_get_name_id_multiple(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
msg = assert_raises(
ResponseNameIDError,
res._get_name_id,
- )
+ )
eq(
- str(msg),
- ('There was a problem getting the name ID: Found more than one '
- + 'name ID'
- ),
- )
+ str(msg), ('There was a problem getting the name ID:' +
+ ' Found more than one name ID'),
+ )
@fudge.with_fakes
def test_get_name_id_none(self):
@@ -241,18 +247,18 @@ def test_get_name_id_none(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
msg = assert_raises(
ResponseNameIDError,
res._get_name_id,
- )
+ )
eq(
str(msg),
('There was a problem getting the name ID: Did not find a name '
+ 'ID'
),
- )
+ )
@fudge.with_fakes
def test_is_valid_not_before_missing(self):
@@ -312,12 +318,12 @@ def test_is_valid_not_before_missing(self):
res = Response(
response=encoded_response,
signature='foo signature',
- )
+ )
fake_verifier = fudge.Fake(
'verifier',
callable=True,
- )
+ )
fake_verifier.times_called(1)
fake_verifier.with_args(res._document, 'foo signature')
@@ -325,7 +331,7 @@ def test_is_valid_not_before_missing(self):
msg = res.is_valid(
_verifier=fake_verifier,
- )
+ )
eq(msg, True)
@@ -387,17 +393,17 @@ def test_is_valid_not_on_or_after_missing(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
msg = assert_raises(
ResponseConditionError,
res.is_valid,
- )
+ )
- eq(str(msg),
- ('There was a problem validating a condition: Did not find '
- + 'NotOnOrAfter condition'
- ),
- )
+ eq(
+ str(msg),
+ ('There was a problem validating a condition:' +
+ ' Did not find NotOnOrAfter condition'),
+ )
@fudge.with_fakes
def test_is_valid_current_time_earlier(self):
@@ -405,7 +411,7 @@ def test_is_valid_current_time_earlier(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
def fake_clock():
return datetime(2004, 12, 05, 9, 16, 45, 462796)
@@ -413,13 +419,13 @@ def fake_clock():
ResponseValidationError,
res.is_valid,
_clock=fake_clock,
- )
+ )
- eq(str(msg),
- ('There was a problem validating the response: Current time is '
- + 'earlier than NotBefore condition'
- ),
- )
+ eq(
+ str(msg),
+ ('There was a problem validating the response: Current time is ' +
+ 'earlier than NotBefore condition'),
+ )
@fudge.with_fakes
def test_is_valid_current_time_on_or_after(self):
@@ -427,7 +433,7 @@ def test_is_valid_current_time_on_or_after(self):
res = Response(
response=encoded_response,
signature=None,
- )
+ )
def fake_clock():
return datetime(2004, 12, 05, 9, 30, 45, 462796)
@@ -435,13 +441,13 @@ def fake_clock():
ResponseValidationError,
res.is_valid,
_clock=fake_clock,
- )
+ )
- eq(str(msg),
- ('There was a problem validating the response: Current time is '
- + 'on or after NotOnOrAfter condition'
- ),
- )
+ eq(
+ str(msg),
+ ('There was a problem validating the response: Current time is ' +
+ 'on or after NotOnOrAfter condition'),
+ )
@fudge.with_fakes
def test_is_valid_simple(self):
@@ -449,7 +455,7 @@ def test_is_valid_simple(self):
res = Response(
response=encoded_response,
signature='foo signature',
- )
+ )
def fake_clock():
return datetime(2004, 12, 05, 9, 18, 45, 462796)
@@ -457,7 +463,7 @@ def fake_clock():
fake_verifier = fudge.Fake(
'verifier',
callable=True,
- )
+ )
fake_verifier.times_called(1)
fake_verifier.with_args(res._document, 'foo signature')
@@ -466,6 +472,6 @@ def fake_clock():
msg = res.is_valid(
_clock=fake_clock,
_verifier=fake_verifier,
- )
+ )
eq(msg, True)
diff --git a/onelogin/saml/test/TestSignatureVerifier.py b/onelogin/saml/test/TestSignatureVerifier.py
index 6c6cd46a..95780b8c 100644
--- a/onelogin/saml/test/TestSignatureVerifier.py
+++ b/onelogin/saml/test/TestSignatureVerifier.py
@@ -8,6 +8,7 @@
from onelogin.saml.test.util import assert_raises
+
class TestSignatureVerifier(object):
def setUp(self):
fudge.clear_expectations()
@@ -26,7 +27,7 @@ def test_verify_simple(self):
fake_tempfile.remember_order()
named_xmlfile = fake_tempfile.expects(
'NamedTemporaryFile'
- )
+ )
named_xmlfile.with_args(delete=False)
xmlfile = named_xmlfile.returns_fake()
xmlfile.remember_order()
@@ -41,13 +42,13 @@ def test_verify_simple(self):
seek.with_args(0)
exit = xmlfile.expects('__exit__')
- exit.with_args(None, None,None)
+ exit.with_args(None, None, None)
xmlfile.has_attr(name='xmlfile')
named_certfile = fake_tempfile.next_call(
'NamedTemporaryFile'
- )
+ )
named_certfile.with_args(delete=False)
certfile = named_certfile.returns_fake()
certfile.remember_order()
@@ -61,16 +62,15 @@ def test_verify_simple(self):
('-----BEGIN CERTIFICATE-----\nfoo signature\n'
+ '-----END CERTIFICATE-----'
)
- )
+ )
seek = certfile.expects('seek')
seek.with_args(0)
exit = certfile.expects('__exit__')
- exit.with_args(None, None,None)
+ exit.with_args(None, None, None)
certfile.has_attr(name='certfile')
-
fake_subprocess = fudge.Fake('subprocess')
fake_subprocess.remember_order()
popen = fake_subprocess.expects('Popen')
@@ -84,10 +84,10 @@ def test_verify_simple(self):
'--id-attr:ID',
'urn:oasis:names:tc:SAML:2.0:assertion:Assertion',
'xmlfile',
- ],
+ ],
stderr=1,
stdout=1,
- )
+ )
proc = popen.returns_fake()
proc.remember_order()
wait = proc.expects('wait')
@@ -109,7 +109,7 @@ def test_verify_simple(self):
_tempfile=fake_tempfile,
_subprocess=fake_subprocess,
_os=fake_os,
- )
+ )
@fudge.with_fakes
def test_get_xmlsec_bin_default(self):
@@ -183,13 +183,13 @@ def test_get_parse_stderr_error(self):
SignatureVerifier.SignatureVerifierError,
SignatureVerifier._parse_stderr,
fake_proc
- )
+ )
- eq(str(msg),
- ('There was a problem validating the response: XMLSec returned error '
- + 'code 1. Please check your certficate.'
- ),
- )
+ eq(
+ str(msg),
+ ('There was a problem validating the response: XMLSec returned error ' +
+ 'code 1. Please check your certficate.'),
+ )
@fudge.with_fakes
def test_get_parse_stderr_error_should_not_happen(self):
@@ -203,13 +203,13 @@ def test_get_parse_stderr_error_should_not_happen(self):
SignatureVerifier.SignatureVerifierError,
SignatureVerifier._parse_stderr,
fake_proc
- )
+ )
- eq(str(msg),
- ('There was a problem validating the response: XMLSec exited with '
- + 'code 0 but did not return OK when verifying the SAML response.'
- )
- )
+ eq(
+ str(msg),
+ ('There was a problem validating the response: XMLSec exited with ' +
+ 'code 0 but did not return OK when verifying the SAML response.')
+ )
@fudge.with_fakes
def test_get_parse_stderr_ok_windows(self):
diff --git a/onelogin/saml/test/util.py b/onelogin/saml/test/util.py
index f693d408..b02ea084 100644
--- a/onelogin/saml/test/util.py
+++ b/onelogin/saml/test/util.py
@@ -7,6 +7,8 @@ def assert_raises(excClass, callableObj, *args, **kwargs):
except excClass, e:
return e
else:
- if hasattr(excClass,'__name__'): excName = excClass.__name__
- else: excName = str(excClass)
+ if hasattr(excClass, '__name__'):
+ excName = excClass.__name__
+ else:
+ excName = str(excClass)
raise AssertionError("%s not raised" % excName)