source: TI12-security/trunk/python/ndg.security.server/ndg/security/server/sso/sso/controllers/login.py @ 3754

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.server/ndg/security/server/sso/sso/controllers/login.py@3754
Revision 3754, 10.1 KB checked in by pjkersha, 12 years ago (diff)
Line 
1import logging
2
3from sso.lib.base import *
4from ndg.security.common.pylons.security_util import setSecuritySession, SecuritySession, \
5    LoginServiceQuery
6from ndg.security.common.AttAuthority import AttAuthorityClient
7from ndg.security.common.SessionMgr import SessionMgrClient, SessionExpired, \
8    AttributeRequestDenied
9from ndg.security.common.m2CryptoSSLUtility import HTTPSConnection, \
10    HostCheck, InvalidCertSignature, InvalidCertDN
11
12from base64 import urlsafe_b64decode, urlsafe_b64decode
13
14log = logging.getLogger(__name__)
15
16class LoginController(BaseController):       
17       
18    def index(self):
19        '''Initialise Session Manager client context, check for an existing
20        user session.  If found, redirect back to SSO Client, if not found
21        present login'''
22        log.debug("LoginController.index ...")   
23
24        # Check the return to URL
25        c.b64encReturnTo = str(request.params.get('r', ''))
26       
27        if 'ndgSec' not in session: 
28            log.debug('No security session details found - offering login...')
29            return render('ndg.security.login')
30       
31        # Session is set in this domain - check it
32        try:   
33            smClnt = SessionMgrClient(uri=session['ndgSec']['h'],
34                    tracefile=g.ndg.security.server.ssoservice.cfg.tracefile,
35                    **g.ndg.security.server.ssoservice.cfg.wss)
36                               
37        except Exception, e:
38            c.xml='Error establishing security context.  Please report ' + \
39                  'the error to your site administrator'
40            log.error("Initialising SessionMgrClient for " + \
41                      "getSessionStatus call: %s" % e)
42            SecuritySession.delete()
43            response.status_code = 400
44            return render('ndg.security.login')
45       
46        # Check session status
47        log.debug('Calling Session Manager "%s" getSessionStatus ' % \
48                  session['ndgSec']['h'] + 'for user "%s" with sid="%s" ...'%\
49                  (session['ndgSec']['u'], session['ndgSec']['sid']))
50        try:
51            bSessOK = smClnt.getSessionStatus(sessID=session['ndgSec']['sid'])
52        except Exception, e:
53            c.xml = "Error checking your session details.  Please re-login"
54            log.error("Session Manager getSessionStatus returned: %s" % e)
55            SecuritySession.delete()
56            response.status_code = 400
57            return render('ndg.security.login')
58   
59        if bSessOK:
60            log.debug("Session found - redirect back to site requesting " + \
61                      "credentials ...")
62            # ... Return across http GET passing security parameters...
63            return self._redirect()
64        else:
65            log.debug("Session wasn't found - removing security details " + \
66                      "from cookie and re-displaying login...")
67            SecuritySession.delete()
68            return render('ndg.security.login')
69
70
71    def getCredentials(self):
72        """Authenticate user and cache user credentials in
73        Session Manager following user login"""
74        log.debug("LoginController.getCredentials ...")   
75
76        # Check the return to URL
77        c.b64encReturnTo = str(request.params.get('r', ''))
78
79        if 'username' not in request.params:
80            log.debug("No username set - rendering login...")
81            return render('ndg.security.login')
82       
83        try:   
84            smClnt = SessionMgrClient(\
85                    uri=g.ndg.security.server.ssoservice.cfg.smURI,
86                    tracefile=g.ndg.security.server.ssoservice.cfg.tracefile,
87                    **g.ndg.security.server.ssoservice.cfg.wss)
88                               
89            username = request.params['username']
90            passphrase = request.params['passphrase']                     
91                               
92        except Exception, e:
93            c.xml='Error establishing security context.  Please report ' + \
94                  'the error to your site administrator'
95            log.error("Login: initialising SessionMgrClient: %s" % e)
96            response.status_code = 400
97            return render('ndg.security.login')
98       
99        # Connect to Session Manager
100        log.debug('Calling Session Manager "%s" connect for user "%s" ...' % \
101                  (g.ndg.security.server.ssoservice.cfg.smURI, username))
102        try:
103            sessID = smClnt.connect(username, passphrase=passphrase)[-1]
104        except Exception, e:
105            c.xml = "Error logging in.  Please check your username/" + \
106                    "pass-phrase and try again."
107            log.error("Session Manager connect returned: %s" % e)
108            response.status_code = 401
109            return render('ndg.security.login')
110       
111        # Cache user attributes in Session Manager
112        log.debug("Calling Session Manager getAttCert for user ")
113        try:
114            # Make request for attribute certificate
115            attCert = smClnt.getAttCert(sessID=sessID, 
116                    attAuthorityURI=g.ndg.security.server.ssoservice.cfg.aaURI)
117        except SessionExpired, e:
118            log.info("Session expired getting Attribute Certificate: %s" % e)
119            c.xml = "Session has expired, please re-login"
120            response.status_code = 401
121            return render('ndg.security.login')
122           
123        except AttributeRequestDenied, e:
124            log.error("Login: attribute Certificate request denied: %s" % e)
125            c.xml = "No authorisation roles are available for your " + \
126                    "account.  Please check with your site administrator."
127            response.status_code = 401
128            return render('ndg.security.login')
129           
130        except Exception, e:
131            log.error("Login: attribute Certificate request: %s" % e)
132            c.xml = "An internal error occured.  Please report this to " + \
133                    "your site administrator."
134            response.status_code = 400
135            return render('ndg.security.login')
136
137        log.debug('Completing login...')
138       
139        # Make security session details
140        setSecuritySession(h=g.ndg.security.server.ssoservice.cfg.smURI,
141                           u=username,
142                           org=attCert.issuerName,
143                           roles=attCert.roles,
144                           sid=sessID)
145        session.save()
146
147        log.info("user %s logged in with roles %s" % (session['ndgSec']['u'],
148                                                  session['ndgSec']['roles']))
149        return self._redirect()
150       
151       
152    def _redirect(self):
153        """Pass security creds back to requestor so that they can make
154        a cookie.  If the requestor is in the same domain as the login then
155        this is not necessary."""
156        log.debug("LoginController._redirect...")
157       
158        # This is set in index and getCredentials
159        if c.b64encReturnTo:
160       
161            # Only add token if return URI is in a different domain
162            thisHostname = request.host.split(':')[0]
163           
164            # Decode return to address
165            returnToURL = urlsafe_b64decode(c.b64encReturnTo)
166            log.debug('Login redirect to [%s]' % returnToURL)
167
168            hostnameWithPortNum = urlsplit(returnToURL)[1]
169           
170            # Require hostname with port number striped to test SSL connection
171            # (will default to 443)
172            returnToURLHostname = hostnameWithPortNum.split(':')[0]
173           
174#            if thisHostname not in returnToURLHostname:
175            if True: # Ensure return args in URL regardless
176                # Returning to a different domain - copy the security session
177                # details into the URL query string
178                if '?' in returnToURL:
179                    returnToURL += '&%s' % LoginServiceQuery()
180                else:
181                    returnToURL += '?%s' % LoginServiceQuery()
182           
183            # Check return-to address by examining peer cert
184            log.debug("Checking return-to URL for valid SSL peer cert. ...")
185
186           
187            # Look-up list of Cert DNs for trusted requestors
188            aaClnt = AttAuthorityClient(\
189                    uri=g.ndg.security.server.ssoservice.cfg.aaURI,
190                    tracefile=g.ndg.security.server.ssoservice.cfg.tracefile,
191                    **g.ndg.security.server.ssoservice.cfg.wss)
192           
193            HostInfo = aaClnt.getAllHostsInfo()
194            requestServerDN = [val['loginRequestServerDN'] \
195                               for val in HostInfo.values()]
196            log.debug(\
197            "Attribute Authority [%s] expecting DN for SSL peer one of: %s" % \
198                (g.ndg.security.server.ssoservice.cfg.aaURI, requestServerDN))
199            hostCheck=HostCheck(acceptedDNs=requestServerDN,
200                    caCertFilePathList=g.ndg.security.server.ssoservice.cfg.sslCACertFilePathList)           
201            testConnection = HTTPSConnection(returnToURLHostname, 
202                                             None, 
203                                             postConnectionCheck=hostCheck)
204
205            log.debug('Testing connection to "%s"' % returnToURLHostname)
206            try:
207                try:
208                    testConnection.connect()
209                except (InvalidCertSignature, InvalidCertDN), e:
210                    log.error("Login: requestor SSL certificate: %s" % e)
211                    c.xml = """Request to redirect back to %s with your
212credentials refused: there is a problem with the SSL certificate of this site.
213  Please report this to your site administrator.""" % returnToURLHostname
214                    response.status_code = 400
215                    return render('ndg.security.login')
216            finally:   
217                testConnection.close()
218
219            log.debug("SSL peer cert. is OK - redirecting to [%s] ..." % \
220                                                                returnToURL)
221            # redirect_to doesn't like unicode
222            h.redirect_to(str(returnToURL))
223        else:
224            log.debug(\
225        "LoginController._redirect: no redirect URL set - render login page")
226            c.xml='Logged in'
227            return render('ndg.security.login')
Note: See TracBrowser for help on using the repository browser.