Ignore:
Timestamp:
24/05/06 20:03:22 (13 years ago)
Author:
pjkersha
Message:

NDG/SecurityCGI.py: rationalised from original code taken from xDomainCredTransfer.py. Needs
testing.

NDG/Session.py: added class methods to UserSession? for NDG security sessino cookie handling.

createSecurityCookie - makes a new cookie
isValidSecuirtyCookie - checks an existing cookie to see if it has the write tags for an NDG
security cookie.

These have been made class methods so that they can by called without making a UserSession?
instance. This is useful for creating a new cookie from an existing one as is needed when
cookie information is communicated across domains.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • TI12-security/trunk/python/NDG/SecurityCGI.py

    r986 r1005  
    1212version 1.0 or later. 
    1313""" 
    14  
    15 from NDG.SecurityClient import * 
    1614from Cookie import SimpleCookie 
    1715 
     
    2018import os 
    2119 
    22  
     20from NDG.SecurityClient import * 
     21from NDG.Session import UserSession  
     22from NDG.Session import UserSessionError 
     23 
     24 
     25class SecurityCGIError(Exception): 
     26    """Exception handling for NDG Security CGI class.""" 
     27     
     28    def __init__(self, msg): 
     29        self.__msg = msg 
     30          
     31    def __str__(self): 
     32        return self.__msg 
     33 
     34    
    2335class SecurityCGI(cgi.FieldStorage): 
    24     """CGI interface class for NDG Security""" 
     36    """CGI interface class for NDG Security 
     37     
     38    Terms used throughout:         
     39        remote site     - where user is accessing resources 
     40        home site       - where user's credentials are held or they login""" 
    2541 
    2642    #_________________________________________________________________________ 
    2743    def __init__(self, 
     44                 smWSDL, 
     45                 userName=None, 
     46                 passPhrase=None, 
     47                 smPubKeyFilePath=None, 
     48                 clntPubKeyFilePath=None, 
     49                 clntPriKeyFilePath=None, 
     50                 clntPriKeyPwd=None, 
     51                 aaPubKey=None, 
    2852                 scriptName=None, 
    29                  sessMgrWSDLuri=None, 
    3053                 returnURI=None,  
    31                  trustedHosts=None,  
    32                  **kwargs): 
     54                 trustedHosts=None, 
     55                 wsDebug=False, 
     56                 **cgiFieldStorageKwArgs): 
    3357        """scriptName:        name of script to call in forms - defaults to 
    3458                              this file.  Modify if you inherit from this 
    3559                              class. 
    36         sessMgrWSDLuri:    URI For Session Manager WSDL used for user  
     60        smWSDL:    URI For Session Manager WSDL used for user  
    3761                              authentication 
    3862        returnURI:            the address to redirect back to following a  
     
    4165                              credentials 
    4266        trustedHosts:         dictionary of URIs for trusted hosts indexed by 
    43                               hostname""" 
     67                              hostname 
     68        wsDebug:              print output from WS transactions to stderr""" 
     69         
     70        self.smWSDL = smWSDL 
     71        self.userName = userName 
     72        self.passPhrase = passPhrase 
     73        self.smPubKeyFilePath = smPubKeyFilePath 
     74        self.clntPubKeyFilePath = clntPubKeyFilePath 
     75        self.clntPriKeyFilePath = clntPriKeyFilePath 
     76        self.clntPriKeyPwd = clntPriKeyPwd 
     77        self.__aaPubKey = aaPubKey 
    4478         
    4579        if scriptName: 
     
    4882            self.scriptName = __file__ 
    4983             
    50         self.sessMgrWSDLuri = sessMgrWSDLuri 
    5184        self.returnURI = returnURI 
    5285        self.trustedHosts = trustedHosts 
     86        self.__wsDebug = False 
    5387        self.__authorisationMethod = None 
    5488         
    55         cgi.FieldStorage.__init__(self, **kwargs) 
     89        cgi.FieldStorage.__init__(self, **cgiFieldStorageKwArgs) 
    5690 
    5791  
     
    6498            self.requestCreds(**kwargs) 
    6599     
    66         elif 'NDG-ID1' in self and 'NDG-ID2' in self: 
    67             # Receive credentials back from home site 
     100        elif 'NDG-ID1' in self and 'NDG-ID2' in self and 'expires' in self: 
     101            # Receive credentials back from home site and set a new cookie at 
     102            # remote site 
    68103            self.receiveCredsResponse(self['NDG-ID1'].value,  
    69                                       self['NDG-ID2'].value) 
    70      
    71         elif 'setCookie' in self and 'returnURI' in self: 
    72             # User has logged on at home site and a cookie is now to be set -  
     104                                      self['NDG-ID2'].value, 
     105                                      self['NDG-ID2']['expires'],  
     106                                      **kwargs) 
     107     
     108        elif 'authenticate' in self: 
     109            # User has logged on at home site and a cookie is now set -  
    73110            # next step is processCredsRequest() below 
    74             self.setCookie(returnURI=self['returnURI'].value) 
    75      
     111            sessCookie = self.authenticate() 
     112             
     113            if 'returnURI' in self: 
     114                # Authentication is required following a redirect from  
     115                # another site - redirect back to the remote site returning 
     116                # the cookie information 
     117                self.processCredsRequest(sessCookie=sessCookie, 
     118                                         setCookie=True,  
     119                                         **kwargs) 
     120                 
    76121        elif 'returnURI' in self: 
    77122            # Home site receives request from remote site for credentials and 
     
    79124            self.processCredsRequest(**kwargs) 
    80125        else: 
     126            # Remote site presents possible sites for user to get their  
     127            # credentials from 
    81128            self.showHomeSiteSelect(**kwargs) 
    82129     
     
    124171     
    125172    #_________________________________________________________________________ 
    126     def receiveCredsResponse(self, sessID, sessMgrURI): 
     173    def receiveCredsResponse(self,  
     174                             sessID, 
     175                             sessMgrURI,  
     176                             expiry, 
     177                             pageTitle='', 
     178                             hdrTxt='', 
     179                             bodyTxt=''): 
    127180        """Remote site receives returned credentials and creates a new cookie  
    128181        for its domain""" 
    129         self.setCookie(sessID, sessMgrURI) 
    130      
    131      
    132     #_________________________________________________________________________ 
    133     def processCredsRequest(self, **returnCredsKwArgs): 
     182     
     183        sessCookie = UserSession.createSecurityCookie(sessID, 
     184                                                      sessMgrURI, 
     185                                                      expiryStr=expiry) 
     186     
     187        print """Content-type: text/html" 
     188%s 
     189 
     190<html> 
     191<head> 
     192<title>%s</title> 
     193%s 
     194</head> 
     195<body> 
     196    %s 
     197</body> 
     198</html>""" % (sessCookie.output(), pageTitle, hdrTxt, bodyTxt) 
     199     
     200     
     201    #_________________________________________________________________________ 
     202    def processCredsRequest(self,  
     203                            returnURI=None,  
     204                            sessCookie=None,  
     205                            **returnCredsKwArgs): 
    134206        """Receive request from remote site for credentials.  Process and  
    135207        return via a redirect""" 
    136                  
     208 
     209        if returnURI is None: 
     210            returnURI = self['returnURI'].value 
     211                                                          
    137212        # Check for cookie in environment 
    138213        if 'HTTP_COOKIE' in os.environ: 
     214     
     215            # Get session ID from existing cookie 
     216            sessCookie = SimpleCookie(os.environ['HTTP_COOKIE']) 
     217 
     218         
     219        if sessCookie: 
    139220            # Cookie is set - check for NDG cookie 
    140      
    141             # Get session ID from existing cookie 
    142             cookie = SimpleCookie(os.environ['HTTP_COOKIE']) 
    143             if "NDG-ID1" not in cookie: 
    144                 raise Exception, 'Expecting "NDG-ID1" ID for session cookie' 
    145      
    146             if "NDG-ID2" not in cookie: 
    147                 raise Exception, 'Expecting "NDG-ID2" ID for session cookie' 
    148      
    149             self.returnCreds(cookie["NDG-ID1"].value, 
    150                              cookie["NDG-ID2"].value, 
    151                              **returnCredsKwArgs) 
     221            try: 
     222                UserSession.isValidSecurityCookie(sessCookie, raiseExcep=True) 
     223                 
     224            except UserSessionError, e: 
     225                raise SecurityCGIError, \ 
     226                                    'Checking existing session cookie: %s' % e 
     227 
     228            # Return cookie to requestor 
     229            self.returnCreds(sessCookie, returnURI, **returnCredsKwArgs) 
     230             
    152231        else: 
    153232            # No cookie present - display login.  Submit must redirect back to 
    154             # sender 
    155             print """Content-type: text/html 
    156      
    157     """ 
    158             showLogin(self.returnURI, 
    159                       setCookie=True, 
    160                       pageTitle="Login", 
    161                       htmlTag=True, 
    162                       bodyTag=True) 
    163  
    164      
    165     #_________________________________________________________________________ 
    166     def returnCreds(self,  
    167                     sessID, 
    168                     sessMgrURI, 
     233            # this script with '?authenticate=1&returnURI=<...>' 
     234            self.showLogin(returnURI=returnURI, 
     235                           setCookie=True, 
     236                           contentTypeHdr=True, 
     237                           pageTitle="NDG Login", 
     238                           htmlTag=True, 
     239                           bodyTag=True) 
     240 
     241     
     242    #_________________________________________________________________________ 
     243    def returnCreds(self, 
     244                    sessCookie,  
     245                    returnURI=None, 
    169246                    pageTitle='', 
     247                    hdrTxt='', 
    170248                    delayTime=0, 
    171                     redirectMsg=''): 
     249                    redirectMsg='', 
     250                    setCookie=False): 
    172251        """User's home site returns credentials to requestor via a HTTP  
    173252        redirect 
    174253         
    175         sessID:       NDG Session ID from cookie 
    176         sessMgrURI:   NDG Session Manager WSDL URI derived from cookie 
     254        sessCookie:   NDG Session cookie 
    177255        pageTitle:    Give the redirect page a title 
    178256        headTags:     Optionally add additional tags in <head/> section 
     
    181259        redirectMsg:  Message to put on redirect page.  Can be plain text or 
    182260                      formatted HTML""" 
    183      
     261 
     262        if returnURI is None: 
     263            returnURI = self['returnURI'].value 
     264                                          
     265        if setCookie: 
     266            cookieTxt = sessCookie.output() + os.line_sep() 
     267        else: 
     268            cookieTxt = '' 
     269             
    184270        print """Content-type: text/html 
    185      
     271%s     
    186272<html> 
    187273<head> 
    188274<title>%s</title> 
    189 <meta http-equiv="REFRESH" content="%d; url=%s?NDG-ID1=%s&NDG-ID2=%s"> 
     275<meta http-equiv="REFRESH"  
     276content="%d; url=%s?NDG-ID1=%s&NDG-ID2=%s&expires=%s"> 
    190277%s 
    191278</head> 
     
    193280%s 
    194281</body> 
    195 </html>""" % \ 
    196 (pageTitle, delayTime, self.returnURI, sessID,sessMgrURI,headTags,redirectMsg) 
    197      
    198      
    199     #_________________________________________________________________________ 
    200     def setCookie(self, sessID=None, sessMgrURI=None, returnURI=None): 
    201         """Make NDG cookie""" 
    202      
    203         cookie = SimpleCookie() 
    204          
    205         # TODO: Replace with call to SessionMgr WS 
    206         if not sessID: sessID = base64.b64encode(os.urandom(128)) 
    207         if not sessMgrURI: sessMgrURI = base64.b64encode(os.urandom(32)) 
    208      
    209         cookie['NDG-ID1'] = sessID 
    210         cookie['NDG-ID1']['expires'] = "Tue, 13-12-2006 12:00:00 GMT" 
    211         cookie['NDG-ID2'] = sessMgrURI 
    212         cookie['NDG-ID2']['expires'] = "Tue, 13-12-2006 12:00:00 GMT" 
    213      
    214         if returnURI: 
    215             returnURIfield = """<meta http-equiv=\"REFRESH\" 
    216             content=\"0;url=./xDomainCredsTransfer.py?returnURI=%s\">""" % \ 
    217                                                                     returnURI 
    218         else: 
    219             returnURIfield = '' 
    220      
    221         print "Content-type: text/html" 
    222         print cookie.output() + os.linesep + os.linesep 
    223         print """<html> 
    224     <head> 
    225     <title>Set Cookie</title> 
    226     %s 
    227     </head> 
    228      
    229     <body> 
    230         <h1>Cookie set!</h1> 
    231     </body> 
    232     </html>""" % returnURIfield 
    233      
     282</html>""" % ( cookieTxt, 
     283               pageTitle,  
     284               delayTime,  
     285               returnURI,  
     286               sessCookie['NDG-ID1'].value, 
     287               sessCookie['NDG-ID2'].value, 
     288               base64.b64encode(sessCookie['NDG-ID1']['expires']), 
     289               redirectMsg)     
     290     
     291     
     292    #_________________________________________________________________________ 
     293    def authenticate(self, bAuthorise=False): 
     294        """Authenticate username and passphrase input from preceeding login 
     295        form 
     296 
     297        bAuthorise: set to True so that if an error occurs, login will be 
     298                    recalled followed by authorisation""" 
     299 
     300        if self.__wsDebug: 
     301            traceFile = sys.stderr 
     302        else: 
     303            traceFile = None 
     304 
     305 
     306        if 'userName' in self: 
     307            self.userName = self['userName'].value 
     308             
     309        if 'passPhrase' in self: 
     310            self.passPhrase = self['passPhrase'].value 
     311             
     312             
     313        if self.userName is None: 
     314            raise SecurityCGIError("no username set for authentication") 
     315 
     316        if self.passPhrase is None: 
     317            raise SecurityCGIError("no pass-phrase set for authentication") 
     318 
     319 
     320        # Instantiate WS proxy and request connection 
     321        try: 
     322            smClient = SessionClient( 
     323                                smWSDL=self.smWSDL, 
     324                                smPubKeyFilePath=self.smPubKeyFilePath, 
     325                                clntPubKeyFilePath=self.clntPubKeyFilePath, 
     326                                clntPriKeyFilePath=self.clntPriKeyFilePath, 
     327                                traceFile=traceFile) 
     328 
     329            return smClient.connect(userName=self.userName, 
     330                                    pPhrase=self.passPhrase, 
     331                                    clntPriKeyPwd=self.clntPriKeyPwd) 
     332        except Exception, e: 
     333            raise SecurityCGIError("Session client: " + str(e)) 
     334             
    234335     
    235336    #_________________________________________________________________________ 
    236337    def showLogin(self, 
    237338                  returnURI=None, 
    238                   setCookie=False, 
     339                  contentTypeHdr=False, 
    239340                  htmlTag=False, 
    240                   pageTitle=None, 
     341                  pageTitle='', 
    241342                  hdrTxt='', 
     343                  headTag=False, 
    242344                  bodyTag=False, 
    243345                  bAuthorise=False): 
    244346        """Display initial NDG login form""" 
    245347     
     348        if contentTypeHdr: print "Content-type: text/html\n\n" 
     349         
    246350        if htmlTag: print "<html>" 
    247351     
    248         if pageTitle: 
     352        if headTag: 
     353            if not hdrTxt: 
     354                hdrTxt = """    <style type=\"text/css\"> 
     355<!-- 
     356.al { 
     357text-align: justify 
     358} 
     359a{ 
     360text-decoration:none; 
     361} 
     362a:hover{ 
     363color:#0000FF; 
     364} 
     365    body { font-family: Verdana, sans-serif; font-size: 11} 
     366    table { font-family: Verdana, sans-serif; font-size: 11} 
     367--> 
     368</style>""" 
     369                     
    249370            print """<head> 
    250371        <title>%s</title> 
     
    260381        else: 
    261382            returnURIfield = '' 
    262      
    263      
    264         if setCookie: 
    265             setCookieField = "<input type=hidden name=setCookie value=\"1\">" 
    266         else: 
    267             setCookieField = '' 
    268      
     383         
    269384     
    270385        if bAuthorise: 
     
    328443        </td> 
    329444    </tr> 
    330     %s 
    331     %s"""  % (self.scriptName, returnURIfield, setCookieField) 
     445    <input type=hidden name=authenticate value="1"> 
     446    %s"""  % (self.scriptName, returnURIfield) 
    332447     
    333448        print \ 
     
    396511        if contentTypeHdr: 
    397512            print "Content-type: text/html\n\n" 
    398      
     513                 
    399514        if htmlTag: 
    400515            print "<html>\n" 
    401516 
    402         if hdrTag: 
     517        if hdrTag:             
     518            if not hdrTxt: 
     519                hdrTxt = """    <style type=\"text/css\"> 
     520<!-- 
     521.al { 
     522text-align: justify 
     523} 
     524a{ 
     525text-decoration:none; 
     526} 
     527a:hover{ 
     528color:#0000FF; 
     529} 
     530    body { font-family: Verdana, sans-serif; font-size: 11} 
     531    table { font-family: Verdana, sans-serif; font-size: 11} 
     532--> 
     533</style>""" 
     534 
    403535            print """<head> 
    404536             
Note: See TracChangeset for help on using the changeset viewer.