source: TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/login.py @ 3503

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/trunk/ows_server/ows_server/controllers/login.py@3503
Revision 3503, 12.1 KB checked in by cbyrom, 12 years ago (diff)

Further tidy up of existing code: remove History, cart and selection templates
and remove leftPanel template function and its references. Also remove selection.py
and tabs.py and clear out any associated code.

Line 
1import sys,cgi
2from urlparse import urlsplit, urlunsplit
3import base64
4
5from ows_server.lib.base import *
6from ows_server.lib.security_util import setSecuritySession, SecuritySession,\
7                                         LoginServiceQuery
8from ows_common.exception_report import OwsError
9from paste.request import parse_querystring
10import logging
11log = logging.getLogger(__name__)
12
13from ndg.security.common.AttAuthority import AttAuthorityClient
14from ndg.security.common.SessionMgr import SessionMgrClient, SessionExpired, \
15    AttributeRequestDenied
16from ndg.security.common.m2CryptoSSLUtility import HTTPSConnection, \
17    HostCheck, InvalidCertSignature, InvalidCertDN
18
19
20class LoginController(BaseController):
21    ''' Provides the pylons controller for local login '''
22   
23    def __before__(self, action): 
24        """For each action, get 'r' return to URL argument from current URL
25        query string.  c.returnTo is used in some of the .kid files"""
26        c.returnTo = request.params.get('r', '')
27       
28        # Check return to address - getCredentials should NOT be returned to
29        # with its query args intact
30        b64decReturnTo = base64.urlsafe_b64decode(c.returnTo)
31        scheme, netloc, pathInfo, query, frag = urlsplit(b64decReturnTo)
32        if 'getCredentials' in pathInfo:
33            # Swap to discovery and remove sensitive creds query args
34            #
35            # TODO: re-write to be more robust and modular.  Nb.
36            # BaseController.__call__ should filter out 'getCredentials'
37            # calls from c.requestURL so this code should never need to be
38            # executed.
39            filteredReturnTo = urlunsplit((scheme,netloc,'/discovery','',''))
40            c.returnTo = base64.urlsafe_b64encode(filteredReturnTo)
41       
42        # Check return to address - getCredentials should NOT be returned to
43        # with its query args intact
44        log.debug("LoginController.__before__: Decoded c.returnTo = %s" % \
45                                      base64.urlsafe_b64decode(c.returnTo))
46   
47   
48    def index(self):
49        ''' Ok, you really want to login here '''
50        log.debug("LoginController.index ...")   
51
52        if 'ndgSec' not in session: 
53            log.debug('No security session details found - offering login...')
54            return render_response('login')
55       
56        # Session is set in this domain - check it
57        try:   
58            smClnt = SessionMgrClient(uri=session['ndgSec']['h'],
59                    sslCACertFilePathList=g.securityCfg.sslCACertFilePathList,
60                    sslPeerCertCN=g.securityCfg.sslPeerCertCN,
61                    signingCertFilePath=g.securityCfg.wssCertFilePath,
62                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath,
63                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd,
64                    caCertFilePathList=g.securityCfg.wssCACertFilePathList,
65                    tracefile=g.securityCfg.tracefile)
66                               
67        except Exception, e:
68            c.xml='Error establishing security context.  Please report ' + \
69                  'the error to your site administrator'
70            log.error("Initialising SessionMgrClient for " + \
71                      "getSessionStatus call: %s" % e)
72            SecuritySession.delete()
73            return Response(render('content'), code=400)
74       
75        # Check session status
76        log.debug('Calling Session Manager "%s" getSessionStatus ' % \
77                  session['ndgSec']['h'] + 'for user "%s" with sid="%s" ...'%\
78                  (session['ndgSec']['u'], session['ndgSec']['sid']))
79        try:
80            bSessOK = smClnt.getSessionStatus(sessID=session['ndgSec']['sid'])
81        except Exception, e:
82            c.xml = "Error checking your session details.  Please re-login"
83            log.error("Session Manager getSessionStatus returned: %s" % e)
84            SecuritySession.delete()
85            return Response(render('login'), code=401)
86   
87        if bSessOK:
88            log.debug("Session found - redirect back to site requesting " + \
89                      "credentials ...")
90            # ... Return across http GET passing security parameters...
91            return self.__doRedirect()
92        else:
93            log.debug("Session wasn't found - removing security details " + \
94                      "from cookie and re-displaying login...")
95            SecuritySession.delete()
96            return render_response('login')
97
98
99    def getCredentials(self):
100        """Authenticate user and cache user credentials in
101        Session Manager following user login"""
102        log.debug("LoginController.getCredentials ...")   
103
104        try:   
105            smClnt = SessionMgrClient(uri=g.securityCfg.smURI,
106                    sslCACertFilePathList=g.securityCfg.sslCACertFilePathList,
107                    sslPeerCertCN=g.securityCfg.sslPeerCertCN,
108                    signingCertFilePath=g.securityCfg.wssCertFilePath,
109                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath,
110                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd,
111                    caCertFilePathList=g.securityCfg.wssCACertFilePathList,
112                    tracefile=g.securityCfg.tracefile)
113                               
114            username = request.params['username']
115            passphrase = request.params['passphrase']                     
116                               
117        except Exception, e:
118            c.xml='Error establishing security context.  Please report ' + \
119                  'the error to your site administrator'
120            log.error("Login: initialising SessionMgrClient: %s" % e)
121            return Response(render('content'), code=400)
122       
123        # Connect to Session Manager
124        log.debug('Calling Session Manager "%s" connect for user "%s" ...' % \
125                  (g.securityCfg.smURI, username))
126        try:
127            sessID = smClnt.connect(username, passphrase=passphrase)[-1]
128        except Exception, e:
129            c.xml = "Error logging in.  Please check your username/" + \
130                    "pass-phrase and try again."
131            log.error("Session Manager connect returned: %s" % e)
132            return Response(render('login'), code=401)
133       
134        # Cache user attributes in Session Manager
135        log.debug("Calling Session Manager getAttCert for user ")
136        try:
137            # Make request for attribute certificate
138            attCert = smClnt.getAttCert(sessID=sessID, 
139                                        attAuthorityURI=g.securityCfg.aaURI)
140        except SessionExpired, e:
141            log.info("Session expired getting Attribute Certificate: %s" % e)
142            c.xml = "Session has expired, please re-login"
143            return Response(render('login'), code=401)
144           
145        except AttributeRequestDenied, e:
146            log.error("Login: attribute Certificate request denied: %s" % e)
147            c.xml = "No authorisation roles are available for your " + \
148                    "account.  Please check with your site administrator."
149            return Response(render('login'), code=401)
150           
151        except Exception, e:
152            log.error("Login: attribute Certificate request: %s" % e)
153            c.xml = "An internal error occured.  Please report this to " + \
154                    "your site administrator."
155            return Response(render('login'), code=400)
156
157        log.debug('Completing login...')
158       
159        # Make security session details
160        setSecuritySession(h=g.securityCfg.smURI,
161                           u=username,
162                           org=attCert.issuerName,
163                           roles=attCert.roles,
164                           sid=sessID)
165        session.save()
166
167        log.info("user %s logged in with roles %s" % (session['ndgSec']['u'],
168                                                  session['ndgSec']['roles']))
169        return self.__doRedirect()
170           
171           
172    def wayf(self):
173        ''' NDG equivalent to Shibboleth WAYF '''
174        log.debug("LoginController.wayf ...")   
175
176        # May be better as a 'g' global set-up at start-up?
177        #
178        # tracefile could be removed for production use
179        aaClnt = AttAuthorityClient(uri=g.securityCfg.aaURI,
180                    signingCertFilePath=g.securityCfg.wssCertFilePath,
181                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath,
182                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd,
183                    caCertFilePathList=g.securityCfg.wssCACertFilePathList,
184                    tracefile=g.securityCfg.tracefile)
185
186        # Get list of login uris for trusted sites including THIS one
187        log.debug("Calling Attribute Authority getTrustedHostInfo and " + \
188                  "getHostInfo for wayf")
189
190        hosts = aaClnt.getAllHostsInfo()   
191        c.providers=dict([(k, v['loginURI']) for k, v in hosts.items()])
192       
193        session.save()
194       
195        return render_response('wayf')
196       
197       
198    def __doRedirect(self):
199        """Pass security creds back to requestor so that they can make
200        a cookie.  If the requestor is in the same domain as the login then
201        this is not necessary."""
202       
203        # and now go back to whence we had come
204        if c.returnTo!='':
205            # is there a keyword on redirect_to that can make this https? See:
206            # http://pylonshq.com/project/pylonshq/browser/Pylons/trunk/pylons/decorators/secure.py#L69
207
208            # Only add token if return URI is in a different domain
209            thisHostname = request.host.split(':')[0]
210           
211            # Decode return to address
212            cc = base64.urlsafe_b64decode(c.returnTo)
213            log.debug('Login redirect to [%s]' % cc)
214
215            returnToHostname = urlsplit(cc)[1]
216#            returnToHostname = 'localhost'
217#            if thisHostname not in returnToHostname:
218            if True:
219                # Returning to a different domain - copy the security session
220                # details into the URL query string
221                if '?' in cc:
222                    cc+='&%s' % LoginServiceQuery()
223                else:
224                    cc+='?%s' % LoginServiceQuery()
225           
226            # Check return-to address by examining peer cert
227            log.debug("Checking return-to URL for valid SSL peer cert. ...")
228           
229            # Look-up list of Cert DNs for trusted requestors
230            aaClnt = AttAuthorityClient(uri=g.securityCfg.aaURI,
231                    signingCertFilePath=g.securityCfg.wssCertFilePath,
232                    signingPriKeyFilePath=g.securityCfg.wssPriKeyFilePath,
233                    signingPriKeyPwd=g.securityCfg.wssPriKeyPwd,
234                    caCertFilePathList=g.securityCfg.wssCACertFilePathList,
235                    tracefile=g.securityCfg.tracefile)
236           
237            HostInfo = aaClnt.getAllHostsInfo()
238            requestServerDN = [val['loginRequestServerDN'] \
239                               for val in HostInfo.values()]
240            log.debug("Expecting DN for SSL peer one of: %s"%requestServerDN)
241            hostCheck=HostCheck(acceptedDNs=requestServerDN,
242                    caCertFilePathList=g.securityCfg.sslCACertFilePathList)           
243            testConnection = HTTPSConnection(returnToHostname, 
244                                             None, 
245                                             postConnectionCheck=hostCheck)
246
247            log.debug('Testing connection to "%s"' % returnToHostname)
248            try:
249                try:
250                    testConnection.connect()
251                except (InvalidCertSignature, InvalidCertDN), e:
252                    log.error("Login: requestor SSL certificate: %s" % e)
253                    c.xml = """Request to redirect back to %s with your
254credentials refused: there is a problem with the SSL certificate of this site.
255  Please report this to your site administrator.""" % returnToHostname
256                    return Response(render('login'), code=400)
257            finally:   
258                testConnection.close()
259
260            log.debug("SSL peer cert. is OK - redirecting to [%s] ..." % cc)
261            h.redirect_to(cc)
262        else:
263            c.xml='<p> Logged in </p>'
264            return render_response('content')
Note: See TracBrowser for help on using the repository browser.