Source code for saml.schema.samlp

# -*- coding: utf-8 -*-
from . import types, base, Element, saml


class Base(base.Base):

    class Meta:
        namespace = 'samlp', 'urn:oasis:names:tc:SAML:2.0:protocol'


class _Message(saml._Message, Base):
    """Contains common information found in most SAML/2.0 protocols.
    """

    # A URI reference indicating the address to which this request has
    # been sent.
    destination = base.Attribute(types.String)

    # Indicates whether or not (and under what conditions) consent has
    # been obtained from a principal in the sending of this request.
    consent = base.Attribute(types.String)


class NameIDPolicy(Base):
    """
    Tailors the name identifier in the subjects of assertions
    resulting from an <AuthnRequest>.
    """

    # Specifies the URI reference corresponding to a name identifier format
    # defined in this or another specification.
    format = base.Attribute(types.String)

    # Optionally specifies that the assertion subject's identifier be
    # returned (or created) in the namespace of a service provider
    # other than the requester, or in the namespace of an affiliation
    # group of service providers
    sp_name_qualifier = base.Attribute(types.String, name='SPNameQualifier')

    # A Boolean value used to indicate whether the identity provider is
    # allowed, in the course of fulfilling the request, to create a
    # new identifier to represent the principal.
    allow_create = base.Attribute(types.Boolean)


class RequestedAuthenticationContext(Base):

    class Meta:
        name = 'RequestedAuthnContext'

    # Specifies the comparison method used to evaluate the requested
    # context classes or statements, one of "exact", "minimum",
    # "maximum", or "better". The default is "exact".
    comparison = base.Attribute(types.String)

    # Specifies one or more URI references identifying authentication
    # context classes or declarations.
    reference = Element(saml.AuthenticationContextReference, collection=True)


class Protocol:
    """
    The available URIs that identifies a SAML protocol binding to be used when
    returning the <Response> message.
    """

    _PREFIX = 'urn:oasis:names:tc:SAML:2.0:bindings:'

    SOAP = '%sSOAP' % _PREFIX

    POAS = '%sPAOS' % _PREFIX

    REDIRECT = '%sHTTP-Redirect' % _PREFIX

    POST = '%sHTTP-POST' % _PREFIX

    ARTIFACT = '%sHTTP-Artifact' % _PREFIX

    URI = '%sURI' % _PREFIX


[docs]class AuthenticationRequest(_Message): """ Create a SAML AuthnRequest :: from saml import schema from datetime import datetime document = schema.AuthenticationRequest() document.id = '11111111-2222-3333-4444-555555555555' document.issue_instant = datetime(2000, 1, 1) document.assertion_consumer_service_index = 0 document.attribute_consuming_service_index = 0 document.issuer = 'https://sp.example.com/SAML2' policy = schema.NameIDPolicy() policy.allow_create = True policy.format = schema.NameID.Format.TRANSIENT document.policy = policy print document.tostring() Produces the following XML document: .. code-block:: xml <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="11111111-2222-3333-4444-555555555555" IssueInstant="2000-01-01T00:00:00Z" AssertionConsumerServiceIndex="0" AttributeConsumingServiceIndex="0"> <saml:Issuer>https://sp.example.com/SAML2</saml:Issuer> <samlp:NameIDPolicy Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient" AllowCreate="true"/> </samlp:AuthnRequest> """ class Meta: name = 'AuthnRequest' # A Boolean value. If "true", the identity provider MUST authenticate # the presenter directly rather than rely on a previous security context. force_authn = base.Attribute(types.Boolean) # A Boolean value. If "true", the identity provider and the user agent # itself MUST NOT visibly take control of the user interface from the # requester and interact with the presenter in a noticeable fashion. is_passive = base.Attribute(types.Boolean) # A URI reference that identifies a SAML protocol binding to be used when # returning the <Response> message. protocol = base.Attribute(types.String, name='ProtocolBinding') # Indirectly identifies the location to which the <Response> message # should be returned to the requester. assertion_consumer_service_index = base.Attribute(types.Integer) # Specifies by value the location to which the <Response> message MUST # be returned to the requester. assertion_consumer_service_url = base.Attribute( types.String, name='AssertionConsumerServiceURL') # Indirectly identifies information associated with the requester # describing the SAML attributes the requester desires or requires to be # supplied by the identity provider in the <Response> message. attribute_consuming_service_index = base.Attribute(types.Integer) # Specifies the human-readable name of the requester for use by the # presenter's user agent or the identity provider. provider_name = base.Attribute(types.String) # Specifies the requested subject of the resulting assertion(s). subject = Element(saml.Subject) # Specifies constraints on the name identifier to be used to represent # the requested subject. policy = Element(NameIDPolicy) # Specifies the requirements, if any, that the requester places on # the authentication context that applies to the responding provider's # authentication of the presenter. requested_context = Element(RequestedAuthenticationContext) # Specifies a set of identity providers trusted by the requester to # authenticate the presenter, as well as limitations and context # related to proxying of the <AuthnRequest> message to subsequent identity # providers by the responder. # TODO: scoping = Element(Scoping)
class StatusCode(Base): # URI prefix for the values in this enumeration. _PREFIX = "urn:oasis:names:tc:SAML:2.0:status:" # The request succeeded. SUCCESS = "{}Success".format(_PREFIX) # Failure due to an error on the part of the requester. REQUESTER = "{}Requester".format(_PREFIX) # The version of the request message was incorrect. VERSION_MISMATCH = "{}VersionMismatch".format(_PREFIX) # The provider wasn't able to successfully authenticate the principal. AUTHENTICATION_FAILED = "{}AuthnFailed".format(_PREFIX) # Unexpected or invalid content was encountered. INVALID_ATTRIBUTE_NAME_OR_VALUE = "{}InvalidAttrNameOrValue".format( _PREFIX) # The responding provider cannot support the requested name ID policy. INVALID_NAME_ID_POLICY = "{}InvalidNameIDPolicy".format(_PREFIX) # The authentication context requirements cannot be met. NO_AUTHENTICATION_CONTEXT = "{}NoAuthnContext".format(_PREFIX) # None of the supported identity providers are available. NO_AVAILABLE_IDP = "{}NoAvailableIDP".format(_PREFIX) # The responding provider cannot authenticate the principal passively. NO_PASSIVE = "{}NoPassive".format(_PREFIX) # None of the identity providers are supported by the intermediary. NO_SUPPORTED_IDP = "{}NoSupportedIDP".format(_PREFIX) # Not able to propagate logout to all other session participants. PARTIAL_LOGOUT = "{}PartialLogout".format(_PREFIX) # Cannot authenticate directly and not permitted to proxy the request. PROXY_COUNT_EXCEEDED = "{}ProxyCountExceeded".format(_PREFIX) # Is able to process the request but has chosen not to respond. REQUEST_DENIED = "{}RequestDenied".format(_PREFIX) # The SAML responder or SAML authority does not support the request. REQUEST_UNSUPPORTED = "{}RequestUnsupported".format(_PREFIX) # Deprecated protocol version specified in the request. REQUEST_VERSION_DEPRECATED = "{}RequestVersionDeprecated".format( _PREFIX) # Protocol version specified in the request message is too low. REQUEST_VERSION_TOO_LOW = "{}RequestVersionTooHigh".format(_PREFIX) # Protocol version specified in the request message is too high. REQUEST_VERSION_TOO_HIGH = "{}RequestVersionTooLow".format(_PREFIX) # Resource value provided in the request message is invalid. RESOURCE_NOT_RECOGNIZED = "{}ResourceNotRecognized".format(_PREFIX) # The response message would contain more elements than able. TOO_MANY_RESPONSES = "{}TooManyResponses".format(_PREFIX) # base.Attribute from an unknown attribute profile. UNKNOWN_ATTR_PROFILE = "{}UnknownAttrProfile".format(_PREFIX) # The responder does not recognize the principal. UNKNOWN_PRINCIPAL = "{}UnknownPrincipal".format(_PREFIX) # The SAML responder cannot properly fulfill the request. UNSUPPORTED_BINDING = "{}UnsupportedBinding".format(_PREFIX) # The status code value. This attribute contains a URI reference. value = base.Attribute(types.String) # A subordinate status code that provides more specific information # on an error condition. # TODO: code = Element('self') class Status(Base): # A code representing the status of the activity carried out in # response to the corresponding request. code = Element(StatusCode, required=True) class StatusResponse(_Message): """Extends the common message type with a status element. """ # A reference to the identifier of the request to which the # response corresponds, if any. in_response_to = base.Attribute(types.String) # A code representing the status of the corresponding request. status = Element(Status)
[docs]class Response(StatusResponse): """ Create a SAML Response :: from saml import schema from datetime import datetime document = schema.Response() document.id = '11111111-1111-1111-1111-111111111111' document.in_response_to = '22222222-2222-2222-2222-222222222222' document.issue_instant = datetime(2000, 1, 1, 1) document.issuer = 'https://idp.example.org/SAML2' document.destination = 'https://sp.example.com/SAML2/SSO/POST' document.status.code.value = schema.StatusCode.SUCCESS # Create an assertion for the response. document.assertions = assertion = schema.Assertion() assertion.id = '33333333-3333-3333-3333-333333333333' assertion.issue_instant = datetime(2000, 1, 1, 2) assertion.issuer = 'https://idp.example.org/SAML2' # Create a subject. assertion.subject = schema.Subject() assertion.subject.principal = '44444444-4444-4444-4444-444444444444' assertion.subject.principal.format = schema.NameID.Format.TRANSIENT data = schema.SubjectConfirmationData() data.in_response_to = '22222222-2222-2222-2222-222222222222' data.not_on_or_after = datetime(2000, 1, 1, 1, 10) data.recipient = 'https://sp.example.com/SAML2/SSO/POST' confirmation = schema.SubjectConfirmation() confirmation.data = data assertion.subject.confirmation = confirmation # Create an authentication statement. statement = schema.AuthenticationStatement() assertion.statements.append(statement) statement.authn_instant = datetime(2000, 1, 1, 1, 3) statement.session_index = '33333333-3333-3333-3333-333333333333' reference = schema.AuthenticationContextReference statement.context.reference = reference.PASSWORD_PROTECTED_TRANSPORT # Create a authentication condition. assertion.conditions = conditions = schema.Conditions() conditions.not_before = datetime(2000, 1, 1, 1, 3) conditions.not_on_or_after = datetime(2000, 1, 1, 1, 9) condition = schema.AudienceRestriction() condition.audiences = 'https://sp.example.com/SAML2' conditions.condition = condition print document.tostring() Produces the following XML document: .. code-block:: xml <samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="11111111-1111-1111-1111-111111111111" IssueInstant="2000-01-01T01:00:00Z" Destination="https://sp.example.com/SAML2/SSO/POST" InResponseTo="22222222-2222-2222-2222-222222222222"> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> <saml:Assertion Version="2.0" ID="33333333-3333-3333-3333-333333333333" IssueInstant="2000-01-01T02:00:00Z"> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <saml:Subject> <saml:NameID Format= "urn:oasis:names:tc:SAML:2.0:nameid-format:transient"> 44444444-4444-4444-4444-444444444444 </saml:NameID> <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer"> <saml:SubjectConfirmationData NotOnOrAfter="2000-01-01T01:10:00Z" Recipient="https://sp.example.com/SAML2/SSO/POST" InResponseTo= "22222222-2222-2222-2222-222222222222"/> </saml:SubjectConfirmation> </saml:Subject> <saml:Conditions NotBefore="2000-01-01T01:03:00Z" NotOnOrAfter="2000-01-01T01:09:00Z"> <saml:AudienceRestriction> <saml:Audience> https://sp.example.com/SAML2 </saml:Audience> </saml:AudienceRestriction> </saml:Conditions> <saml:AuthnStatement AuthnInstant="2000-01-01T01:03:00Z" SessionIndex="33333333-3333-3333-3333-333333333333"> <saml:AuthnContext> <saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes: PasswordProtectedTransport </saml:AuthnContextClassRef> </saml:AuthnContext> </saml:AuthnStatement> </saml:Assertion> </samlp:Response> """ # Specifies an assertion by value, or optionally an encrypted assertion # by value. assertions = Element(saml.Assertion, collection=True)
class Artifact(Base): """ The artifact value that the requester received and now wishes to translate into the protocol message it represents. """ class ArtifactResolve(_Message): """ Used to request that a SAML protocol message be returned in an <ArtifactResponse> message by specifying an artifact that represents the SAML protocol message. """ # The artifact value that the requester received and now wishes to # translate into the protocol message it represents. artifact = Element(Artifact, required=True) class ArtifactResponse(StatusResponse): """ Responds to an <ArtifactResolve> request with an embedded message that was referenced by the given artifact. """ # The embedded message. message = Element(_Message) class SessionIndex(Base): """The identifier that indexes a session at the message recipient. """
[docs]class LogoutRequest(_Message): """ Create a SAML LogoutRequest :: from saml import schema from datetime import datetime document = schema.LogoutRequest() document.id = '11111111-1111-1111-1111-111111111111' document.issue_instant = datetime(2000, 1, 1) document.issuer = 'https://idp.example.org/SAML2' document.destination = 'https://sp.example.org/SAML2/logout' document.principal = 'myemail@mydomain.com' document.principal.format = schema.NameID.Format.EMAIL document.principal.name_qualifier = 'https://idp.example.org/SAML2' document.session_index = 'SESSION-22222222-2222-2222-2222-222222222222' print document.tostring() Produces the following XML document: .. code-block:: xml <samlp:LogoutRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="11111111-1111-1111-1111-111111111111" IssueInstant="2000-01-01T00:00:00Z" Destination="https://idphost/adfs/ls/"> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <saml:NameID NameQualifier="https://idp.example.org/SAML2" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress"> myemail@mydomain.com </saml:NameID> <samlp:SessionIndex> SESSION-22222222-2222-2222-2222-222222222222 </samlp:SessionIndex> </samlp:LogoutRequest> """ # The time at which the request expires, after which the recipient # may discard the message. not_on_or_after = base.Attribute(types.DateTime) # An indication of the reason for the logout, in the # form of a URI reference. reason = base.Attribute(types.String) # The identifier and associated attributes # (in plaintext or encrypted form) that specify the principal as # currently recognized by the identity and service providers prior # to this request. principal = Element(saml.NameID, required=True) # The identifier that indexes this session at the message recipient. session_index = Element(SessionIndex)
[docs]class LogoutResponse(StatusResponse): """ Create a SAML LogoutResponse :: from saml import schema from datetime import datetime document = schema.LogoutResponse() document.id = '22222222-2222-2222-2222-222222222222' document.in_response_to = '11111111-1111-1111-1111-111111111111' document.issue_instant = datetime(2000, 1, 1) document.issuer = 'https://idp.example.org/SAML2' document.destination = 'https://sp.example.com/SAML2/SLO/POST' document.status.code.value = schema.StatusCode.SUCCESS print document.tostring() Produces the following XML document: .. code-block:: xml <samlp:LogoutResponse xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" ID="22222222-2222-2222-2222-222222222222" IssueInstant="2000-01-01T00:00:00Z" Destination="https://sp.example.com/SAML2/SLO/POST" InResponseTo="11111111-1111-1111-1111-111111111111"> <saml:Issuer>https://idp.example.org/SAML2</saml:Issuer> <samlp:Status> <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/> </samlp:Status> </samlp:LogoutResponse> """