source: TI12-security/trunk/python/NDG/SecurityCGI.py @ 1125

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/NDG/SecurityCGI.py@1125
Revision 1125, 28.4 KB checked in by pjkersha, 14 years ago (diff)

ts/xDomainCredsTransfer.py, NDG/SecurityCGI.py, NDG/Session.py, XMLSecDoc.py: use urlsafe_b64encode/
urlsafe_b64decode to allow safe passing of encoded parameters across URIs. Standard b64encode/b64decode
will include + and / symbols which have special meanings (thanks to Netscape :/ )

NDG/SecurityCGI.py: more work on authorisation request handlers.

NDG/AttAuthority.py: improved no local roles to map to error to print comma separated list of roles.

  • Property svn:executable set to *
Line 
1#!/usr/bin/env python
2
3"""NDG Security CGI services
4
5NERC Data Grid Project
6
7P J Kershaw 23/05/06
8
9Copyright (C) 2006 CCLRC & NERC
10
11This software may be distributed under the terms of the Q Public License,
12version 1.0 or later.
13"""
14from Cookie import SimpleCookie
15
16import sys
17import cgi
18import os
19import base64
20
21# Set cookie expiry
22from datetime import datetime
23from datetime import timedelta
24
25from NDG.SecurityClient import *
26from NDG.Session import UserSession
27from NDG.Session import UserSessionError
28
29
30class SecurityCGIError(Exception):
31    """Exception handling for NDG Security CGI class."""
32
33    def __init__(self, msg):
34        self.__msg = msg
35         
36    def __str__(self):
37        return self.__msg
38
39   
40class SecurityCGI(cgi.FieldStorage):
41    """CGI interface class for NDG Security
42   
43    Terms used throughout:       
44        remote site     - where user is accessing resources
45        home site       - where user's credentials are held or they login"""
46
47    #_________________________________________________________________________
48    def __init__(self,
49                 smWSDL,
50                 aaWSDL,
51                 smPubKeyFilePath=None,
52                 aaPubKeyFilePath=None,
53                 clntPubKeyFilePath=None,
54                 clntPriKeyFilePath=None,
55                 clntPriKeyPwd=None,
56                 userName=None,
57                 passPhrase=None,
58                 scriptName=None,
59                 returnURI=None, 
60                 trustedHostInfo=None,
61                 cookieLifetimeHrs=8,
62                 wsDebug=False,
63                 **cgiFieldStorageKwArgs):
64        """scriptName:        name of script to call in forms - defaults to
65                              this file.  Modify if you inherit from this
66                              class.
67        smWSDL:               URI For Session Manager WSDL used for user
68                              authentication
69        aaWSDL:               URI for Attribute Authority WSDL used to get a
70                              list of login URI for trusted hosts
71        returnURI:            the address to redirect back to following a
72                              redirect
73                              to the user's home site to obtain their
74                              credentials
75        trustedHostInfo:      dictionary of URIs for trusted hosts indexed by
76                              hostname
77        cookieLifetimeHrs:    cookie lifetime in hours
78        wsDebug:              print output from WS transactions to stderr"""
79       
80        self.smWSDL = smWSDL
81        self.smClnt = None
82        self.aaWSDL = aaWSDL
83        self.aaClnt = None
84       
85        self.userName = userName
86        self.passPhrase = passPhrase
87       
88        self.smPubKeyFilePath = smPubKeyFilePath
89        self.aaPubKeyFilePath = aaPubKeyFilePath
90       
91        self.clntPubKeyFilePath = clntPubKeyFilePath
92        self.clntPriKeyFilePath = clntPriKeyFilePath
93        self.clntPriKeyPwd = clntPriKeyPwd
94
95        if scriptName:
96            self.scriptName = scriptName
97        else:
98            self.scriptName = __file__
99           
100        self.returnURI = returnURI
101        self.trustedHostInfo = trustedHostInfo
102        self.cookieLifetimeHrs = cookieLifetimeHrs
103
104        # Work out expiry time offset from the time this script is run
105        self.dtCookieExpiry = datetime.utcnow() + \
106                            timedelta(seconds=self.cookieLifetimeHrs*60*60)
107
108        self.__wsDebug = False
109        self._authorisationMethod = None
110
111        self.attCert = None
112       
113       
114        cgi.FieldStorage.__init__(self, **cgiFieldStorageKwArgs)
115
116 
117    #_________________________________________________________________________
118    def processFields(self, **kwargs):
119        """Call appropriate actions according to the fields set"""
120
121        bAuthorise = "authorise" in self
122       
123        if 'requestURI' in self:
124            # Request credentials from user's home site
125            self.requestCreds(**kwargs)
126
127        elif 'NDG-ID1' in self and 'NDG-ID2' in self:
128            # Receive credentials back from home site and set a new cookie at
129            # remote site
130            if 'expires' in self:
131                encodedExpiry = self['expires'].value
132            else:
133                encodedExpiry = None
134
135            self.receiveCredsResponse(self['NDG-ID1'].value,
136                                      self['NDG-ID2'].value,
137                                      encodedExpiry=encodedExpiry,
138                                      **kwargs)
139
140        elif 'authenticate' in self:
141            # User has entered login details - now authenticate using the
142            # Session Manager WS
143            sessCookie = self.authenticate()
144           
145            if bAuthorise:
146
147                # Authorisation and authentication arguments were set
148                # - Call authentication first
149                cookie = self.authenticate(setCookie=False)
150
151                # Call authorisation passing the session ID for authorise to
152                # set the cookie
153                self.getAttCert(cookie)
154           
155            if 'returnURI' in self:
156                # The authentication process is as a result of a redirect
157                # request from another site - redirect back to the remote site
158                # returning the credentials contained in the NDG security
159                self.processCredsRequest(sessCookie=sessCookie,
160                                         setCookie=True, 
161                                         **kwargs)
162               
163        elif bAuthorise:
164            self.getAttCert()
165                   
166        elif 'returnURI' in self:
167            # Home site receives request from remote site for credentials and
168            # returns them
169            self.processCredsRequest(**kwargs)
170        else:
171            # Remote site presents possible sites for user to get their
172            # credentials from
173            self.showHomeSiteSelect(**kwargs)
174   
175   
176    #_________________________________________________________________________
177    # Use instance name as an alias to processFields method
178    __call__ = processFields
179   
180
181    #_________________________________________________________________________
182    def requestCreds(self,
183                     requestURI=None,
184                     pageTitle='',
185                     headTags='',
186                     delayTime=0,
187                     redirectMsg=''):
188        """Request credentials from a user's home site
189       
190        requestURI:   site to request credentials from - default is
191                      'requestURI' CGI form value
192        pageTitle:    Give the redirect page a title
193        headTags:     Optionally add additional tags in <head/> section
194        delayTime:    time in seconds before carrying out redirect - redirect
195                      page will be displayed in this interval
196        redirectMsg:  Message to put on redirect page.  Can be plain text or
197                      formatted HTML"""
198       
199        if requestURI is None:
200            requestURI = self['requestURI'].value
201
202        print """Content-type: text/html
203
204<html>
205<head>
206<title>%s</title>
207<meta http-equiv="REFRESH" content="%d; url=%s?returnURI=%s">
208%s
209</head>
210<body>
211%s
212</body>
213</html>""" % \
214    (pageTitle, delayTime, requestURI, self.returnURI, headTags, redirectMsg)
215
216
217    #_________________________________________________________________________
218    def receiveCredsResponse(self,
219                             sessID,
220                             sessMgrURI,
221                             encodedExpiry=None,
222                             **showCredsReceivedKwArgs):
223        """Remote site receives returned credentials and creates a new cookie
224        for its domain"""
225        sessCookie = self.createCookie(sessID, sessMgrURI, encodedExpiry)
226        self.showCredsReceived(sessCookie)
227
228    #_________________________________________________________________________
229    def showCredsReceived(sessCookie, pageTitle='', hdrTxt='', bodyTxt=''):
230        """Called from receiveCredsResponse() once a cookie has been created.
231        Makes a page to set the cookie and display to the user that they have
232        been authenticated.  Derived class should override this method as
233        required"""
234        print """Content-type: text/html"
235%s
236
237<html>
238<head>
239<title>%s</title>
240%s
241</head>
242<body>
243    %s
244</body>
245</html>""" % (sessCookie.output(), pageTitle, hdrTxt, bodyTxt)
246
247   
248    #_________________________________________________________________________
249    def createCookie(self, sessID, sessMgrURI, encodedExpiry=None):
250        """Convert credentials passed over URI from users home site into a new
251        cookie"""
252
253        if encodedExpiry:
254            # Expiry is taken from encoded value passed over URI
255            dtExpiry = None
256            expiryStr = base64.urlsafe_b64decode(encodedExpiry)
257        else:
258            # Expiry is set from life time in hours input in __init__
259            dtExpiry = self.dtCookieExpiry
260            expiryStr = None
261
262        return UserSession.createSecurityCookie(sessID,
263                                                sessMgrURI,
264                                                dtExpiry=dtExpiry,
265                                                expiryStr=expiryStr)
266
267
268        #_________________________________________________________________________
269    def processCredsRequest(self,
270                            returnURI=None,
271                            bAuthorise=False, 
272                            sessCookie=None, 
273                            **returnCredsKwArgs):
274        """Receive request from remote site for credentials.  Process and
275        return via a redirect"""
276
277        if returnURI is None:
278            returnURI = self['returnURI'].value
279                                                         
280        # Check for cookie in environment
281        if 'HTTP_COOKIE' in os.environ:
282   
283            # Get session ID from existing cookie
284            sessCookie = SimpleCookie(os.environ['HTTP_COOKIE'])
285
286        if sessCookie:
287            # Cookie is set - check for NDG cookie
288            try:
289                UserSession.isValidSecurityCookie(sessCookie, raiseExcep=True)
290               
291            except UserSessionError, e:
292                raise SecurityCGIError, \
293                                    'Checking existing session cookie: %s' % e
294
295            # Return cookie to requestor
296            self.returnCreds(sessCookie, returnURI, **returnCredsKwArgs)
297
298        else:
299            # No cookie present - display login.  Submit must redirect back to
300            # this script with '?authenticate=1&returnURI=<...>'
301            self.showLogin(returnURI=returnURI,
302                           bAuthorise=bAuthorise, 
303                           pageTitle="NDG Login")
304
305   
306    #_________________________________________________________________________
307    def returnCreds(self,
308                    sessCookie, 
309                    returnURI=None,
310                    pageTitle='',
311                    hdrTxt='',
312                    delayTime=0,
313                    redirectMsg='',
314                    setCookie=False):
315        """User's home site returns credentials to requestor via a HTTP
316        redirect
317       
318        sessCookie:   NDG Session cookie
319        pageTitle:    Give the redirect page a title
320        headTags:     Optionally add additional tags in <head/> section
321        delayTime:    time in seconds before carrying out redirect - redirect
322                      page will be displayed in this interval
323        redirectMsg:  Message to put on redirect page.  Can be plain text or
324                      formatted HTML"""
325
326        if returnURI is None:
327            returnURI = self['returnURI'].value
328                                         
329        if setCookie:
330            cookieTxt = sessCookie.output() + os.linesep
331        else:
332            cookieTxt = ''
333           
334        output = """Content-type: text/html
335%s
336<html>
337<head>
338<title>%s</title>
339<meta http-equiv="REFRESH"
340content="%d; url=%s?NDG-ID1=%s&NDG-ID2=%s&expires=%s">
341%s
342</head>
343<body>
344%s
345</body>
346</html>""" % ( cookieTxt,
347               pageTitle,
348               delayTime,
349               returnURI,
350               sessCookie['NDG-ID1'].value,
351               sessCookie['NDG-ID2'].value,
352               base64.urlsafe_b64encode(sessCookie['NDG-ID1']['expires']),
353               hdrTxt,
354               redirectMsg)
355        print output
356
357
358    #_________________________________________________________________________
359    def authenticate(self, bAuthorise=False):
360        """Authenticate username and passphrase input from preceeding login
361        form
362
363        bAuthorise: set to True so that if an error occurs, login will be
364                    recalled followed by authorisation"""
365
366        if self.__wsDebug:
367            traceFile = sys.stderr
368        else:
369            traceFile = None
370
371
372        if 'userName' in self:
373            self.userName = self['userName'].value
374           
375        if 'passPhrase' in self:
376            self.passPhrase = self['passPhrase'].value
377           
378        if 'returnURI' in self:
379            returnURI = self['returnURI'].value
380        else:
381            returnURI = None
382           
383           
384        if self.userName is None:
385            self.showLogin(returnURI=returnURI,
386                           bAuthorise=bAuthorise,
387                           pageTitle="Login - error no username set")
388            raise SecurityCGIError, "no username set for authentication"
389
390        if self.passPhrase is None:
391            self.showLogin(returnURI=returnURI,
392                           bAuthorise=bAuthorise,
393                           pageTitle="Login - error no pass-phrase set")
394            raise SecurityCGIError, "no pass-phrase set for authentication"
395
396
397        # Instantiate WS proxy and request connection
398        try:
399            if not self.smClnt:
400                self.smClnt = SessionClient(smWSDL=self.smWSDL,
401                                   smPubKeyFilePath=self.smPubKeyFilePath,
402                                   clntPubKeyFilePath=self.clntPubKeyFilePath,
403                                   clntPriKeyFilePath=self.clntPriKeyFilePath,
404                                   traceFile=traceFile)
405
406            sSessCookie = self.smClnt.connect(userName=self.userName,
407                                         pPhrase=self.passPhrase,
408                                         clntPriKeyPwd=self.clntPriKeyPwd)
409            sessCookie = SimpleCookie(sSessCookie)
410            return sessCookie
411
412        except Exception, e:
413            self.showLogin(returnURI=returnURI,
414                           bAuthorise=bAuthorise,
415                           pageTitle="Login - internal error")
416            raise SecurityCGIError, "Session client: " + str(e)
417
418
419    #_________________________________________________________________________
420    def getAttCert(self, sessCookie=None, reqRole=None):
421        """Contact Attribute Authority to get Attribute Certificate for data
422        access
423
424        sessCookie:     NDG security session cookie
425        reqRole:        specify the required role to get authorisation.  Set
426                        this to optimise the process for getting the required
427                        AC from a trusted host in order to perform mapping"""
428
429        if self.__wsDebug:
430            traceFile = sys.stderr
431        else:
432            traceFile = None
433
434
435        # Check for session cookie input
436        if not sessCookie:
437            # No cookie set as input argument check for environment variable
438            if 'HTTP_COOKIE' in os.environ:
439                sessCookie = SimpleCookie(os.environ['HTTP_COOKIE'])   
440            else:
441                raise SecurityCGIError, \
442                    "Attribute certificate request requires a security cookie"
443
444        # Check cookie is valid
445        try:
446            UserSession.isValidSecurityCookie(sessCookie, raiseExcep=True)
447           
448        except UserSessionError, e:
449            raise SecurityCGIError, 'Checking existing session cookie: %s' % e
450
451
452        # Configure flags for attribute certificate request.  This determines
453        # whether mapping of certificates from trusted hosts is allowed
454        if self._authorisationMethod == 'allowMapping':
455            bMapFromTrustedHosts = True
456            bRtnExtAttCertList = False
457
458        elif self._authorisationMethod == 'allowMappingWithPrompt':
459            bMapFromTrustedHosts = False
460            bRtnExtAttCertList = True
461        else:
462            bMapFromTrustedHosts = False
463            bRtnExtAttCertList = False
464
465
466        # Instantiate WS proxy and request authorisation
467        try:
468            if not self.smClnt:
469                self.smClnt = SessionClient(
470                                smWSDL=self.smWSDL,
471                                smPubKeyFilePath=self.smPubKeyFilePath,
472                                clntPubKeyFilePath=self.clntPubKeyFilePath,
473                                clntPriKeyFilePath=self.clntPriKeyFilePath,
474                                traceFile=traceFile)
475
476            resp = self.smClnt.reqAuthorisation(sessCookie=sessCookie,
477                                aaWSDL=self.aaWSDL,
478                                aaPubKey=self.aaPubKey,
479                                reqRole=reqRole,
480                                mapFromTrustedHosts=bMapFromTrustedHosts,
481                                rtnExtAttCertList=bRtnExtAttCertList,
482                                clntPriKeyPwd=self.clntPriKeyPwd)
483        except Exception, e:
484            # Socket error returns tuple - reformat to just give msg
485            raise SecurityCGIError, "Session client: " + str(e)
486
487
488        if resp['statCode'] == 'AccessGranted':
489            self.onAttCertGranted(resp['attCert'])
490       
491        elif resp['statCode'] == 'AccessDenied':
492            self.onAttCertDenied(resp['extAttCertList'], resp['errMsg'])
493           
494        elif resp['statCode'] == 'AccessError':
495            raise SecurityCGIError, resp['errMsg']
496           
497   
498    #_________________________________________________________________________
499    def onAttCertGranted(self, attCert):
500        """Callback invoked by getAttCert - handle case where an Attribute
501        Authority has granted a new attribute certificate to the user.  Derive
502        from this class and override this method as required.
503        """
504        pass
505   
506   
507    #_________________________________________________________________________
508    def onAttCertDenied(self, extAttCertList, errMsg):
509        """Callback invoked by getAttCert - handle case where an Attribute
510        Authority has denied an attribute certificate to the user.  Derive
511        from this class and override this method as required.
512       
513        extAttCertList:    a list of attribute certificates from trusted
514                           hosts.  Any of these could be selected and
515                           presented back to the target AA in order to get
516                           a mapped certificate.  This list may be None if
517                           no ACs could be obtained or if the
518                           mapFromTrustedHosts flag in the call to the Session
519                           Manager WS reqAuthorisation method was set to
520                           False.
521                           
522        errMsg:            the error message returned from the call to the
523                           AA to get an AC."""
524       
525        if not extAttCertList:
526            self.showLogin(pageTitle="Access denied by Attribute Authority")
527            raise SecurityCGIError, errMsg
528       
529        else:
530            # Display list of attCerts to choose from
531            if contentTypeHdr:
532                print "Content-type: text/html\n\n"
533                   
534            if htmlTag:
535                print "<html>\n"
536   
537            if hdrTag:           
538                if not hdrTxt:
539                    hdrTxt = """    <style type=\"text/css\">
540<!--
541.al {
542text-align: justify
543}
544a{
545text-decoration:none;
546}
547a:hover{
548color:#0000FF;
549}
550    body { font-family: Verdana, sans-serif; font-size: 11}
551    table { font-family: Verdana, sans-serif; font-size: 11}
552-->
553</style>"""
554
555                print """<head>
556           
557    <title>%s</title>
558    %s
559</head>""" % (pageTitle, hdrTxt)
560   
561   
562                if bodyTag:
563                    print "<body>\n"
564               
565                print """
566    <form action="%s" method="POST">
567    <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5>
568    <tbody>"""
569                for attCert in extAttCertList:
570                    print \
571"""    <tr>
572        <td>%s</td>
573    </tr>""" % attCert['issuer']
574               
575                print \
576"""    </tbody>
577    </table>
578    </form>"""
579
580                if bodyTag:
581                    print "</body>\n"
582       
583                if htmlTag:
584                    print "</html>\n"
585   
586        # end of handleAttCertDenied()
587
588   
589    #_________________________________________________________________________
590    def showLogin(self,
591                  returnURI=None,
592                  contentTypeHdr=True,
593                  htmlTag=True,
594                  pageTitle='',
595                  hdrTxt='',
596                  headTag=True,
597                  bodyTag=True,
598                  bAuthorise=False):
599        """Display initial NDG login form"""
600   
601        if contentTypeHdr: print "Content-type: text/html\n\n"
602       
603        if htmlTag: print "<html>"
604   
605        if headTag:
606            if not hdrTxt:
607                hdrTxt = """    <style type=\"text/css\">
608<!--
609.al {
610text-align: justify
611}
612a{
613text-decoration:none;
614}
615a:hover{
616color:#0000FF;
617}
618    body { font-family: Verdana, sans-serif; font-size: 11}
619    table { font-family: Verdana, sans-serif; font-size: 11}
620-->
621</style>"""
622                   
623            print """<head>
624        <title>%s</title>
625        %s
626    </head>""" % (pageTitle, hdrTxt)
627   
628   
629        if bodyTag: print "<body>"
630   
631        if returnURI:
632            returnURIfield = \
633                "<input type=hidden name=returnURI value=\"%s\">" % returnURI
634        else:
635            returnURIfield = ''
636       
637   
638        if bAuthorise:
639            authoriseArg = "<input type=hidden name=authorise value=\"1\">"
640        else:
641            authoriseArg = ""
642   
643   
644        # Set authorisation method default
645        authorisationMethodChk = {  "allowMapping":              '',
646                                    "allowMappingWithPrompt" :   '',
647                                    "noMapping":                 ''}
648   
649        if self._authorisationMethod is None:
650            # Default to safest option for user
651            authorisationMethodChk["allowMappingWithPrompt"] = ' checked'
652        else:
653            authorisationMethodChk[self._authorisationMethod] = ' checked'
654   
655        print \
656    """<script language="javascript">
657    <!--
658        function toggleLayer(layerId)
659        {
660            if (document.getElementById)
661            {
662                // Standard
663                var style = document.getElementById(layerId).style;
664            }
665            else if (document.all)
666            {
667                // Old msie versions
668                var style = document.all[whichLayer].style;
669            }
670            else if (document.layers)
671            {
672                // nn4
673                var style = document.layers[whichLayer].style;
674            }
675            style.visibility = style.visibility == "visible" ?
676"hidden":"visible";        }
677    //-->
678    </script>
679    <h3>NERC Data Grid Site Login (Test)<BR clear=all></h3>
680    <hr>
681   
682    <form action="%s" method="POST">
683   
684    <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5>
685    <tbody>
686    <tr><td>User Name:</td> <td><input type=text name=userName value="">
687    </td></tr>
688    <tr>
689        <td>Password:</td>
690        <td><input type=password name=passPhrase></td>
691    </tr>
692    <tr>
693        <td colspan="2" align="right">
694            <a href="javascript:toggleLayer('advSettings');">Advanced
695Settings</a>            <input type=submit value="Login">
696        </td>
697    </tr>
698    <input type=hidden name=authenticate value="1">
699    %s"""  % (self.scriptName, returnURIfield)
700   
701        print \
702    """</tbody></table>
703    <br>
704    <div id="advSettings" style="position: relative; visibility: hidden;">
705        <h4>Role Mapping for access to other trusted sites</h4>
706        <p>Your account has roles or <i>privileges</i> which determine what data
707you have access to.  If you access data at another NDG trusted site, these roles
708can be mapped to local roles at that site to help you gain access:        </p>   
709     <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5>        <tbody>
710        <tr>
711        <td>
712            <input type="radio" name="authorisationMethod"
713value="allowMapping"%s>        </td>
714            <td>
715                Allow my roles to be mapped to local roles at other NDG trusted
716sites.            </td>
717        </tr>
718        <tr>
719            <td>
720                <input type="radio" name="authorisationMethod"
721value="allowMappingWithPrompt"%s>            </td>
722        <td>
723            Allow my roles to be mapped, but prompt me so that I may choose
724which roles to map before gaining access.        </td>
725        <tr>
726        <td>
727            <input type="radio" name="authorisationMethod" value="noMapping"%s>
728        </td>
729        <td>
730            Don't allow mapping of my roles.
731        </td>
732        </tr>
733        </tbody>
734        </table>
735    </div>
736    </form>
737    """ % (authorisationMethodChk['allowMapping'], \
738           authorisationMethodChk['allowMappingWithPrompt'], \
739           authorisationMethodChk['noMapping'])
740   
741        if bodyTag: print "</body>"
742        if htmlTag: print "</html>"
743   
744        # end of showLogin()
745   
746   
747    #_________________________________________________________________________
748    def showHomeSiteSelect(self,
749                           trustedHostInfo=None,
750                           scriptName=None,
751                           contentTypeHdr=False,
752                           htmlTag=False,
753                           hdrTag=False,
754                           hdrTxt='',
755                           bodyTag=False,
756                           pageTitle=""):
757
758        if trustedHostInfo:
759            self.trustedHostInfo = trustedHostInfo
760
761        if not self.trustedHostInfo:
762            self.getTrustedHostInfo()
763           
764        if scriptName:
765            self.scriptName = scriptName
766           
767               
768        if contentTypeHdr:
769            print "Content-type: text/html\n\n"
770               
771        if htmlTag:
772            print "<html>\n"
773
774        if hdrTag:           
775            if not hdrTxt:
776                hdrTxt = """    <style type=\"text/css\">
777<!--
778.al {
779text-align: justify
780}
781a{
782text-decoration:none;
783}
784a:hover{
785color:#0000FF;
786}
787    body { font-family: Verdana, sans-serif; font-size: 11}
788    table { font-family: Verdana, sans-serif; font-size: 11}
789-->
790</style>"""
791
792            print """<head>
793           
794    <title>%s</title>
795    %s
796</head>""" % (pageTitle, hdrTxt)
797   
798   
799        if bodyTag:
800            print "<body>\n"
801
802            print """
803    <form action="%s" method="POST">
804    <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5>
805    <tbody>
806    <tr>
807      <td>
808        <select name="requestURI">       
809          <option value="">Select your home site...""" % self.scriptName
810         
811            for hostname, info in self.trustedHostInfo.items():
812                print "<option value=\"%s\">%s" % (info['loginURI'], hostname)
813               
814            print \
815"""        </select>
816      </td>
817      <td align="right">
818        <input type=submit value="Go">
819      </td>
820    </tr>
821    </tbody>
822    </table>
823    </form>"""
824
825        if bodyTag:
826            print "</body>\n"
827
828        if htmlTag:
829            print "</html>\n"
830   
831        # end of showHomeSiteSelect()
832
833
834    #_________________________________________________________________________
835    def getTrustedHostInfo(self):
836        """Call Attribute Authority to find out trusted hosts.  These can be
837        use to populate list for use to select home site for login"""
838       
839        if self.__wsDebug:
840            traceFile = sys.stderr
841        else:
842            traceFile = None
843
844        try:
845            if not self.aaClnt:
846                self.aaClnt = AttAuthorityClient(aaWSDL=self.aaWSDL,
847                                aaPubKeyFilePath=self.aaPubKeyFilePath,
848                                clntPubKeyFilePath=self.clntPubKeyFilePath,
849                                clntPriKeyFilePath=self.clntPriKeyFilePath,
850                                traceFile=traceFile)
851           
852            self.trustedHostInfo = self.aaClnt.getTrustedHostInfo(
853                                           clntPriKeyPwd=self.clntPriKeyPwd)
854        except Exception, e:
855            raise SecurityCGIError, "Attribute Authority client: " + str(e)
Note: See TracBrowser for help on using the repository browser.