source: TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/paster_templates/template.py @ 7824

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/NDGSecurity/python/ndg_security_server/ndg/security/server/paster_templates/template.py@7824
Revision 7824, 16.2 KB checked in by pjkersha, 10 years ago (diff)

Incomplete - task 16: NDG Security 2.x.x - incl. updated Paster templates

  • Completed all templates
  • Tested OpenID Provider setup from template. TODO: test remaining configurations as created by respective templates
  • ALL UNIT TESTS pass for ndg.security.*
  • fix from rel to abs file path for authorisation-service.ini, tidied unit test directory.
  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1"""NDG Security Paster template classes
2
3NERC DataGrid Project
4"""
5__author__ = "P J Kershaw"
6__date__ = "20/10/2010"
7__copyright__ = "(C) 2010 Science and Technology Facilities Council"
8__license__ = "BSD - see top-level directory for LICENSE file"
9__contact__ = "Philip.Kershaw@stfc.ac.uk"
10__revision__ = "$Id$"
11
12import os
13import socket
14import base64
15import string
16import re
17from urlparse import urlunsplit, urlparse
18from paste.script.templates import Template, var
19from paste.script.copydir import LaxTemplate
20
21_hostTuple = socket.gethostbyaddr(socket.gethostname())
22try:
23    # Get first alias from list if present
24    _hostname = _hostTuple[1][0]
25except IndexError:
26    # ... or default to hostname
27    _hostname = _hostTuple[0]
28   
29from ndg.saml.saml2.core import Issuer   
30
31
32class DoublePercentTemplate(string.Template):
33    """Alternative template uses '%%' instead of '$' to denote template
34    variables.  This is used because some NDG Security templates contain
35    '$' variables used for other purposes."""
36    delimiter = "%%"
37
38
39"""@var _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for a MyProxy
40server endpoint.  This entry also include a localID $user_url which the OpenID
41Provider application code will fill out at runtime.
42@type _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
43"""
44_MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<XRD>
45        <Service priority="10">
46            <Type>urn:esg:security:myproxy-service</Type>
47            <URI>%%{myproxyServerURI}</URI>
48            <LocalID>$user_url</LocalID>
49        </Service>
50    </XRD>
51""")
52
53"""@var _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for an
54Attribute Service endpoint.  This entry also include a localID $user_url which
55the OpenID Provider application code will fill out at runtime.
56@type _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
57"""
58_ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<XRD>
59        <Service priority="20">
60            <Type>urn:esg:security:attribute-service</Type>
61            <Type>urn:esg:security:attribute-service</Type>
62            <URI>%%{attributeServiceURI}</URI>
63            <LocalID>$user_url</LocalID>
64        </Service>
65    </XRD>
66""")
67
68"""@var _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for a
69MyProxy server endpoint.  No localID entry is included as this template is for
70use with the serveryadis.xml_tmpl which applies to requests where the specific
71identity is not provided.
72@type _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
73"""
74_MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<XRD>
75        <Service priority="10">
76            <Type>urn:esg:security:myproxy-service</Type>
77            <URI>%%{myproxyServerURI}</URI>
78        </Service>
79    </XRD>
80""")
81
82"""@var _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for an
83Attribute Service endpoint.  No localID entry is included as this template is
84for use with the serveryadis.xml_tmpl which applies to requests where the
85specific identity is not provided.
86@type _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
87"""
88_ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<XRD>
89        <Service priority="20">
90            <Type>urn:esg:security:attribute-service</Type>
91            <URI>%%{attributeServiceURI}</URI>
92        </Service>
93    </XRD>
94""")
95
96
97class ServicesTemplate(Template):
98    """Make a template containing all the Security Services available with
99    NDG Security.  These are provided together in one template but deployers
100    should consider adapting this and dividing up into separate WSGI apps
101    to suit
102    """
103    DEFAULT_URI = urlunsplit(('https', _hostname, '', None, None))
104   
105    ATTRIBUTE_SERVICE_DEFAULT_MOUNT_POINT = '/AttributeService'
106    ATTRIBUTE_SERVICE_DEFAULT_ISSUER_NAME = '/O=Site A/CN=Attribute Authority'
107    ATTRIBUTE_SERVICE_DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
108   
109    AUTHORISATION_SERVICE_DEFAULT_ISSUER_NAME = \
110        '/O=Site A/CN=Authorisation Service'
111    AUTHORISATION_SERVICE_DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
112    AUTHORISATION_SERVICE_DEFAULT_MOUNT_POINT = '/AuthorisationService'   
113   
114    _template_dir = 'services'
115    summary = ('NERC DataGrid Security services full deployment template '
116               'including the SAML Attribute and Authorisation Services, '
117               'OpenID Provider application, OpenID Relying Party and SSL '
118               'client authentication services')
119    vars = [
120        var('baseURI',
121            'Base URI for the service(s) [with no trailing slash]',
122            default=DEFAULT_URI),
123           
124        var('attributeServiceMountPoint',
125            'Mount point for Attribute Service',
126            ATTRIBUTE_SERVICE_DEFAULT_MOUNT_POINT),
127           
128        var('authorisationServiceMountPoint',
129            'Mount point for Authorisation Service',
130            AUTHORISATION_SERVICE_DEFAULT_MOUNT_POINT),
131           
132        var('attributeServiceIssuerName',
133            'SAML Issuer Name field for Attribute Service SAML responses',
134            ATTRIBUTE_SERVICE_DEFAULT_ISSUER_NAME),
135           
136        var('attributeServiceIssuerFormat',
137            'SAML Issuer Name field for Attribute Service SAML responses',
138            ATTRIBUTE_SERVICE_DEFAULT_ISSUER_FORMAT),
139           
140        var('authorisationServiceIssuerName',
141            'SAML Issuer Name field for Authorisation Service SAML responses',
142            AUTHORISATION_SERVICE_DEFAULT_ISSUER_NAME),
143           
144        var('authorisationServiceIssuerFormat',
145            'SAML Issuer Name field for Authorisation Service SAML responses',
146            AUTHORISATION_SERVICE_DEFAULT_ISSUER_FORMAT),
147
148        var('authkitCookieSecret', 
149            ('Cookie secret for AuthKit authentication middleware.  This value '
150             'MUST agree with the one used for the ini file of the application '
151             'to be secured'),
152            default=base64.b64encode(os.urandom(32))[:32]),
153
154        var('beakerSessionCookieSecret', 
155            'Secret for securing the OpenID Provider and SSL Client '
156            'authentication session cookie',
157            default=base64.b64encode(os.urandom(32))[:32]),
158           
159        var('openidRelyingPartyCookieSecret',
160            'Secret for securing OpenID Relying Party session cookie',
161            default=base64.b64encode(os.urandom(32))[:32]),
162           
163        var('myproxyServerURI',
164            'MyProxy Server address to advertise in OpenID Provider Yadis '
165            'document - defaults to omit this entry',
166            default=''),
167           
168        var('includeAttributeServiceInYadis',
169            'Include Attribute Service address in OpenID Provider Yadis '
170            'document',
171            default=True)
172        ]
173   
174    def template_renderer(self, content, vars, filename=None):
175        """Alternative renderer defined to enable use of '%%' prefix for template
176        variables.  NDG Security ini files already use '$' for other variables
177       
178        @param content: template content
179        @type content: string
180        @param vars: variables to substituted into the template
181        @type vars: dict
182        @return: content with all variables substituted for
183        @rtype: string
184        """
185        tmpl = DoublePercentTemplate(content)
186        return tmpl.substitute(**vars)
187   
188    def pre(self, command, output_dir, vars):
189        '''Extend to enable substitutions for OpenID Provider Yadis templates,
190        port number and fix log file path setting
191       
192        @param command: command to create template
193        @type command:
194        @param output_dir: output directory for template file(s)
195        @type output_dir: string
196        @param vars: variables to be substituted into template
197        @type vars: dict
198        ''' 
199       
200        # This sets the log file path
201        vars['outputDir'] = os.path.abspath(output_dir)
202
203        # Cut out port number from base URI
204        uriParts = urlparse(vars['baseURI'])
205        netlocLastElem = uriParts.netloc.split(':')[-1]
206        if netlocLastElem.isdigit():
207            vars['portNumber'] = netlocLastElem
208        else:
209            vars['portNumber'] = ''
210           
211        vars['yadisExtraXrdEntries'] = ''
212        vars['serveryadisExtraXrdEntries'] = ''
213       
214        attributeServiceURI = vars['baseURI'] + vars[
215                                'attributeServiceMountPoint'].lstrip('/')
216       
217        # Attribute Service entry added if flag was set
218        if vars['includeAttributeServiceInYadis']:
219            # yadis.xml_tmpl entry
220            vars['yadisExtraXrdEntries'
221                 ] += _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL.substitute(
222                        attributeServiceURI=attributeServiceURI)
223
224            # serveryadis.xml_tmpl entry
225            vars['serveryadisExtraXrdEntries'
226                 ] += _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL.substitute(
227                        attributeServiceURI=attributeServiceURI)
228
229        del vars['includeAttributeServiceInYadis']
230       
231        # MyProxy Server entry added if an endpoint was specified
232        if vars['myproxyServerURI']:
233            # yadis.xml_tmpl entry
234            vars['yadisExtraXrdEntries'
235                 ] += _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL.substitute(
236                            myproxyServerURI=vars['myproxyServerURI'])       
237           
238            vars['serveryadisExtraXrdEntries'
239                 ] += _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL.substitute(
240                        myproxyServerURI=vars['myproxyServerURI'])
241        del vars['myproxyServerURI']   
242       
243        super(ServicesTemplate, self).pre(command, output_dir, vars)
244
245       
246class SecuredAppTemplate(Template):
247    """Create a template for a secured application with authentication and
248    authorisation filters"""
249   
250    _template_dir = 'secured_application'
251    summary = (
252        'Secure an application with NERC DataGrid Security '
253        'authentication and authorisation filters')
254    vars = [
255        var('hostname', 
256            ('Virtual host name to mount services on'),
257            default=_hostname),
258
259        var('authkitCookieSecret', 
260            ('Cookie secret for AuthKit authentication middleware (if using a '
261             'separate SSL based OpenID Relying Party then this value MUST '
262             'agree with the one used for that ini file'),
263            default=base64.b64encode(os.urandom(32))[:32]),
264
265        var('beakerSessionSecret', 
266            'Cookie secret for keeping security session state',
267            default=base64.b64encode(os.urandom(32))[:32])
268    ]
269
270
271class AttributeServiceTemplate(Template):
272    """Paster template for the SAML attribute service"""
273   
274    DEFAULT_MOUNT_POINT = '/AttributeService'
275    DEFAULT_ISSUER_NAME = 'O=NDG, OU=Security, CN=localhost'
276    DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
277   
278    _template_dir = 'attributeservice'
279    summary = 'Create an NDG Security SAML Attribute Service'
280    vars = [
281        var('mountPoint', 
282            ('URI path to mount service i.e. https://myhost/<mountPoint>'),
283            default=DEFAULT_MOUNT_POINT),
284
285        var('issuerName', 
286            ('ID of this service used in SAML queries and responses'),
287            default=DEFAULT_ISSUER_NAME),
288
289        var('issuerFormat', 
290            ('Format of issuerName string; if using the default, ensure that '
291             'the issuerName value is a correctly formatted X.509 Subject '
292             'Name'),
293            default=DEFAULT_ISSUER_FORMAT)
294    ]
295   
296
297class AuthorisationServiceTemplate(Template):
298    """Paster template for the SAML authorisation service"""
299   
300    DEFAULT_MOUNT_POINT = '/AuthorisationService'
301    DEFAULT_ISSUER_NAME = 'O=NDG, OU=Security, CN=localhost'
302    DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
303   
304    _template_dir = 'authorisationservice'
305    summary = 'Create an NDG Security Authorisation Service'
306    vars = [
307        var('mountPoint', 
308            ('URI path to mount service i.e. https://myhost/<mountPoint>'),
309            default=DEFAULT_MOUNT_POINT),
310
311        var('issuerName', 
312            ('ID of this service used in SAML queries and responses'),
313            default=DEFAULT_ISSUER_NAME),
314
315        var('issuerFormat', 
316            ('Format of issuerName string; if using the default, ensure that '
317             'the issuerName value is a correctly formatted X.509 Subject '
318             'Name'),
319            default=DEFAULT_ISSUER_FORMAT)
320    ]
321
322
323class OpenIDProviderTemplate(Template):
324    """Paster template for OpenID Provider service"""
325    _template_dir = 'openidprovider'
326    summary = 'Create an NDG Security OpenID Provider'
327   
328    DEFAULT_URI = urlunsplit(('https', _hostname, '', None, None))
329   
330    vars = [
331        var('baseURI',
332            'Base URI for the service [with no trailing slash]',
333            default=DEFAULT_URI),
334
335        var('beakerSessionCookieSecret', 
336            'Secret for securing the OpenID Provider and SSL Client '
337            'authentication session cookie',
338            default=base64.b64encode(os.urandom(32))[:32]),
339           
340        var('myproxyServerURI',
341            'MyProxy Server address to advertise in OpenID Provider Yadis '
342            'document - defaults to omit this entry',
343            default=''),
344           
345        var('attributeServiceURI',
346            'Attribute Service address to advertise in OpenID Provider Yadis '
347            'document - defaults to omit this entry',
348            default='')
349        ]
350   
351    def template_renderer(self, content, vars, filename=None):
352        """Alternative renderer defined to enable use of '%%' prefix for template
353        variables.  NDG Security ini files already use '$' for other variables
354       
355        @param content: template content
356        @type content: string
357        @param vars: variables to substituted into the template
358        @type vars: dict
359        @return: content with all variables substituted for
360        @rtype: string
361        """
362        tmpl = DoublePercentTemplate(content)
363        return tmpl.substitute(**vars)
364
365    def pre(self, command, output_dir, vars):
366        '''Extend to enable substitutions for OpenID Provider Yadis templates,
367        port number and fix log file path setting
368       
369        @param command: command to create template
370        @type command:
371        @param output_dir: output directory for template file(s)
372        @type output_dir: string
373        @param vars: variables to be substituted into template
374        @type vars: dict
375        ''' 
376       
377        # This sets the log file path
378        vars['outputDir'] = os.path.abspath(output_dir)
379
380        # Cut out port number from base URI
381        uriParts = urlparse(vars['baseURI'])
382        netlocLastElem = uriParts.netloc.split(':')[-1]
383        if netlocLastElem.isdigit():
384            vars['portNumber'] = netlocLastElem
385        else:
386            vars['portNumber'] = ''
387
388        # Set Yadis XRDS entries
389        vars['yadisExtraXrdEntries'] = ''
390        vars['serveryadisExtraXrdEntries'] = ''
391       
392        # Attribute Service entry added if an endpoint was specified
393        if vars['attributeServiceURI']:
394            # yadis.xml_tmpl entry
395            vars['yadisExtraXrdEntries'
396                 ] += _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL.substitute(
397                        attributeServiceURI=vars['attributeServiceURI'])
398
399            # serveryadis.xml_tmpl entry
400            vars['serveryadisExtraXrdEntries'
401                 ] += _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL.substitute(
402                        attributeServiceURI=vars['attributeServiceURI'])
403
404        del vars['attributeServiceURI']
405       
406        if vars['myproxyServerURI']:
407            # yadis.xml_tmpl entry
408            vars['yadisExtraXrdEntries'
409                 ] += _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL.substitute(
410                            myproxyServerURI=vars['myproxyServerURI'])       
411           
412            vars['serveryadisExtraXrdEntries'
413                 ] += _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL.substitute(
414                        myproxyServerURI=vars['myproxyServerURI'])
415                         
416        del vars['myproxyServerURI'] 
417         
418        super(OpenIDProviderTemplate, self).pre(command, output_dir, vars)
419
420
Note: See TracBrowser for help on using the repository browser.