Changes between Version 8 and Version 9 of SAML2.0


Ignore:
Timestamp:
01/10/10 14:51:21 (9 years ago)
Author:
pjkersha
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • SAML2.0

    v8 v9  
    55 
    66== Example Code == 
     7=== Attribute Query === 
     8This example creates an attribute query: 
    79{{{ 
    810from ndg.saml.saml2.core import (AttributeQuery, SAMLVersion, Issuer, Subject, 
     
    6163</samlp:AttributeQuery> 
    6264}}} 
     65 
     66=== Query/Request Profile with SOAP Binding === 
     67This example shows how a simple Attribute Service can be created with WSGI together with a client call. 
     68 
     69The server is configured using a Paste ini file.  A pipeline arranges a custom filter `AttributeAuthorityFilter`, in this case upstream of the `SAMLSoapAttributeInterfaceFilter` available with this package.  `TestApp` is a simple WSGI application to terminate the chain. 
     70{{{ 
     71[pipeline:main] 
     72pipeline = AttributeAuthorityFilter SAMLSoapAttributeInterfaceFilter TestApp 
     73}}} 
     74`SAMLSoapAttributeInterfaceFilter` uses the `ndg.saml.saml2.binding.soap.server.wsgi.queryinterface:SOAPQueryInterfaceMiddleware` class.  The settings define the path for where the service will be mounted and the serialisation/parsing classes for handling the SAML XML content.  the ElementTree based ones have been used.   
     75{{{ 
     76[filter:SAMLSoapAttributeInterfaceFilter] 
     77paste.filter_app_factory = ndg.saml.saml2.binding.soap.server.wsgi.queryinterface:SOAPQueryInterfaceMiddleware.filter_app_factory 
     78prefix = saml. 
     79saml.mountPath = /attributeauthority 
     80saml.queryInterfaceKeyName = attributeQueryInterface 
     81saml.deserialise = ndg.saml.xml.etree:AttributeQueryElementTree.fromXML 
     82saml.serialise = ndg.saml.xml.etree:ResponseElementTree.toXML 
     83}}} 
     84The `saml.queryInterfaceKeyName` setting above is important.  This sets the keyword in `environ` that this class will use to get a callback function.  This callback handles the actual query.  It has the pattern: 
     85{{{ 
     86attributeQuery(query, response) 
     87}}} 
     88where `query` is the parsed SAML query and response is the SAML response object which needs to be populated.  For covenience, the caller set a number of values in this object such as for example the issuer instant, ID and the `inResponseTo` values.  As the callback is read from `environ`, any custom middleware upstream of this filter can set it.  This is what the `AttributeAuthorityFilter` does in this example.  Looking at the details in the ini file, it sets an `environ` key named `attributeQueryInterface` which assigns to a callback function it creates: 
     89{{{ 
     90[filter:AttributeAuthorityFilter] 
     91# This filter is a container for a binding to a SOAP based interface to the 
     92# Attribute Authority 
     93paste.filter_app_factory = ndg.saml.test.binding.soap.test_attributeservice:TestAttributeServiceMiddleware 
     94queryInterfaceKeyName = attributeQueryInterface 
     95}}} 
     96Looking at the `ndg.saml.test.binding.soap.test_attributeservice:TestAttributeServiceMiddleware` implementation, a factory method creates the callback (shortened for breverity): 
     97 
     98    def attributeQueryFactory(self): 
     99        """Makes the attribute query method""" 
     100         
     101        def attributeQuery(query, response): 
     102            """Attribute Query interface called by the next middleware in the  
     103            stack the SAML SOAP Query interface middleware instance 
     104            (ndg.saml.saml2.binding.soap.server.wsgi.queryinterface.SOAPQueryInterfaceMiddleware) 
     105            """ 
     106            <...>  
     107                 
     108            assertion = Assertion() 
     109             
     110            assertion.version = SAMLVersion(SAMLVersion.VERSION_20) 
     111            assertion.id = str(uuid4()) 
     112            assertion.issueInstant = response.issueInstant 
     113             
     114            assertion.conditions = Conditions() 
     115            assertion.conditions.notBefore = assertion.issueInstant 
     116            assertion.conditions.notOnOrAfter = \ 
     117                assertion.conditions.notBefore + timedelta(seconds=60*60*8) 
     118             
     119            assertion.subject = Subject()   
     120            assertion.subject.nameID = NameID() 
     121            assertion.subject.nameID.format = query.subject.nameID.format 
     122            assertion.subject.nameID.value = query.subject.nameID.value 
     123            <...> 
     124             
     125            response.assertions.append(assertion) 
     126            response.status.statusCode.value = StatusCode.SUCCESS_URI         
     127}}} 
     128The middleware's `__call__` method invokes this method to set the callback in `environ`: 
     129{{{ 
     130    def __call__(self, environ, start_response): 
     131        environ[self.queryInterfaceKeyName] = self.attributeQueryFactory() 
     132        return self._app(environ, start_response) 
     133}}} 
     134 
     135The client request is created using the SOAP binding and sent with SSL.  `ndg.saml.saml2.binding.soap.client.attributequery.AttributeQuerySslSOAPBinding` is a wrapper class to perform this task taking SAML attribute query inputs and SSL settings.  In this example, the subject is queried for an e-mail address.  The connection is mutually authenticated with the client passing a certificate in the SSL handshake: 
     136 
     137{{{ 
     138from ndg.soap.utils.etree import prettyPrint 
     139 
     140from ndg.saml.saml2.core import Attribute, StatusCode 
     141from ndg.saml.xml.etree import ResponseElementTree 
     142from ndg.saml.saml2.binding.soap.client.attributequery import \ 
     143    AttributeQuerySslSOAPBinding 
     144 
     145attributeQuery = AttributeQuerySslSOAPBinding() 
     146 
     147attributeQuery.subjectID = "https://openid.localhost/philip.kershaw" 
     148attributeQuery.subjectIdFormat = "urn:ndg:saml:openid" 
     149attributeQuery.clockSkewTolerance = 2. 
     150attributeQuery.issuerName = '/O=Site A/CN=Authorisation Service' 
     151 
     152attribute = Attribute() 
     153attribute.name = 'urn:ndg:saml:emailaddress' 
     154attribute.friendlyName = 'emailAddress' 
     155attribute.nameFormat = 'http://www.w3.org/2001/XMLSchema' 
     156 
     157attributeQuery.queryAttributes.append(attribute) 
     158 
     159attributeQuery.sslCACertDir = "./trustroots" 
     160attributeQuery.sslCertFilePath = "./client.crt" 
     161attributeQuery.sslPriKeyFilePath = "./client.key" 
     162 
     163response = attributeQuery.send(uri='https://localhost:5443/attributeauthority') 
     164 
     165# Convert back to ElementTree instance read for string output 
     166samlResponseElem = ResponseElementTree.toXML(response) 
     167 
     168print("Pretty print SAML Response ...") 
     169print(prettyPrint(samlResponseElem)) 
     170}}} 
     171 
     172The response is generated: 
     173{{{ 
     174<samlp:Response ID="c61f8c17-8d2d-4b6a-ad7f-3acd6b4c3adc" InResponseTo="6fb92e0e-4570-4c03-8df9-6ee76ecfb03f" IssueInstant="2010-10-01T13:24:20.446046Z" Version="2.0" xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk</saml:Issuer><samlp:Status><samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success" /></samlp:Status><saml:Assertion ID="bcd28e09-1eb9-47f6-95c7-5b4133783aec" IssueInstant="2010-10-01T13:24:20.446046Z" Version="2.0" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"><saml:Subject><saml:NameID Format="urn:ndg:saml:openid">https://openid.localhost/philip.kershaw</saml:NameID></saml:Subject><saml:Conditions NotBefore="2010-10-01T13:24:20.446046Z" NotOnOrAfter="2010-10-01T21:24:20.446046Z" /><saml:AttributeStatement><saml:Attribute FriendlyName="emailAddress" Name="urn:ndg:saml:emailaddress" NameFormat="http://www.w3.org/2001/XMLSchema"><saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">pkershaw@somewhere.ac.uk</saml:AttributeValue></saml:Attribute></saml:AttributeStatement></saml:Assertion></samlp:Response> 
     175Pretty print SAML Response ... 
     176<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" IssueInstant="2010-10-01T13:24:20.446046Z" InResponseTo="6fb92e0e-4570-4c03-8df9-6ee76ecfb03f" Version="2.0" ID="c61f8c17-8d2d-4b6a-ad7f-3acd6b4c3adc"> 
     177    <saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">/O=NDG/OU=BADC/CN=attributeauthority.badc.rl.ac.uk</saml:Issuer> 
     178    <samlp:Status> 
     179        <samlp:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"></samlp:StatusCode> 
     180    </samlp:Status> 
     181    <saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" Version="2.0" IssueInstant="2010-10-01T13:24:20.446046Z" ID="bcd28e09-1eb9-47f6-95c7-5b4133783aec"> 
     182        <saml:Subject> 
     183            <saml:NameID Format="urn:ndg:saml:openid">https://openid.localhost/philip.kershaw</saml:NameID> 
     184        </saml:Subject> 
     185        <saml:Conditions NotOnOrAfter="2010-10-01T21:24:20.446046Z" NotBefore="2010-10-01T13:24:20.446046Z"></saml:Conditions> 
     186        <saml:AttributeStatement> 
     187            <saml:Attribute FriendlyName="emailAddress" Name="urn:ndg:saml:emailaddress" NameFormat="http://www.w3.org/2001/XMLSchema"> 
     188                <saml:AttributeValue xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string" xmlns:xs="http://www.w3.org/2001/XMLSchema">pkershaw@somewhere.ac.uk</saml:AttributeValue> 
     189            </saml:Attribute> 
     190        </saml:AttributeStatement> 
     191    </saml:Assertion> 
     192</samlp:Response> 
     193}}} 
     194 
    63195== Repository == 
    64196http://proj.badc.rl.ac.uk/ndg/browser/TI12-security/trunk/ndg_saml