Handle different problems pointed out by Seth Arnold.

This commit is contained in:
Roland Hedberg
2015-03-01 10:30:03 -08:00
parent 7f4e595b2c
commit 0f34abb58e
4 changed files with 75 additions and 49 deletions

View File

@@ -20,6 +20,7 @@ from saml2 import BINDING_HTTP_REDIRECT
from saml2 import BINDING_HTTP_POST
from saml2 import server
from saml2 import time_util
from saml2.authn import is_equal
from saml2.authn_context import AuthnBroker
from saml2.authn_context import PASSWORD
@@ -131,20 +132,20 @@ class Service(object):
else:
# saml_msg may also contain Signature and SigAlg
if "Signature" in saml_msg:
args = {"signature": saml_msg["signature"],
kwargs = {"signature": saml_msg["signature"],
"sigalg": saml_msg["SigAlg"]}
else:
args = {}
kwargs = {}
try:
_encrypt_cert = encrypt_cert_from_item(
saml_msg["req_info"].message)
return self.do(saml_msg["SAMLRequest"], binding,
saml_msg["RelayState"],
encrypt_cert=_encrypt_cert, **args)
encrypt_cert=_encrypt_cert, **kwargs)
except KeyError:
# Can live with no relay state # TODO or can we, for inacademia?
return self.do(saml_msg["SAMLRequest"], binding,
saml_msg["RelayState"], **args)
saml_msg["RelayState"], **kwargs)
def artifact_operation(self, saml_msg):
if not saml_msg:
@@ -454,10 +455,9 @@ class SSO(Service):
except TypeError:
resp = Unauthorized()
else:
logger.debug("Authz_info: %s" % _info)
try:
(user, passwd) = _info.split(":")
if PASSWD[user] != passwd:
if is_equal(PASSWD[user], passwd):
resp = Unauthorized()
self.user = user
self.environ[
@@ -931,12 +931,16 @@ def metadata(environ, start_response):
def staticfile(environ, start_response):
try:
path = args.path
path = args.path[:]
if path is None or len(path) == 0:
path = os.path.dirname(os.path.abspath(__file__))
if path[-1] != "/":
path += "/"
path += environ.get('PATH_INFO', '').lstrip('/')
path = os.path.realpath(path)
if not path.startswith(args.path):
resp = Unauthorized()
return resp(environ, start_response)
start_response('200 OK', [('Content-Type', "text/xml")])
return open(path, 'r').read()
except Exception as ex:

View File

@@ -10,6 +10,7 @@ from hashlib import sha1
from urlparse import parse_qs
from Cookie import SimpleCookie
import os
from saml2.authn import is_equal
from saml2.profile import ecp
from saml2 import server
@@ -73,12 +74,14 @@ def get_eptid(idp, req_info, session):
req_info.sender(), session["permanent_id"],
session["authn_auth"])
# -----------------------------------------------------------------------------
def dict2list_of_tuples(d):
return [(k, v) for k, v in d.items()]
# -----------------------------------------------------------------------------
@@ -292,7 +295,7 @@ class SSO(Service):
if not _resp:
identity = USERS[self.user].copy()
#identity["eduPersonTargetedID"] = get_eptid(IDP, query, session)
# identity["eduPersonTargetedID"] = get_eptid(IDP, query, session)
logger.info("Identity: %s" % (identity,))
if REPOZE_ID_EQUIVALENT:
@@ -357,7 +360,8 @@ class SSO(Service):
_req = self.req_info.message
if "SigAlg" in saml_msg and "Signature" in saml_msg: # Signed request
if "SigAlg" in saml_msg and "Signature" in saml_msg: # Signed
# request
issuer = _req.issuer.text
_certs = IDP.metadata.certs(issuer, "any", "signing")
verified_ok = False
@@ -405,7 +409,7 @@ class SSO(Service):
return self.not_authn(key, _req.requested_authn_context)
# def artifact(self):
# # Can be either by HTTP_Redirect or HTTP_POST
# # Can be either by HTTP_Redirect or HTTP_POST
# _req = self._store_request(self.unpack_either())
# if isinstance(_req, basestring):
# return self.not_authn(_req)
@@ -424,10 +428,9 @@ class SSO(Service):
except TypeError:
resp = Unauthorized()
else:
logger.debug("Authz_info: %s" % _info)
try:
(user, passwd) = _info.split(":")
if PASSWD[user] != passwd:
if is_equal(PASSWD[user], passwd):
resp = Unauthorized()
self.user = user
self.environ[
@@ -449,6 +452,7 @@ class SSO(Service):
self.op_type = "ecp"
return self.operation(_dict, BINDING_SOAP)
# -----------------------------------------------------------------------------
# === Authentication ====
# -----------------------------------------------------------------------------
@@ -474,11 +478,11 @@ def do_authentication(environ, start_response, authn_context, key,
# -----------------------------------------------------------------------------
PASSWD = {
"daev0001": "qwerty",
"haho0032": "qwerty",
"roland": "dianakra",
"babs": "howes",
"upper": "crust"}
"daev0001": "qwerty",
"haho0032": "qwerty",
"roland": "dianakra",
"babs": "howes",
"upper": "crust"}
def username_password_authn(environ, start_response, reference, key,
@@ -552,7 +556,7 @@ def not_found(environ, start_response):
# === Single log out ===
# -----------------------------------------------------------------------------
#def _subject_sp_info(req_info):
# def _subject_sp_info(req_info):
# # look for the subject
# subject = req_info.subject_id()
# subject = subject.text.strip()
@@ -605,13 +609,13 @@ class SLO(Service):
resp = Response(hinfo["data"], headers=hinfo["headers"])
return resp(self.environ, self.start_response)
# ----------------------------------------------------------------------------
# Manage Name ID service
# ----------------------------------------------------------------------------
class NMI(Service):
def do(self, query, binding, relay_state="", encrypt_cert=None):
logger.info("--- Manage Name ID Service ---")
req = IDP.parse_manage_name_id_request(query, binding)
@@ -633,6 +637,7 @@ class NMI(Service):
resp = Response(hinfo["data"], headers=hinfo["headers"])
return resp(self.environ, self.start_response)
# ----------------------------------------------------------------------------
# === Assertion ID request ===
# ----------------------------------------------------------------------------
@@ -680,6 +685,7 @@ class ARS(Service):
resp = Response(hinfo["data"], headers=hinfo["headers"])
return resp(self.environ, self.start_response)
# ----------------------------------------------------------------------------
# === Authn query service ===
# ----------------------------------------------------------------------------
@@ -734,6 +740,7 @@ class ATTR(Service):
resp = Response(hinfo["data"], headers=hinfo["headers"])
return resp(self.environ, self.start_response)
# ----------------------------------------------------------------------------
# Name ID Mapping service
# When an entity that shares an identifier for a principal with an identity
@@ -862,10 +869,10 @@ def metadata(environ, start_response):
try:
path = args.path
if path is None or len(path) == 0:
path = os.path.dirname(os.path.abspath( __file__ ))
path = os.path.dirname(os.path.abspath(__file__))
if path[-1] != "/":
path += "/"
metadata = create_metadata_string(path+args.config, IDP.config,
metadata = create_metadata_string(path + args.config, IDP.config,
args.valid, args.cert, args.keyfile,
args.id, args.name, args.sign)
start_response('200 OK', [('Content-Type', "text/xml")])
@@ -874,6 +881,7 @@ def metadata(environ, start_response):
logger.error("An error occured while creating metadata:" + ex.message)
return not_found(environ, start_response)
def staticfile(environ, start_response):
try:
path = args.path
@@ -882,12 +890,17 @@ def staticfile(environ, start_response):
if path[-1] != "/":
path += "/"
path += environ.get('PATH_INFO', '').lstrip('/')
path = os.path.realpath(path)
if not path.startswith(args.path):
resp = Unauthorized()
return resp(environ, start_response)
start_response('200 OK', [('Content-Type', "text/xml")])
return open(path, 'r').read()
except Exception as ex:
logger.error("An error occured while creating metadata:" + ex.message)
return not_found(environ, start_response)
def application(environ, start_response):
"""
The main WSGI application. Dispatch the current request to
@@ -924,7 +937,6 @@ def application(environ, start_response):
except KeyError:
user = None
url_patterns = AUTHN_URLS
if not user:
logger.info("-- No USER --")
@@ -956,7 +968,7 @@ def application(environ, start_response):
# by moving some initialization out of __name__ == '__main__' section.
# uwsgi -s 0.0.0.0:8088 --protocol http --callable application --module idp
args = type('Config', (object,), { })
args = type('Config', (object,), {})
args.config = 'idp_conf'
args.mako_root = './'
args.path = None
@@ -984,7 +996,8 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-p', dest='path', help='Path to configuration file.')
parser.add_argument('-v', dest='valid',
help="How long, in days, the metadata is valid from the time of creation")
help="How long, in days, the metadata is valid from "
"the time of creation")
parser.add_argument('-c', dest='cert', help='certificate')
parser.add_argument('-i', dest='id',
help="The ID of the entities descriptor")

View File

@@ -19,6 +19,7 @@ from saml2 import BINDING_SOAP
from saml2 import BINDING_HTTP_REDIRECT
from saml2 import BINDING_HTTP_POST
from saml2 import time_util
from saml2.authn import is_equal
from saml2.authn_context import AuthnBroker
from saml2.authn_context import PASSWORD
@@ -414,7 +415,7 @@ class SSO(Service):
logger.debug("Authz_info: %s" % _info)
try:
(user, passwd) = _info.split(":")
if PASSWD[user] != passwd:
if is_equal(PASSWD[user], passwd):
resp = Unauthorized()
self.user = user
except (ValueError, TypeError):

View File

@@ -39,6 +39,16 @@ class UserAuthnMethod(object):
raise NotImplemented
def is_equal(a, b):
if len(a) != len(b):
return False
result = 0
for x, y in zip(a, b):
result |= x ^ y
return result == 0
def url_encode_params(params=None):
if not isinstance(params, dict):
raise EncodeError("You must pass in a dictionary!")
@@ -137,7 +147,7 @@ class UsernamePasswordMako(UserAuthnMethod):
return resp
def _verify(self, pwd, user):
assert pwd == self.passwd[user]
assert is_equal(pwd, self.passwd[user])
def verify(self, request, **kwargs):
"""
@@ -149,7 +159,7 @@ class UsernamePasswordMako(UserAuthnMethod):
wants the user after authentication.
"""
logger.debug("verify(%s)" % request)
#logger.debug("verify(%s)" % request)
if isinstance(request, basestring):
_dict = parse_qs(request)
elif isinstance(request, dict):
@@ -157,8 +167,6 @@ class UsernamePasswordMako(UserAuthnMethod):
else:
raise ValueError("Wrong type of input")
logger.debug("dict: %s" % _dict)
logger.debug("passwd: %s" % self.passwd)
# verify username and password
try:
self._verify(_dict["password"][0], _dict["login"][0])