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

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@7845
Revision 7845, 18.7 KB checked in by pjkersha, 9 years ago (diff)

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

  • fixed yadis template syntax
  • updating securedapp template.
  • 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
16from urlparse import urlunsplit, urlparse
17from paste.script.templates import Template, var
18
19_hostTuple = socket.gethostbyaddr(socket.gethostname())
20try:
21    # Get first alias from list if present
22    _hostname = _hostTuple[1][0]
23except IndexError:
24    # ... or default to hostname
25    _hostname = _hostTuple[0]
26   
27from ndg.saml.saml2.core import Issuer   
28
29
30class DoublePercentTemplate(string.Template):
31    """Alternative template uses '%%' instead of '$' to denote template
32    variables.  This is used because some NDG Security templates contain
33    '$' variables used for other purposes."""
34    delimiter = "%%"
35   
36   
37class TemplateBase(Template):
38    """Base Paste Template class sets a custom renderer"""
39   
40    def template_renderer(self, content, vars, filename=None):
41        """Alternative renderer defined to enable use of '%%' prefix for template
42        variables.  NDG Security ini files already use '$' for other variables
43       
44        @param content: template content
45        @type content: string
46        @param vars: variables to substituted into the template
47        @type vars: dict
48        @return: content with all variables substituted for
49        @rtype: string
50        """
51        tmpl = DoublePercentTemplate(content)
52        return tmpl.substitute(**vars)
53
54"""@var _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for a MyProxy
55server endpoint.  This entry also include a localID $user_url which the OpenID
56Provider application code will fill out at runtime.
57@type _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
58"""
59_MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<Service priority="10">
60            <Type>urn:esg:security:myproxy-service</Type>
61            <URI>%%{myproxyServerURI}</URI>
62            <LocalID>$user_url</LocalID>
63        </Service>
64""")
65
66"""@var _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for an
67Attribute Service endpoint.  This entry also include a localID $user_url which
68the OpenID Provider application code will fill out at runtime.
69@type _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
70"""
71_ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<Service priority="20">
72            <Type>urn:esg:security:attribute-service</Type>
73            <Type>urn:esg:security:attribute-service</Type>
74            <URI>%%{attributeServiceURI}</URI>
75            <LocalID>$user_url</LocalID>
76        </Service>
77""")
78
79"""@var _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for a
80MyProxy server endpoint.  No localID entry is included as this template is for
81use with the serveryadis.xml_tmpl which applies to requests where the specific
82identity is not provided.
83@type _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
84"""
85_MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<Service priority="10">
86            <Type>urn:esg:security:myproxy-service</Type>
87            <URI>%%{myproxyServerURI}</URI>
88        </Service>
89""")
90
91"""@var _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL: Yadis XRDS entry for an
92Attribute Service endpoint.  No localID entry is included as this template is
93for use with the serveryadis.xml_tmpl which applies to requests where the
94specific identity is not provided.
95@type _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL: ndg.security.server.paster_templates.template.DoublePercentTemplate
96"""
97_ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL = DoublePercentTemplate("""<Service priority="20">
98            <Type>urn:esg:security:attribute-service</Type>
99            <URI>%%{attributeServiceURI}</URI>
100        </Service>
101""")
102
103
104class ServicesTemplate(TemplateBase):
105    """Make a template containing all the Security Services available with
106    NDG Security.  These are provided together in one template but deployers
107    should consider adapting this and dividing up into separate WSGI apps
108    to suit
109    """
110    DEFAULT_URI = urlunsplit(('https', _hostname, '', None, None))
111   
112    ATTRIBUTE_SERVICE_DEFAULT_MOUNT_PATH = '/AttributeService'
113    ATTRIBUTE_SERVICE_DEFAULT_ISSUER_NAME = '/O=Site A/CN=Attribute Authority'
114    ATTRIBUTE_SERVICE_DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
115   
116    AUTHORISATION_SERVICE_DEFAULT_ISSUER_NAME = \
117        '/O=Site A/CN=Authorisation Service'
118    AUTHORISATION_SERVICE_DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
119    AUTHORISATION_SERVICE_DEFAULT_MOUNT_PATH = '/AuthorisationService'   
120   
121    _template_dir = 'services'
122    summary = ('NDG Security services full deployment template '
123               'including the SAML Attribute and Authorisation Services, '
124               'OpenID Provider application, OpenID Relying Party and SSL '
125               'client authentication services')
126    vars = [
127        var('baseURI',
128            'Base URI for the service(s) [with no trailing slash]',
129            default=DEFAULT_URI),
130           
131        var('attributeServiceMountPoint',
132            'Mount point for Attribute Service',
133            ATTRIBUTE_SERVICE_DEFAULT_MOUNT_PATH),
134           
135        var('authorisationServiceMountPoint',
136            'Mount point for Authorisation Service',
137            AUTHORISATION_SERVICE_DEFAULT_MOUNT_PATH),
138           
139        var('attributeServiceIssuerName',
140            'SAML Issuer Name field for Attribute Service SAML responses',
141            ATTRIBUTE_SERVICE_DEFAULT_ISSUER_NAME),
142           
143        var('attributeServiceIssuerFormat',
144            'SAML Issuer Name field for Attribute Service SAML responses',
145            ATTRIBUTE_SERVICE_DEFAULT_ISSUER_FORMAT),
146           
147        var('authorisationServiceIssuerName',
148            'SAML Issuer Name field for Authorisation Service SAML responses',
149            AUTHORISATION_SERVICE_DEFAULT_ISSUER_NAME),
150           
151        var('authorisationServiceIssuerFormat',
152            'SAML Issuer Name field for Authorisation Service SAML responses',
153            AUTHORISATION_SERVICE_DEFAULT_ISSUER_FORMAT),
154
155        var('authkitCookieSecret', 
156            ('Cookie secret for AuthKit authentication middleware.  This value '
157             'MUST agree with the one used for the ini file of the application '
158             'to be secured'),
159            default=base64.b64encode(os.urandom(32))[:32]),
160
161        var('beakerSessionCookieSecret', 
162            'Secret for securing the OpenID Provider and SSL Client '
163            'authentication session cookie',
164            default=base64.b64encode(os.urandom(32))[:32]),
165           
166        var('openidRelyingPartyCookieSecret',
167            'Secret for securing OpenID Relying Party session cookie',
168            default=base64.b64encode(os.urandom(32))[:32]),
169           
170        var('myproxyServerURI',
171            'MyProxy Server address to advertise in OpenID Provider Yadis '
172            'document - defaults to omit this entry',
173            default=''),
174           
175        var('includeAttributeServiceInYadis',
176            'Include Attribute Service address in OpenID Provider Yadis '
177            'document',
178            default=True)
179        ]
180   
181    def pre(self, command, output_dir, vars):
182        '''Extend to enable substitutions for OpenID Provider Yadis templates,
183        port number and fix log file path setting
184       
185        @param command: command to create template
186        @type command:
187        @param output_dir: output directory for template file(s)
188        @type output_dir: string
189        @param vars: variables to be substituted into template
190        @type vars: dict
191        ''' 
192       
193        # This sets the log file path
194        vars['outputDir'] = os.path.abspath(output_dir)
195
196        # Cut out port number from base URI
197        uriParts = urlparse(vars['baseURI'])
198        netlocLastElem = uriParts.netloc.split(':')[-1]
199        if netlocLastElem.isdigit():
200            vars['portNumber'] = netlocLastElem
201        else:
202            vars['portNumber'] = ''
203           
204        vars['yadisExtraServiceEndpoints'] = ''
205        vars['serveryadisExtraServiceEndpoints'] = ''
206       
207        attributeServiceURI = vars['baseURI'] + vars[
208                                'attributeServiceMountPoint'].lstrip('/')
209       
210        # Attribute Service entry added if flag was set
211        if vars['includeAttributeServiceInYadis']:
212            # yadis.xml_tmpl entry
213            vars['yadisExtraServiceEndpoints'
214                 ] += _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL.substitute(
215                        attributeServiceURI=attributeServiceURI)
216
217            # serveryadis.xml_tmpl entry
218            vars['serveryadisExtraServiceEndpoints'
219                 ] += _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL.substitute(
220                        attributeServiceURI=attributeServiceURI)
221
222        del vars['includeAttributeServiceInYadis']
223       
224        # MyProxy Server entry added if an endpoint was specified
225        if vars['myproxyServerURI']:
226            # yadis.xml_tmpl entry
227            vars['yadisExtraServiceEndpoints'
228                 ] += _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL.substitute(
229                            myproxyServerURI=vars['myproxyServerURI'])       
230           
231            vars['serveryadisExtraServiceEndpoints'
232                 ] += _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL.substitute(
233                        myproxyServerURI=vars['myproxyServerURI'])
234        del vars['myproxyServerURI']   
235       
236        super(ServicesTemplate, self).pre(command, output_dir, vars)
237
238       
239class SecuredAppTemplate(TemplateBase):
240    """Create a template for a secured application with authentication and
241    authorisation filters"""
242    DEFAULT_PORT = 7080
243    DEFAULT_AUTHN_REDIRECT_URI = 'https://localhost:7443/verify'
244    DEFAULT_AUTHZ_SERVICE_URI = 'https://localhost:7443/AuthorisationService'
245    DEFAULT_ISSUER_NAME = 'O=NDG, OU=Security, CN=localhost'
246    DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
247   
248    _template_dir = 'secured_application'
249    summary = (
250        'NDG Security template for securing an application with '
251        'authentication and authorisation filters')
252    vars = [
253        var('portNumber',
254            'Port number for service to listen on [applies to running with '
255            'paster ONLY]',
256            default=DEFAULT_PORT),
257
258        var('authkitCookieSecret', 
259            ('Cookie secret for AuthKit authentication middleware (if using a '
260             'separate SSL based OpenID Relying Party then this value MUST '
261             'agree with the one used for that ini file'),
262            default=base64.b64encode(os.urandom(32))[:32]),
263
264        var('beakerSessionSecret', 
265            'Cookie secret for keeping security session state',
266            default=base64.b64encode(os.urandom(32))[:32]),
267
268        var('authnRedirectURI', 
269            ('endpoint hosting OpenID Relying Party and/or SSL authentication '
270             'interface'),
271            default=DEFAULT_AUTHN_REDIRECT_URI),
272
273        var('authzServiceURI', 
274            ('endpoint authorisation service which this app is secured with'),
275            default=DEFAULT_AUTHZ_SERVICE_URI),
276           
277        var('authzDecisionQueryIssuerName', 
278            ('ID of this service used in SAML authorisation queries'),
279            default=DEFAULT_ISSUER_NAME),
280
281        var('authzDecisionQueryIssuerFormat', 
282            ('Format of authzDecisionQueryIssuerName string; if using the '
283             'default, ensure that the issuerName value is a correctly '
284             'formatted X.509 Subject Name'),
285            default=DEFAULT_ISSUER_FORMAT)
286    ]
287
288
289class AttributeServiceTemplate(TemplateBase):
290    """Paster template for the SAML attribute service"""
291   
292    DEFAULT_PORT = 5000
293    DEFAULT_MOUNT_PATH = '/AttributeService'
294    DEFAULT_ISSUER_NAME = 'O=NDG, OU=Security, CN=localhost'
295    DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
296   
297    _template_dir = 'attributeservice'
298    summary = 'NDG Security SAML Attribute Service template'
299    vars = [
300        var('portNumber',
301            'Port number for service to listen on [applies to running with '
302            'paster ONLY]',
303            default=DEFAULT_PORT),
304           
305        var('mountPath', 
306            ('URI path to mount service i.e. "https://myhost/<mountPath>" ['
307             'Nb. for mod_wsgi path may be e.g. "https://myhost/<script alias '
308             'path><mountPath>" !]'),
309            default=DEFAULT_MOUNT_PATH),
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    def pre(self, command, output_dir, vars):
323        '''Extend to fix log file path setting and check mount point setting
324       
325        @param command: command to create template
326        @type command:
327        @param output_dir: output directory for template file(s)
328        @type output_dir: string
329        @param vars: variables to be substituted into template
330        @type vars: dict
331        ''' 
332        vars['outputDir'] = os.path.abspath(output_dir)
333       
334        # Fix for mount point in case leading slash was omitted.
335        if not vars['mountPath'].startswith('/'):
336            vars['mountPath'] = '/' + vars['mountPath']
337           
338
339class AuthorisationServiceTemplate(TemplateBase):
340    """Paster template for the SAML authorisation service"""
341   
342    DEFAULT_PORT = 5100
343    DEFAULT_MOUNT_PATH = '/AuthorisationService'
344    DEFAULT_ISSUER_NAME = 'O=NDG, OU=Security, CN=localhost'
345    DEFAULT_ISSUER_FORMAT = Issuer.X509_SUBJECT
346   
347    _template_dir = 'authorisationservice'
348    summary = 'NDG Security Authorisation Service template'
349   
350    vars = [
351        var('portNumber',
352            'Port number for service to listen on [applies to running with '
353            'paster ONLY]',
354            default=DEFAULT_PORT),
355
356        var('mountPath', 
357            ('URI path to mount service i.e. "https://myhost/<mountPath>" ['
358             'Nb. for mod_wsgi path may be e.g. "https://myhost/<script alias '
359             'path><mountPath>" !]'),
360            default=DEFAULT_MOUNT_PATH),
361
362        var('issuerName', 
363            ('ID of this service used in SAML queries and responses'),
364            default=DEFAULT_ISSUER_NAME),
365
366        var('issuerFormat', 
367            ('Format of issuerName string; if using the default, ensure that '
368             'the issuerName value is a correctly formatted X.509 Subject '
369             'Name'),
370            default=DEFAULT_ISSUER_FORMAT)
371    ]
372
373    def pre(self, command, output_dir, vars):
374        '''Extend to fix log file path setting and check mount point setting
375       
376        @param command: command to create template
377        @type command:
378        @param output_dir: output directory for template file(s)
379        @type output_dir: string
380        @param vars: variables to be substituted into template
381        @type vars: dict
382        ''' 
383        vars['outputDir'] = os.path.abspath(output_dir)
384       
385        # Fix for mount point in case leading slash was omitted.
386        if not vars['mountPath'].startswith('/'):
387            vars['mountPath'] = '/' + vars['mountPath']
388               
389
390class OpenIDProviderTemplate(TemplateBase):
391    """Paster template for OpenID Provider service"""
392    _template_dir = 'openidprovider'
393    summary = 'NDG Security OpenID Provider template'
394   
395    DEFAULT_URI = urlunsplit(('https', _hostname, '', None, None))
396   
397    vars = [
398        var('baseURI',
399            'Base URI for the service [with no trailing slash]',
400            default=DEFAULT_URI),
401
402        var('beakerSessionCookieSecret', 
403            'Secret for securing the OpenID Provider and SSL Client '
404            'authentication session cookie',
405            default=base64.b64encode(os.urandom(32))[:32]),
406           
407        var('myproxyServerURI',
408            'MyProxy Server address to advertise in OpenID Provider Yadis '
409            'document - defaults to omit this entry',
410            default=''),
411           
412        var('attributeServiceURI',
413            'Attribute Service address to advertise in OpenID Provider Yadis '
414            'document - defaults to omit this entry',
415            default='')
416        ]
417
418    def pre(self, command, output_dir, vars):
419        '''Extend to enable substitutions for OpenID Provider Yadis templates,
420        port number and fix log file path setting
421       
422        @param command: command to create template
423        @type command:
424        @param output_dir: output directory for template file(s)
425        @type output_dir: string
426        @param vars: variables to be substituted into template
427        @type vars: dict
428        ''' 
429       
430        # This sets the log file path
431        vars['outputDir'] = os.path.abspath(output_dir)
432
433        # Cut out port number from base URI
434        uriParts = urlparse(vars['baseURI'])
435        netlocLastElem = uriParts.netloc.split(':')[-1]
436        if netlocLastElem.isdigit():
437            vars['portNumber'] = netlocLastElem
438        else:
439            vars['portNumber'] = ''
440
441        # Set Yadis XRDS entries
442        vars['yadisExtraServiceEndpoints'] = ''
443        vars['serveryadisExtraServiceEndpoints'] = ''
444       
445        # Attribute Service entry added if an endpoint was specified
446        if vars['attributeServiceURI']:
447            # yadis.xml_tmpl entry
448            vars['yadisExtraServiceEndpoints'
449                 ] += _ATTRIBUTE_SERVICE_LOCALID_XRD_ENTRY_TMPL.substitute(
450                        attributeServiceURI=vars['attributeServiceURI'])
451
452            # serveryadis.xml_tmpl entry
453            vars['serveryadisExtraServiceEndpoints'
454                 ] += _ATTRIBUTE_SERVICE_NONLOCALID_XRD_ENTRY_TMPL.substitute(
455                        attributeServiceURI=vars['attributeServiceURI'])
456
457        del vars['attributeServiceURI']
458       
459        if vars['myproxyServerURI']:
460            # yadis.xml_tmpl entry
461            vars['yadisExtraServiceEndpoints'
462                 ] += _MYPROXY_SERVER_LOCALID_XRD_ENTRY_TMPL.substitute(
463                            myproxyServerURI=vars['myproxyServerURI'])       
464           
465            vars['serveryadisExtraServiceEndpoints'
466                 ] += _MYPROXY_SERVER_NONLOCALID_XRD_ENTRY_TMPL.substitute(
467                        myproxyServerURI=vars['myproxyServerURI'])
468                         
469        del vars['myproxyServerURI'] 
470         
471        super(OpenIDProviderTemplate, self).pre(command, output_dir, vars)
472
473
Note: See TracBrowser for help on using the repository browser.