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

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@3897
Revision 3897, 10.5 KB checked in by pjkersha, 12 years ago (diff)

Working version with independent Policy Enforcement Point (Gatekeeper) + Polciy Decision Point for Pylons Browse code stack

python/ndg.security.server/ndg/security/server/sso/sso/controllers/login.py: extra help info in message for login error

python/ndg.security.test/ndg/security/test/wsSecurity/server/echoServer.py: mod to SignatureHandler? init due to change in WSSecurityConfig interface

python/Tests/authtest/authtest/controllers/test2.py,
python/Tests/authtest/authtest/lib/template.py: missed out on last check in

python/ndg.security.common/ndg/security/common/authz/pdp/proftp.py: udpate to init following change to PDPInterface class for browse code

python/ndg.security.common/ndg/security/common/authz/pdp/init.py: PDPInterface takes cfg keyword which can be file path or a ConfigParser? object

python/ndg.security.common/ndg/security/common/authz/pdp/browse.py:

  • fixes to XPath queries.
  • BrowsePDP now does some more of the work done previously by ows_server.models.ndgInterface.GateKeep and queries directly for role and AA values direct from the doc root
  • made fix to WS-Security settings - may be picked up from the same config file as the PDP settings

python/ndg.security.common/ndg/security/common/authz/pep.py,
python/ndg.security.common/ndg/security/common/wsSecurity.py: allow generic cfg keyword for file path / config obj input

Line 
1import logging
2
3from ndg.security.server.sso.sso.lib.base import *
4from ndg.security.common.pylons.security_util import setSecuritySession, \
5    SecuritySession, SSOServiceQuery
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.kid', '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.kid', '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.kid', '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.kid', '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.kid', '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.kid', '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.  If the problem persists " + \
107                    "please contact your site administrator."
108            log.error("Session Manager connect returned: %s" % e)
109            response.status_code = 401
110            return render('ndg.security.kid', 'ndg.security.login')
111       
112        # Cache user attributes in Session Manager
113        log.debug("Calling Session Manager getAttCert for user ")
114        try:
115            # Make request for attribute certificate
116            attCert = smClnt.getAttCert(sessID=sessID, 
117                    attAuthorityURI=g.ndg.security.server.ssoservice.cfg.aaURI)
118        except SessionExpired, e:
119            log.info("Session expired getting Attribute Certificate: %s" % e)
120            c.xml = "Session has expired, please re-login"
121            response.status_code = 401
122            return render('ndg.security.kid', 'ndg.security.login')
123           
124        except AttributeRequestDenied, e:
125            log.error("Login: attribute Certificate request denied: %s" % e)
126            c.xml = "No authorisation roles are available for your " + \
127                    "account.  Please check with your site administrator."
128            response.status_code = 401
129            return render('ndg.security.kid', 'ndg.security.login')
130           
131        except Exception, e:
132            log.error("Login: attribute Certificate request: %s" % e)
133            c.xml = "An internal error occured.  Please report this to " + \
134                    "your site administrator."
135            response.status_code = 400
136            return render('ndg.security.kid', 'ndg.security.login')
137
138        log.debug('Completing login...')
139       
140        # Make security session details
141        setSecuritySession(h=g.ndg.security.server.ssoservice.cfg.smURI,
142                           u=username,
143                           org=attCert.issuerName,
144                           roles=attCert.roles,
145                           sid=sessID)
146        session.save()
147
148        log.debug("session = %s" % session)
149        log.info("user %s logged in with roles %s" % (session['ndgSec']['u'],
150                                                  session['ndgSec']['roles']))
151        return self._redirect()
152       
153       
154    def _redirect(self):
155        """Pass security creds back to requestor so that they can make
156        a cookie.  If the requestor is in the same domain as the login then
157        this is not necessary."""
158        log.debug("LoginController._redirect...")
159       
160        # This is set in index and getCredentials
161        if c.b64encReturnTo:
162       
163            # Only add token if return URI is in a different domain
164            thisHostname = request.host.split(':')[0]
165           
166            # Decode return to address
167            returnToURL = urlsafe_b64decode(c.b64encReturnTo)
168            log.debug('Login redirect to [%s]' % returnToURL)
169
170            hostnameWithPortNum = urlsplit(returnToURL)[1]
171           
172            # Require hostname with port number striped to test SSL connection
173            # (will default to 443)
174            returnToURLHostname = hostnameWithPortNum.split(':')[0]
175           
176#            if thisHostname not in returnToURLHostname:
177            if True: # Ensure return args in URL regardless
178                # Returning to a different domain - copy the security session
179                # details into the URL query string
180                if '?' in returnToURL:
181                    returnToURL += '&%s' % SSOServiceQuery()
182                else:
183                    returnToURL += '?%s' % SSOServiceQuery()
184           
185            # Check return-to address by examining peer cert
186            log.debug("Checking return-to URL for valid SSL peer cert. ...")
187
188           
189            # Look-up list of Cert DNs for trusted requestors
190            aaClnt = AttAuthorityClient(\
191                    uri=g.ndg.security.server.ssoservice.cfg.aaURI,
192                    tracefile=g.ndg.security.server.ssoservice.cfg.tracefile,
193                    **g.ndg.security.server.ssoservice.cfg.wss)
194           
195            HostInfo = aaClnt.getAllHostsInfo()
196            requestServerDN = [val['loginRequestServerDN'] \
197                               for val in HostInfo.values()]
198            log.debug(\
199            "Attribute Authority [%s] expecting DN for SSL peer one of: %s" % \
200                (g.ndg.security.server.ssoservice.cfg.aaURI, requestServerDN))
201           
202            hostCheck = HostCheck(acceptedDNs=requestServerDN,
203                                  caCertFilePathList=\
204                    g.ndg.security.server.ssoservice.cfg.sslCACertFilePathList)
205           
206            testConnection = HTTPSConnection(returnToURLHostname, 
207                                             None, 
208                                             postConnectionCheck=hostCheck)
209
210            log.debug('Testing connection to "%s"' % returnToURLHostname)
211            try:
212                try:
213                    testConnection.connect()
214                except (InvalidCertSignature, InvalidCertDN), e:
215                    log.error("Login: requestor SSL certificate: %s" % e)
216                    c.xml = """Request to redirect back to %s with your
217credentials refused: there is a problem with the SSL certificate of this site.
218  Please report this to your site administrator.""" % returnToURLHostname
219                    response.status_code = 400
220                    return render('ndg.security.kid', 'ndg.security.login')
221            finally:   
222                testConnection.close()
223
224            log.debug("SSL peer cert. is OK - redirecting to [%s] ..." % \
225                                                                returnToURL)
226            # redirect_to doesn't like unicode
227            h.redirect_to(str(returnToURL))
228        else:
229            log.debug(\
230        "LoginController._redirect: no redirect URL set - render login page")
231            c.xml='Logged in'
232            return render('ndg.security.kid', 'ndg.security.login')
Note: See TracBrowser for help on using the repository browser.