source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/sso/sso/lib/openid_util.py @ 4692

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.server/ndg/security/server/sso/sso/lib/openid_util.py@4692
Revision 4692, 6.0 KB checked in by pjkersha, 11 years ago (diff)

Refactoring of SSO service to enable use of local AA and SM instances via keys to environ.

Line 
1import pylons
2from pylons.templating import Buffet
3from pylons import config, request, session
4import ndg.security.server.sso.sso.lib.helpers as h
5from ndg.security.server.sso.sso.lib.app_globals import Globals
6
7import logging
8log = logging.getLogger(__name__)
9
10log.debug("Defining MyBuffet for OpenID template ...")
11
12class MyBuffet(Buffet):
13    def _update_names(self, ns):
14        return ns
15
16def_eng = config['buffet.template_engines'][0]
17log.info("def_eng = %s" % def_eng)
18buffet = MyBuffet(
19    def_eng['engine'],
20    template_root=def_eng['template_root'],
21    **def_eng['template_options']
22)
23
24for e in config['buffet.template_engines'][1:]:
25    buffet.prepare(
26        e['engine'],
27        template_root=e['template_root'],
28        alias=e['alias'],
29        **e['template_options']
30    )
31
32class State:
33    pass
34
35
36# State variable for WAYF kid file set-up
37c = State()
38c.openid = 'None'
39c.title = "Where are You From?"
40c.xml = ''
41c.doc = 'logged in'
42c.providers = {}
43
44import base64
45
46def make_template():
47    '''Make kid template for OpenID login - the NDG WAYF piggy backs this.
48   
49    It's triggered by a HTTP 401 authorisation error and called explicitly
50    via the WAYF controller'''
51   
52    g = config['pylons.g']
53   
54    # Check for return from OpenID login
55    try:
56        userSet = 'REMOTE_USER' in request.environ
57    except TypeError, e:
58        # Request object may not be registered - crude fix here wrapping it a
59        # catch
60        # TODO: referencing environ outside a controller
61        log.info("Keying 'REMOTE_USER' in request.environ: %s" % e)
62        userSet = False
63       
64    if userSet:
65        if not g.ndg.security.common.sso.state.returnToURL:
66            log.error("No returnToURL set for redirect following OpenID " + \
67                      "login")
68        else:
69            log.info("Redirecting to [%s] following OpenID login ..." % \
70                     g.ndg.security.common.sso.state.returnToURL)
71            h.redirect_to(g.ndg.security.common.sso.state.returnToURL)
72
73    state = g.ndg.security.common.sso.state
74    cfg =  g.ndg.security.common.sso.cfg
75   
76    # Set encoded return to address - ensure login can return to an address
77    # over https to preserve confidentiality of credentials
78    # TODO: revisit - at the moment a redirect back from https -> http at the
79    # client to the IdP is rejected
80#    if state.returnToURL and cfg.server in state.returnToURL:
81#        state.returnToURL = state.returnToURL.replace(cfg.server,
82#                                                      cfg.sslServer)
83#        log.debug("make_template: switched return to address to https = %s" % \
84#                                                            state.returnToURL)
85
86    state.b64encReturnToURL = base64.urlsafe_b64encode(str(state.returnToURL))       
87   
88    # Retrieve IdP details
89    _getTrustedIdPs(g)
90   
91    return _render("ndg.security.wayf", h=h, g=g, c=c)
92
93
94def _render(templateName, **kw):
95    '''TODO: Wrapper to enable substitution of $message and $css_class used by
96    AuthKit open_id module'''
97    rendering = buffet.render('ndg.security.kid', 
98                              template_name=templateName,
99                              namespace=kw)
100    # Add $message and $css_class here somehow
101    return rendering
102
103
104from ndg.security.server.wsgi.utils.attributeauthorityclient import \
105    WSGIAttributeAuthorityClient
106
107def _getTrustedIdPs(g):
108    '''Retrieve list of trusted login sites for user to select - calls
109    Attribute Authority WS'''
110
111    # Get references to globals
112    state = g.ndg.security.common.sso.state
113    cfg =  g.ndg.security.server.sso.cfg
114                               
115    # Check for cached copy and return if set to avoid recalling
116    # Attribute Authority - This has the consequence that if the list
117    # of trusted hosts in the Map Configuration changes, the Attribute
118    # Authority and THIS service must be restarted.
119    if len(g.ndg.security.server.sso.state.trustedIdPs) > 0:
120        return _render('ndg.security.wayf', h=h, g=g, c=c)
121   
122    log.debug("Initialising connection to Attribute Authority [%s]" % \
123              cfg.aaURI)
124   
125    try:
126        aaClnt = WSGIAttributeAuthorityClient(
127                                        environ=pylons.request.environ,
128                                        uri=cfg.aaURI,
129                                        environKey=self.cfg.aaEnvironKey,
130                                        tracefile=cfg.tracefile,
131                                        httpProxyHost=cfg.httpProxyHost,
132                                        noHttpProxyList=cfg.noHttpProxyList,
133                                        **cfg.wss)
134    except Exception, e:
135        c.xml='Error establishing security context.  Please report ' + \
136              'the error to your site administrator'
137        log.error("Initialising AttributeAuthorityClient for " + \
138                  "getAllHostsInfo call: %s" % e)
139        return _render('ndg.security.error', h=h, g=config['pylons.g'], c=c)
140       
141    # Get list of login uris for trusted sites including THIS one
142    log.debug("Calling Attribute Authority getAllHostsInfo for wayf ...")
143
144    try:
145        hosts = aaClnt.getAllHostsInfo() 
146    except Exception, e:
147        c.xml='Error getting a list of trusted sites for login.  ' + \
148            'Please report the error to your site administrator.'
149        log.error("AttributeAuthorityClient getAllHostsInfo call: %s" % e) 
150        return _render('ndg.security.error', h=h, g=config['pylons.g'], c=c)
151       
152    g.ndg.security.server.sso.state.trustedIdPs = \
153                        dict([(k, v['loginURI']) for k, v in hosts.items()])
154
155
156from ndg.security.common.pylons.security_util import setSecuritySession
157from urlparse import urlsplit
158
159def url2user(environ, url):
160    '''Function picked up by authkit.openid.urltouser config setting.  It
161    sets a username from the users OpenID URL following login'''
162    log.info("OpenID sign in with [%s]" % url)
163   
164    # Remove protocol prefix and strip /'s
165    username = ''.join(urlsplit(url)[1:]).strip('/').replace('/', '-')
166    return username
Note: See TracBrowser for help on using the repository browser.