Changeset 1035


Ignore:
Timestamp:
26/05/06 14:53:19 (13 years ago)
Author:
pjkersha
Message:

Tests/SecurityClientTest?.py: minor change to re-test glue AA getTrustedHostInfo

Tests/security.py: WORKING VERSION -

  • fixed showLogin
  • fixed showCredsReceived

dist/NDG-Security-0.66.tar.gz: new version of distribution

NDG/SecurityCGI.py: WORKING VERSION -

  • cookie expiry for new cookie transfered from another domain can be set with cookieLifetimeHrs keyword to init

This is only applies if the 'expires' argument is not set when passed back from trusted host login URL. Only
'NDG-ID1' and 'NDG-ID2' args are needed to pass credential info back to the requestor.

  • receiveCredsResponse broken up into method createCookie() to create a new cookie from the credentials received

in the URL and showCredsReceived method to display a page on completion of the transaction and set the new cookie
in the users browser.

  • authenticate method modified so that if authentication fails, the login page is re-displayed.

NDG/Session.py:

  • UserSession? class reduced sessID length to 64 chars from 128 to keep URL lenght to a minimum when transfering

credentials between domains. ID should be as long as possible to make it difficult to guess.

  • Quoted cookie expiry: sessCookieExpiryFmt = "\"%a, %d-%b-%Y %H:%M:%S GMT\"" as official format reuqires. If not

quoted, SimpleCookie? won't parse it correctly.

Location:
TI12-security/trunk/python
Files:
5 edited

Legend:

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

    r1022 r1035  
    5959                 returnURI=None,  
    6060                 trustedHostInfo=None, 
    61                  cookieLifetimeHrs=12, 
     61                 cookieLifetimeHrs=8, 
    6262                 wsDebug=False, 
    6363                 **cgiFieldStorageKwArgs): 
     
    7070                              list of login URI for trusted hosts 
    7171        returnURI:            the address to redirect back to following a 
    72                               redirect   
     72                              redirect 
    7373                              to the user's home site to obtain their  
    7474                              credentials 
     
    101101 
    102102        # Work out expiry time offset from the time this script is run 
    103         self.dtCookieExpiry = datetime.utcnow() 
    104         self.dtCookieExpiry += timedelta(seconds=self.cookieLifetimeHrs*60*60) 
     103        self.dtCookieExpiry = datetime.utcnow() + \ 
     104                                timedelta(seconds=self.cookieLifetimeHrs*60*60) 
    105105 
    106106        self.__wsDebug = False 
    107         self.__authorisationMethod = None 
     107        self._authorisationMethod = None 
    108108         
    109109        cgi.FieldStorage.__init__(self, **cgiFieldStorageKwArgs) 
     
    121121            # Receive credentials back from home site and set a new cookie at 
    122122            # remote site 
     123            if 'expires' in self: 
     124                encodedExpiry = self['expires'].value 
     125            else: 
     126                encodedExpiry = None 
     127 
    123128            self.receiveCredsResponse(self['NDG-ID1'].value, 
    124129                                      self['NDG-ID2'].value, 
     130                                      encodedExpiry=encodedExpiry, 
    125131                                      **kwargs) 
    126132 
    127133        elif 'authenticate' in self: 
    128             # User has logged on at home site and a cookie is now set -  
     134            # User has logged on at home site and a cookie is now set - 
    129135            # next step is processCredsRequest() below 
    130136            sessCookie = self.authenticate() 
    131137             
    132138            if 'returnURI' in self: 
    133                 # Authentication is required following a redirect from  
     139                # Authentication is required following a redirect from 
    134140                # another site - redirect back to the remote site returning 
    135141                # the cookie information 
     
    158164                     pageTitle='', 
    159165                     headTags='', 
    160                      delayTime=3, 
    161                      redirectMsg='Redirecting'): 
     166                     delayTime=0, 
     167                     redirectMsg=''): 
    162168        """Request credentials from a user's home site 
    163169         
     
    174180            requestURI = self['requestURI'].value 
    175181 
    176         output = """Content-type: text/html 
     182        print """Content-type: text/html 
    177183 
    178184<html> 
     
    187193</html>""" % \ 
    188194    (pageTitle, delayTime, requestURI, self.returnURI, headTags, redirectMsg) 
    189         sys.stderr.write(output) 
    190         print output 
    191      
    192      
     195 
     196 
    193197    #_________________________________________________________________________ 
    194198    def receiveCredsResponse(self, 
    195199                             sessID, 
    196200                             sessMgrURI, 
    197                              pageTitle='', 
    198                              hdrTxt='', 
    199                              bodyTxt=''): 
    200         """Remote site receives returned credentials and creates a new cookie  
     201                             encodedExpiry=None, 
     202                             **showCredsReceivedKwArgs): 
     203        """Remote site receives returned credentials and creates a new cookie 
    201204        for its domain""" 
    202      
    203         sessCookie = UserSession.createSecurityCookie(sessID, 
    204                                                 sessMgrURI, 
    205                                                 dtExpiry=self.dtCookieExpiry) 
    206  
     205        sessCookie = self.createCookie(sessID, sessMgrURI, encodedExpiry) 
     206        self.showCredsReceived(sessCookie) 
     207 
     208    #_________________________________________________________________________ 
     209    def showCredsReceived(sessCookie, pageTitle='', hdrTxt='', bodyTxt=''): 
     210        """Called from receiveCredsResponse() once a cookie has been created. 
     211        Makes a page to set the cookie and display to the user that they have 
     212        been authenticated.  Derived class should override this method as 
     213        required""" 
    207214        print """Content-type: text/html" 
    208215%s 
     
    217224</body> 
    218225</html>""" % (sessCookie.output(), pageTitle, hdrTxt, bodyTxt) 
    219      
    220      
    221     #_________________________________________________________________________ 
    222     def processCredsRequest(self,  
     226 
     227     
     228    #_________________________________________________________________________ 
     229    def createCookie(self, sessID, sessMgrURI, encodedExpiry=None): 
     230        """Convert credentials passed over URI from users home site into a new 
     231        cookie""" 
     232 
     233        if encodedExpiry: 
     234            # Expiry is taken from encoded value passed over URI 
     235            dtExpiry = None 
     236            expiryStr = base64.b64decode(encodedExpiry) 
     237        else: 
     238            # Expiry is set from life time in hours input in __init__ 
     239            dtExpiry = self.dtCookieExpiry 
     240            expiryStr = None 
     241 
     242        return UserSession.createSecurityCookie(sessID, 
     243                                                sessMgrURI, 
     244                                                dtExpiry=dtExpiry, 
     245                                                expiryStr=expiryStr) 
     246 
     247 
     248        #_________________________________________________________________________ 
     249    def processCredsRequest(self, 
    223250                            returnURI=None,  
    224251                            sessCookie=None,  
     
    236263            sessCookie = SimpleCookie(os.environ['HTTP_COOKIE']) 
    237264 
    238          
    239265        if sessCookie: 
    240266            # Cookie is set - check for NDG cookie 
     
    248274            # Return cookie to requestor 
    249275            self.returnCreds(sessCookie, returnURI, **returnCredsKwArgs) 
    250              
     276 
    251277        else: 
    252278            # No cookie present - display login.  Submit must redirect back to 
     
    284310                                          
    285311        if setCookie: 
    286             cookieTxt = sessCookie.output() + os.line_sep() 
     312            cookieTxt = sessCookie.output() + os.linesep 
    287313        else: 
    288314            cookieTxt = '' 
    289315             
    290         print """Content-type: text/html 
    291 %s     
     316        output = """Content-type: text/html 
     317%s 
    292318<html> 
    293319<head> 
    294320<title>%s</title> 
    295321<meta http-equiv="REFRESH" 
    296 content="%d; url=%s?NDG-ID1=%s&NDG-ID2=%s"> 
     322content="%d; url=%s?NDG-ID1=%s&NDG-ID2=%s&expires=%s"> 
    297323%s 
    298324</head> 
     
    306332               sessCookie['NDG-ID1'].value, 
    307333               sessCookie['NDG-ID2'].value, 
     334               base64.b64encode(sessCookie['NDG-ID1']['expires']), 
    308335               hdrTxt, 
    309336               redirectMsg) 
    310  
    311      
     337        print output 
     338 
     339 
    312340    #_________________________________________________________________________ 
    313341    def authenticate(self, bAuthorise=False): 
     
    332360             
    333361        if self.userName is None: 
     362            self.showLogin(returnURI=self['returnURI'].value, 
     363                           setCookie=True, 
     364                           contentTypeHdr=True, 
     365                           pageTitle="NDG Login", 
     366                           htmlTag=True, 
     367                           bodyTag=True) 
    334368            raise SecurityCGIError("no username set for authentication") 
    335369 
    336370        if self.passPhrase is None: 
     371            self.showLogin(returnURI=self['returnURI'].value, 
     372                           setCookie=True, 
     373                           contentTypeHdr=True, 
     374                           pageTitle="NDG Login", 
     375                           htmlTag=True, 
     376                           bodyTag=True) 
    337377            raise SecurityCGIError("no pass-phrase set for authentication") 
    338378 
     
    346386                                   traceFile=traceFile) 
    347387 
    348             return smClnt.connect(userName=self.userName, 
    349                                   pPhrase=self.passPhrase, 
    350                                   clntPriKeyPwd=self.clntPriKeyPwd) 
     388            sSessCookie = smClnt.connect(userName=self.userName, 
     389                                         pPhrase=self.passPhrase, 
     390                                         clntPriKeyPwd=self.clntPriKeyPwd) 
     391            sessCookie = SimpleCookie(sSessCookie) 
     392            return sessCookie 
     393 
    351394        except Exception, e: 
     395            self.showLogin(returnURI=self['returnURI'].value, 
     396                           setCookie=True, 
     397                           contentTypeHdr=True, 
     398                           pageTitle="NDG Login", 
     399                           htmlTag=True, 
     400                           bodyTag=True) 
    352401            raise SecurityCGIError("Session client: " + str(e)) 
    353402             
     
    413462                                    "noMapping":                 ''} 
    414463     
    415         if self.__authorisationMethod is None: 
     464        if self._authorisationMethod is None: 
    416465            # Default to safest option for user 
    417466            authorisationMethodChk["allowMappingWithPrompt"] = ' checked' 
    418467        else: 
    419             authorisationMethodChk[self.__authorisationMethod] = ' checked' 
     468            authorisationMethodChk[self._authorisationMethod] = ' checked' 
    420469     
    421470        print \ 
     
    439488                var style = document.layers[whichLayer].style; 
    440489            } 
    441             style.visibility = style.visibility == "visible" ? "hidden":"visible"; 
    442         } 
     490            style.visibility = style.visibility == "visible" ?  
     491"hidden":"visible";        } 
    443492    //--> 
    444493    </script> 
     
    458507    <tr> 
    459508        <td colspan="2" align="right"> 
    460             <a href="javascript:toggleLayer('advSettings');">Advanced Settings</a> 
    461             <input type=submit value="Login"> 
     509            <a href="javascript:toggleLayer('advSettings');">Advanced  
     510Settings</a>            <input type=submit value="Login"> 
    462511        </td> 
    463512    </tr> 
     
    470519    <div id="advSettings" style="position: relative; visibility: hidden;"> 
    471520        <h4>Role Mapping for access to other trusted sites</h4> 
    472         <p>Your account has roles or <i>privileges</i> which determine what data you have access to.  If you access data at another NDG trusted site, these roles can be mapped to local roles at that site to help you gain access: 
    473         </p> 
    474         <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5> 
    475         <tbody> 
     521        <p>Your account has roles or <i>privileges</i> which determine what data  
     522you have access to.  If you access data at another NDG trusted site, these roles  
     523can be mapped to local roles at that site to help you gain access:        </p>    
     524     <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5>        <tbody> 
    476525        <tr> 
    477526        <td> 
    478             <input type="radio" name="authorisationMethod" value="allowMapping"%s> 
    479         </td> 
     527            <input type="radio" name="authorisationMethod"  
     528value="allowMapping"%s>        </td> 
    480529            <td> 
    481                 Allow my roles to be mapped to local roles at other NDG trusted sites. 
    482             </td> 
     530                Allow my roles to be mapped to local roles at other NDG trusted  
     531sites.            </td> 
    483532        </tr> 
    484533        <tr> 
    485534            <td> 
    486                 <input type="radio" name="authorisationMethod" value="allowMappingWithPrompt"%s> 
    487             </td> 
     535                <input type="radio" name="authorisationMethod"  
     536value="allowMappingWithPrompt"%s>            </td> 
    488537        <td> 
    489             Allow my roles to be mapped, but prompt me so that I may choose which roles to map before gaining access. 
    490         </td> 
     538            Allow my roles to be mapped, but prompt me so that I may choose  
     539which roles to map before gaining access.        </td> 
    491540        <tr> 
    492541        <td> 
     
    613662                                clntPubKeyFilePath=self.clntPubKeyFilePath, 
    614663                                clntPriKeyFilePath=self.clntPriKeyFilePath, 
    615                                 traceFile=traceFile)  
     664                                traceFile=traceFile) 
    616665             
    617666            self.trustedHostInfo = aaClnt.getTrustedHostInfo( 
  • TI12-security/trunk/python/NDG/Session.py

    r1022 r1035  
    7373 
    7474 
    75  
    76  
    7775#_____________________________________________________________________________ 
    7876# Inheriting from 'object' allows Python 'new-style' class with Get/Set 
     
    8280 
    8381    # Session ID 
    84     __sessIDlen = 128 
     82    __sessIDlen = 64 
    8583 
    8684    __cookieTags = ("NDG-ID1", "NDG-ID2") 
     
    9189    __cookieDomainTag = 'domain' 
    9290    __cookieExpiryTag = "expires" 
    93          
    94     __sessCookieExpiryFmt = "%a, %d-%b-%Y %H:%M:%S GMT" 
     91  
     92    # Quotes are vital (and part of the official cookei format) - otherwise it 
     93    # will not be parsed correctly 
     94    __sessCookieExpiryFmt = "\"%a, %d-%b-%Y %H:%M:%S GMT\"" 
    9595 
    9696 
     
    327327            if not isinstance(dtExpiry, datetime): 
    328328                UserSessionError, \ 
    329                     "Expecting vaild datetime object with dtExpiry keyword" 
     329                    "Expecting valid datetime object with dtExpiry keyword" 
    330330                 
    331331            expiryStr = dtExpiry.strftime(cls.__sessCookieExpiryFmt) 
  • TI12-security/trunk/python/Tests/SecurityClientTest.py

    r1022 r1035  
    5050 
    5151            # Attribute Authority client tests 
    52             aaWSDL = 'http://gabriel.bnsc.rl.ac.uk/attAuthority.wsdl' 
     52            aaWSDL = 'http://glue.badc.rl.ac.uk/attAuthority.wsdl' 
    5353            aaPubKeyFilePath = None 
    5454             
     
    183183        import pdb 
    184184        pdb.set_trace() 
    185         role = 'staff' 
     185        role = 'acsoe' 
    186186        try: 
    187187            trustedHosts = self.aaClnt.getTrustedHostInfo( 
  • TI12-security/trunk/python/Tests/security.py

    r1022 r1035  
    2121 
    2222    #_________________________________________________________________________ 
    23     def showLogin(self, returnURI=None, **kwargs): 
     23    def showLogin(self, returnURI=None, bAuthorise=False, **kwargs): 
    2424        """Display initial NDG login form""" 
    2525 
    2626        if returnURI: 
    2727            returnURIfield = \ 
    28                 "<input type=hidden name=returnURI value=\"%s\">" % returnURI 
     28             "<input type=hidden name=\"returnURI\" value=\"%s\">" % returnURI 
    2929        else: 
    3030            returnURIfield = '' 
     
    3232 
    3333        if bAuthorise: 
    34             authoriseArg = "<input type=hidden name=authorise value=\"1\">" 
     34            authoriseField = \ 
     35                "<input type=hidden name=\"authorise\" value=\"1\">" 
    3536        else: 
    36             authoriseArg = "" 
     37            authoriseField = "" 
    3738 
    3839 
     
    4142                                    "allowMappingWithPrompt" :   '', 
    4243                                    "noMapping":                 ''} 
    43      
    44         if self.__authorisationMethod is None: 
     44 
     45        if self._authorisationMethod is None: 
    4546            # Default to safest option for user 
    4647            authorisationMethodChk["allowMappingWithPrompt"] = ' checked' 
    4748        else: 
    48             authorisationMethodChk[self.__authorisationMethod] = ' checked' 
    49      
     49            authorisationMethodChk[self._authorisationMethod] = ' checked' 
     50 
    5051 
    5152        print """Content-type: text/html 
    52          
    53 <html>"     
     53 
     54<html> 
    5455<head> 
    55 <title>%s</title> 
     56<title>NDG Login</title> 
    5657<style type=\"text/css\"> 
    5758<!-- 
     
    9091                    var style = document.layers[whichLayer].style; 
    9192                } 
    92                 style.visibility = style.visibility == "visible" ? "hidden":"visible"; 
    93             } 
     93                style.visibility = style.visibility == "visible" ? 
     94"hidden":"visible";            } 
    9495        //--> 
    9596    </script> 
    9697    <h3>NERC Data Grid Site Login (Test)<BR clear=all></h3> 
    9798    <hr> 
    98      
     99 
    99100    <form action="%s" method="POST"> 
    100      
     101 
    101102    <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5> 
    102103    <tbody> 
    103     <tr><td>User Name:</td> <td><input type=text name=userName value=""> 
    104     </td></tr> 
    105     <tr> 
    106         <td>Password:</td> 
    107         <td><input type=password name=passPhrase></td> 
    108     </tr> 
    109     <tr> 
    110         <td colspan="2" align="right"> 
    111             <a href="javascript:toggleLayer('advSettings');">Advanced Settings</a> 
    112             <input type=submit value="Login"> 
    113         </td> 
    114     </tr> 
    115     <input type=hidden name=authenticate value="1"> 
    116     %s"""  % (self.scriptName, returnURIfield) 
    117      
     104    <tr> 
     105      <td>User Name:</td> 
     106      <td><input type=text name="userName" value=""></td> 
     107    </tr> 
     108    <tr> 
     109      <td>Password:</td> 
     110      <td><input type=password name="passPhrase"></td> 
     111    </tr> 
     112    <tr> 
     113      <td colspan="2" align="right"> 
     114        <a href="javascript:toggleLayer('advSettings');"> 
     115        Advanced Settings 
     116        </a> 
     117        <input type=submit value="Login"> 
     118      </td> 
     119    </tr> 
     120    <input type=hidden name="authenticate" value="1"> 
     121    </tbody> 
     122    </table> 
     123    %s 
     124    %s 
     125    </form> 
     126</body> 
     127</html>"""  % (self.scriptName, returnURIfield, authoriseField) 
     128 
    118129        print \ 
    119     """</tbody></table> 
     130"""    </tbody> 
     131    </table> 
    120132    <br> 
    121133    <div id="advSettings" style="position: relative; visibility: hidden;"> 
    122         <h4>Role Mapping for access to other trusted sites</h4> 
    123         <p>Your account has roles or <i>privileges</i> which determine what data you have access to.  If you access data at another NDG trusted site, these roles can be mapped to local roles at that site to help you gain access: 
    124         </p> 
    125         <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5> 
    126         <tbody> 
     134      <h4>Role Mapping for access to other trusted sites</h4> 
     135      <p>Your account has roles or <i>privileges</i> which determine what data 
     136you have access to.  If you access data at another NDG trusted site, these 
     137roles can be mapped to local roles at that site to help you gain access: 
     138      </p> 
     139    <table bgcolor=#ADD8E6 cellspacing=0 border=0 cellpadding=5> 
     140    <tbody> 
     141      <tr> 
     142        <td><input type="radio" name="authorisationMethod" 
     143value="allowMapping"%s> 
     144        </td> 
     145        <td> 
     146        Allow my roles to be mapped to local roles at other NDG trusted sites. 
     147        </td> 
     148      </tr> 
     149      <tr> 
     150        <td> 
     151          <input type="radio" name="authorisationMethod" 
     152value="allowMappingWithPrompt"%s> 
     153        </td> 
     154        <td> 
     155            Allow my roles to be mapped, but prompt me so that I may choose 
     156which roles to map before gaining access. 
     157        </td> 
    127158        <tr> 
    128159        <td> 
    129             <input type="radio" name="authorisationMethod" value="allowMapping"%s> 
    130         </td> 
    131             <td> 
    132                 Allow my roles to be mapped to local roles at other NDG trusted sites. 
    133             </td> 
     160          <input type="radio" name="authorisationMethod" value="noMapping"%s> 
     161        </td> 
     162        <td> 
     163          Don't allow mapping of my roles. 
     164        </td> 
    134165        </tr> 
    135         <tr> 
    136             <td> 
    137                 <input type="radio" name="authorisationMethod" value="allowMappingWithPrompt"%s> 
    138             </td> 
    139         <td> 
    140             Allow my roles to be mapped, but prompt me so that I may choose which roles to map before gaining access. 
    141         </td> 
    142         <tr> 
    143         <td> 
    144             <input type="radio" name="authorisationMethod" value="noMapping"%s> 
    145         </td> 
    146         <td> 
    147             Don't allow mapping of my roles. 
    148         </td> 
    149         </tr> 
    150         </tbody> 
    151         </table> 
     166      </tbody> 
     167      </table> 
    152168    </div> 
    153169    </form> 
     
    214230 
    215231 
    216          
     232    #_________________________________________________________________________ 
     233    def showCredsReceived(self, 
     234                              sessCookie, 
     235                                                  pageTitle='', 
     236                                                  hdrTxt='', 
     237                                                  bodyTxt=''): 
     238        """Called from receiveCredsResponse() once a cookie has been created. 
     239        Makes a page to set the cookie and display to the user that they have 
     240        been authenticated.  Derived class should override this method as 
     241        required""" 
     242        print """Content-type: text/html 
     243%s 
     244 
     245<html> 
     246<head> 
     247<title>NDG Authentication</title> 
     248    <style type=\"text/css\"> 
     249    <!-- 
     250    .al { 
     251    text-align: justify 
     252    } 
     253    a{ 
     254    text-decoration:none; 
     255    } 
     256    a:hover{ 
     257    color:#0000FF; 
     258    } 
     259        body { font-family: Verdana, sans-serif; font-size: 11} 
     260        table { font-family: Verdana, sans-serif; font-size: 11} 
     261    --> 
     262    </style> 
     263</head> 
     264<body> 
     265    New cookie set from credentials transfered from other domain 
     266</body> 
     267</html>""" % sessCookie.output() 
     268 
     269 
     270#_____________________________________________________________________________ 
    217271if __name__ == "__main__": 
    218      
     272 
    219273    smWSDL = "http://gabriel.bnsc.rl.ac.uk/sessionMgr.wsdl" 
    220274    aaWSDL = 'http://gabriel.bnsc.rl.ac.uk/attAuthority.wsdl' 
     
    222276    smPubKeyFilePath = "/usr/local/NDG/conf/certs/gabriel-sm-cert.pem" 
    223277    aaPubKeyFilePath = "/usr/local/NDG/conf/certs/gabriel-aa-cert.pem" 
    224      
     278 
    225279    clntPubKeyFilePath = "../certs/GabrielCGI-cert.pem" 
    226280    clntPriKeyFilePath = "../certs/GabrielCGI-key.pem" 
Note: See TracChangeset for help on using the changeset viewer.