refactored
This commit is contained in:
@@ -19,8 +19,8 @@
|
|||||||
or attribute authority (AA) may use to conclude its tasks.
|
or attribute authority (AA) may use to conclude its tasks.
|
||||||
"""
|
"""
|
||||||
from saml2 import saml, samlp
|
from saml2 import saml, samlp
|
||||||
from saml2.utils import sid, decode_base64_and_inflate
|
from saml2.utils import sid, decode_base64_and_inflate, make_instance
|
||||||
from saml2.time_util import instant
|
from saml2.time_util import instant, in_a_while
|
||||||
from saml2.metadata import MetaData
|
from saml2.metadata import MetaData
|
||||||
|
|
||||||
class VersionMismatch(Exception):
|
class VersionMismatch(Exception):
|
||||||
@@ -44,9 +44,21 @@ EXCEPTION2STATUS = {
|
|||||||
|
|
||||||
def properties(klass):
|
def properties(klass):
|
||||||
props = [val[0] for key,val in klass.c_children.items()]
|
props = [val[0] for key,val in klass.c_children.items()]
|
||||||
props.extend(klass.c_attributes)
|
props.extend(klass.c_attributes.values())
|
||||||
return props
|
return props
|
||||||
|
|
||||||
|
def klassdict(klass, text=None, **kwargs):
|
||||||
|
spec = {}
|
||||||
|
if text:
|
||||||
|
spec["text"] = text
|
||||||
|
props = properties(klass)
|
||||||
|
#print props
|
||||||
|
for key, val in kwargs.items():
|
||||||
|
#print "?",key
|
||||||
|
if key in props:
|
||||||
|
spec[key] = val
|
||||||
|
return spec
|
||||||
|
|
||||||
class Server(object):
|
class Server(object):
|
||||||
def __init__(self, config, log=None):
|
def __init__(self, config, log=None):
|
||||||
if config:
|
if config:
|
||||||
@@ -84,131 +96,81 @@ class Server(object):
|
|||||||
print "Configuration: %s" % (self.conf,)
|
print "Configuration: %s" % (self.conf,)
|
||||||
|
|
||||||
def issuer(self):
|
def issuer(self):
|
||||||
return {
|
return klassdict( saml.Issuer, self.conf["entityid"],
|
||||||
"format": saml.NAMEID_FORMAT_ENTITY,
|
format=saml.NAMEID_FORMAT_ENTITY)
|
||||||
"text": self.conf["entityid"]
|
|
||||||
}
|
|
||||||
|
|
||||||
def status_from_exception(self, exception):
|
def status_from_exception(self, exception):
|
||||||
return {
|
return klassdict(samlp.Status,
|
||||||
"status_code": {
|
status_code=klassdict(samlp.StatusCode,
|
||||||
"value": samlp.STATUS_RESPONDER,
|
value=samlp.STATUS_RESPONDER,
|
||||||
"status_code": {
|
status_code=klassdict(samlp.StatusCode,
|
||||||
"value": EXCEPTION2STATUS[exception.__class__],
|
value=EXCEPTION2STATUS[exception.__class__])
|
||||||
},
|
),
|
||||||
},
|
status_message=exception.args[0],
|
||||||
"status_message": exception.args[0],
|
)
|
||||||
}
|
|
||||||
|
|
||||||
def status(self, status, message=None, status_code=None):
|
def status_message(self, text="", **kwargs):
|
||||||
res = {
|
return klassdict(samlp.StatusMessage, text, **kwargs)
|
||||||
"status_code": {
|
|
||||||
"value": status,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if message:
|
|
||||||
res["status_message"] = message
|
|
||||||
if status_code:
|
|
||||||
res["status_code"].update(status_code)
|
|
||||||
return res
|
|
||||||
|
|
||||||
def audience_restriction(self, audience):
|
|
||||||
return { "audience": audience }
|
|
||||||
|
|
||||||
def conditions(self, not_before=None, not_on_or_after=None,
|
def status_code(self, text="", **kwargs):
|
||||||
audience_restriction=None, condition=None,
|
return klassdict(samlp.StatusCode, text, **kwargs)
|
||||||
one_time_use=None, proxy_restriction=None):
|
|
||||||
|
def status(self, text="", **kwargs):
|
||||||
res = {}
|
return klassdict(samlp.Status, text, **kwargs)
|
||||||
if not_before:
|
|
||||||
res["not_before"] = not_before
|
|
||||||
if not_on_or_after:
|
|
||||||
res["not_on_or_after"] = not_on_or_after
|
|
||||||
if audience_restriction:
|
|
||||||
res["audience_restriction"] = audience_restriction
|
|
||||||
# The ones below are hardly used
|
|
||||||
if condition:
|
|
||||||
res["condition"] = condition
|
|
||||||
if one_time_use:
|
|
||||||
res["one_time_use"] = one_time_use
|
|
||||||
if proxy_restriction:
|
|
||||||
res["proxy_restriction"] = proxy_restriction
|
|
||||||
|
|
||||||
return res
|
def success_status(self):
|
||||||
|
return self.status(status_code=self.status_code(
|
||||||
|
value=samlp.STATUS_SUCCESS))
|
||||||
|
|
||||||
|
def audience(self, text="", **kwargs):
|
||||||
|
return klassdict(saml.Audience, text, **kwargs)
|
||||||
|
|
||||||
|
def audience_restriction(self, text="", **kwargs):
|
||||||
|
return klassdict(saml.AudienceRestriction, text, **kwargs)
|
||||||
|
|
||||||
|
def conditions(self, text="", **kwargs):
|
||||||
|
return klassdict(saml.Conditions, text, **kwargs)
|
||||||
|
|
||||||
def attribute(self, value="", name="", name_format="", friendly_name=""):
|
def attribute(self, text="", **kwargs):
|
||||||
dic = {}
|
return klassdict(saml.Attribute, text, **kwargs)
|
||||||
if value:
|
|
||||||
dic["attribute_value"] = value
|
def attribute_value(self, text="", **kwargs):
|
||||||
if name:
|
return klassdict(saml.AttributeValue, text, **kwargs)
|
||||||
dic["name"] = name
|
|
||||||
if name_format:
|
def attribute_statement(self, text="", **kwargs):
|
||||||
dic["name_format"] = name_format
|
return klassdict(saml.AttributeStatement, text, **kwargs)
|
||||||
if friendly_name:
|
|
||||||
dic["friendly_name"] = friendly_name
|
|
||||||
return dic
|
|
||||||
|
|
||||||
def attribute_statement(self, attribute):
|
|
||||||
return { "attribute": attribute }
|
|
||||||
|
|
||||||
def subject(self, name, name_id, subject_confirmation=None):
|
def subject_confirmation_data(self, text="", **kwargs):
|
||||||
spec = {
|
return klassdict(saml.SubjectConfirmationData, text, **kwargs)
|
||||||
"text": name,
|
|
||||||
"name_id": name_id,
|
|
||||||
}
|
|
||||||
if subject_confirmation:
|
|
||||||
spec["subject_confirmation"] = subject_confirmation
|
|
||||||
return spec
|
|
||||||
|
|
||||||
def assertion(self, subject, signature=False,
|
def subject_confirmation(self, text="", **kwargs):
|
||||||
conditions=None, advice=None, statement=None,
|
return klassdict(saml.SubjectConfirmation, text, **kwargs)
|
||||||
authn_statement=None, authz_desc_statement=None,
|
|
||||||
attribute_statement=None):
|
|
||||||
|
|
||||||
spec = {
|
|
||||||
"version": "2.0",
|
|
||||||
"id" : sid(),
|
|
||||||
"issue_instant" : instant(),
|
|
||||||
"issuer": self.issuer(),
|
|
||||||
"subject": subject,
|
|
||||||
}
|
|
||||||
|
|
||||||
if signature:
|
def subject(self, text="", **kwargs):
|
||||||
spec["signature"] = sigver.pre_signature_part(spec["id"])
|
return klassdict(saml.Subject, text, **kwargs)
|
||||||
if conditions:
|
|
||||||
spec["conditions"] = conditions
|
|
||||||
if advice:
|
|
||||||
spec["advice"] = advice
|
|
||||||
if statement:
|
|
||||||
spec["statement"] = statement
|
|
||||||
if authn_statement:
|
|
||||||
spec["authn_statement"] = authn_statement
|
|
||||||
if authz_desc_statement:
|
|
||||||
spec["authz_desc_statement"] = authz_desc_statement
|
|
||||||
if attribute_statement:
|
|
||||||
spec["attribute_statement"] = attribute_statement
|
|
||||||
|
|
||||||
return spec
|
|
||||||
|
|
||||||
def response(self, in_response_to, destination, status,
|
|
||||||
consent=None, signature=False, assertion=None,
|
|
||||||
encrypt=False):
|
|
||||||
|
|
||||||
spec = {
|
def authn_statement(self, text="", **kwargs):
|
||||||
|
return klassdict(saml.Subject, text, **kwargs)
|
||||||
|
|
||||||
|
def assertion(self, text="", **kwargs):
|
||||||
|
kwargs.update({
|
||||||
|
"version": "2.0",
|
||||||
|
"id" : sid(),
|
||||||
|
"issue_instant" : instant(),
|
||||||
|
})
|
||||||
|
return klassdict(saml.Assertion, text, **kwargs)
|
||||||
|
|
||||||
|
def response(self, signature=False, encrypt=False, **kwargs):
|
||||||
|
|
||||||
|
kwargs.update({
|
||||||
"id" : sid(),
|
"id" : sid(),
|
||||||
"in_response_to": in_response_to,
|
|
||||||
"version": "2.0",
|
"version": "2.0",
|
||||||
"issue_instant" : instant(),
|
"issue_instant" : instant(),
|
||||||
"issuer": self.issuer(),
|
})
|
||||||
"destination": destination,
|
|
||||||
"status": status,
|
|
||||||
}
|
|
||||||
if signature:
|
if signature:
|
||||||
spec["signature"] = sigver.pre_signature_part(spec["id"])
|
kwargs["signature"] = sigver.pre_signature_part(kwargs["id"])
|
||||||
if assertion:
|
|
||||||
spec["assertion"] = assertion
|
|
||||||
|
|
||||||
return spec
|
return kwargs
|
||||||
|
|
||||||
def parse_request(self, enc_request):
|
def parse_request(self, enc_request):
|
||||||
request_xml = decode_base64_and_inflate(enc_request)
|
request_xml = decode_base64_and_inflate(enc_request)
|
||||||
@@ -225,12 +187,17 @@ class Server(object):
|
|||||||
try:
|
try:
|
||||||
consumer_url = self.metadata.consumer_url(spentityid)
|
consumer_url = self.metadata.consumer_url(spentityid)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
self.log and self.log.info(
|
||||||
|
"entities: %s" % self.metadata.entity.keys())
|
||||||
raise UnknownPricipal(spentityid)
|
raise UnknownPricipal(spentityid)
|
||||||
if not consumer_url: # what to do ?
|
if not consumer_url: # what to do ?
|
||||||
raise UnsupportedBinding(spentityid)
|
raise UnsupportedBinding(spentityid)
|
||||||
|
|
||||||
if consumer_url != return_destination:
|
if consumer_url != return_destination:
|
||||||
# serious error on someones behalf
|
# serious error on someones behalf
|
||||||
|
self.log and self.log.info("%s != %s" % (consumer_url,
|
||||||
|
return_destination))
|
||||||
|
print "%s != %s" % (consumer_url, return_destination)
|
||||||
raise OtherError("ConsumerURL and return destination mismatch")
|
raise OtherError("ConsumerURL and return destination mismatch")
|
||||||
|
|
||||||
policy = request.name_id_policy
|
policy = request.name_id_policy
|
||||||
@@ -238,5 +205,68 @@ class Server(object):
|
|||||||
policy.format == saml.NAMEID_FORMAT_TRANSIENT:
|
policy.format == saml.NAMEID_FORMAT_TRANSIENT:
|
||||||
name_id_policies = policy.format
|
name_id_policies = policy.format
|
||||||
|
|
||||||
return (consumer_url, id, name_id_policies)
|
return (consumer_url, id, name_id_policies, spentityid)
|
||||||
|
|
||||||
|
def do_attribute_statement(self, identity):
|
||||||
|
"""
|
||||||
|
:param identity: A dictionary with fiendly names as keys
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
|
attrs = []
|
||||||
|
for key, val in identity.items():
|
||||||
|
dic = {}
|
||||||
|
if isinstance(val,basestring):
|
||||||
|
attrval = self.attribute_value(val)
|
||||||
|
elif isinstance(val,list):
|
||||||
|
attrval = [self.attribute_value(v) for v in val]
|
||||||
|
else:
|
||||||
|
raise OtherError("strange value type on: %s" % val)
|
||||||
|
dic["attribute_value"] = attrval
|
||||||
|
if isinstance(key, basestring):
|
||||||
|
dic["name"] = key
|
||||||
|
elif isinstance(key, tuple): # 3-tuple
|
||||||
|
(name,format,friendly) = key
|
||||||
|
if name:
|
||||||
|
dic["name"] = name
|
||||||
|
if format:
|
||||||
|
dic["name_format"] = format
|
||||||
|
if friendly:
|
||||||
|
dic["friendly_name"] = friendly
|
||||||
|
attrs.append(self.attribute(**dic))
|
||||||
|
|
||||||
|
return self.attribute_statement(attribute=attrs)
|
||||||
|
|
||||||
|
def do_sso_response(self, consumer_url, in_response_to,
|
||||||
|
sp_entity_id, identity, name_id_policies=None,
|
||||||
|
subject_id=None ):
|
||||||
|
|
||||||
|
attribute_statement = self.do_attribute_statement(identity)
|
||||||
|
|
||||||
|
# start using now and for a hour
|
||||||
|
conditions = self.conditions(
|
||||||
|
not_before=instant(),
|
||||||
|
# an hour from now
|
||||||
|
not_on_or_after=in_a_while(0,0,0,0,0,1),
|
||||||
|
audience_restriction=self.audience_restriction(
|
||||||
|
audience=self.audience(sp_entity_id)))
|
||||||
|
# temporary identifier or ??
|
||||||
|
subject_id = sid()
|
||||||
|
tmp = self.response(
|
||||||
|
in_response_to=in_response_to,
|
||||||
|
destination=consumer_url,
|
||||||
|
status=self.success_status(),
|
||||||
|
assertion=self.assertion(
|
||||||
|
subject = self.subject(subject_id,
|
||||||
|
name_id=saml.NAMEID_FORMAT_TRANSIENT,
|
||||||
|
method=saml.SUBJECT_CONFIRMATION_METHOD_BEARER,
|
||||||
|
subject_confirmation=self.subject_confirmation(
|
||||||
|
subject_confirmation_data=self.subject_confirmation_data(
|
||||||
|
in_response_to=in_response_to))),
|
||||||
|
attribute_statement = attribute_statement,
|
||||||
|
authn_statement= self.authn_statement(
|
||||||
|
authn_instant=instant(),
|
||||||
|
session_index=sid()),
|
||||||
|
conditions=conditions,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
return make_instance(samlp.Response, tmp)
|
||||||
|
|||||||
Reference in New Issue
Block a user