refactored

This commit is contained in:
Roland Hedberg
2009-11-06 19:40:57 +01:00
parent 64be8427a4
commit c571ece8a9

View File

@@ -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)