source: TI12-security/trunk/python/ndg.security.common/ndg/security/common/SessionCookie.py @ 2270

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI12-security/trunk/python/ndg.security.common/ndg/security/common/SessionCookie.py@2270
Revision 2270, 9.4 KB checked in by pjkersha, 12 years ago (diff)

Replaced

reposID = '$Id$'

with,

revision = '$Id$'

for all relevant files.

ndg.security.server/setup.py:

  • added license keyword to setup

ndg.security.server/ndg/security/server/AttAuthority/init.py:

  • removed refs to proxy certificate in getattCert call. Input cert may not necessarily be a proxy.

ndg.security.common/setup.py: Major fixes to give *working* version.

  • PyXML dependency to ZSI fixed by giving explict sourceforge dependency link
  • Get ZSI from PyPI insteads of Sourceforge
  • Moved SQLObject and MySQL dependency to a separate if clause. This will be completed later to

allow inclusion of these on provision of a given option

  • added license keyword to setup.
Line 
1"""NDG Session Cookie used by Session Manager UserSession and Login
2Service CGI code.
3
4NERC Data Grid Project
5
6P J Kershaw 27/10/06
7
8Copyright (C) 2006 CCLRC & NERC
9
10This software may be distributed under the terms of the Q Public License,
11version 1.0 or later.
12"""
13
14__revision__ = '$Id$'
15
16from datetime import datetime
17from Cookie import SimpleCookie
18
19#_____________________________________________________________________________
20class SessionCookieError(Exception):
21    "Handle exception from SessionCookie class"
22   
23       
24#_____________________________________________________________________________
25class _MetaSessionCookie(type):
26    """Enable SessionCookie to have read only class variables e.g.
27   
28    print sessionCookie.cookieTags is allowed but,
29   
30    sessionCookie.cookieTags = None
31   
32    ... raises - AttributeError: can't set attribute"""
33    def __getTags(cls):
34        '''ndgID1 is the session ID and ndgID2 is the encrypted session
35        manager WSDL address.'''
36        return ("ndgID1", "ndgID2")
37
38    tags = property(fget=__getTags)
39
40    def __getSessIDlen(cls):
41        '''This sets the session ID length (!)'''
42        return 64
43   
44    sessIDlen = property(fget=__getSessIDlen)
45   
46   
47#_____________________________________________________________________________
48class SessionCookie(object):
49    """Class encapsulates Session Cookie for handling by UserSession and
50    LoginService"""
51   
52    __metaclass__ = _MetaSessionCookie
53
54    # Follow standard format for cookie path and expiry attributes
55    __cookiePathTag = "path"
56    __cookiePath = "/"
57    __cookieDomainTag = 'domain'
58    __cookieExpiryTag = "expires"
59 
60    # Quotes are vital (and part of the official cookei format) - otherwise it
61    # will not be parsed correctly
62    __sessCookieExpiryFmt = "\"%a, %d-%b-%Y %H:%M:%S GMT\""
63
64       
65    #_________________________________________________________________________   
66    def __init__(self,
67                 cookieStr=None, 
68                 expiryStr=None,
69                 dtExpiry=None,
70                 cookiePath=None,
71                 cookieDomain=None,
72                 **cookieTagKw):
73        """Cookie creation             
74           
75        Caller should set the cookie e.g. in a CGI script
76        print "Content-type: text/html"
77        print str(cookie) + os.linesep
78
79        cookieStr:                   Optionally, create new object by parsing a
80                               cookie string
81                               Use UserSession.encrypt() to encrypt the
82                               SessionManager WSDL address.  The site
83                               SessionManager holds the encryption key.
84        expiryStr|dtExpiry:    expiry date time for the cookie.  Input as a
85                               string formatted in the standard way for
86                               cookies or input a datetime type for
87                               conversion.
88        cookiePath:            cookie path - defaults to '/'
89        cookieDomain:          The domain for the cookie.  Default is the
90                               web server address.  Override to set to a
91                               site wide cookie e.g. .rl.ac.uk.  Nb. that this
92                               has security implications
93       
94        **cookieTagKw:         session ID for cookie (ndgID1) and
95                               encrypted Session Manager WSDL address (ndgID2)
96                               ** style arg means they can be passed as a
97                               dictionary without the caller needing to
98                               know the tag names.
99        """
100
101        # Domain for cookie used by createCookie method - if not set, it will
102        # default to web server domain name
103        self.__cookieDomain = cookieDomain
104
105        # Nb. SimpleCookie doesn't like unicode
106        self.__cookie = SimpleCookie(str(cookieStr))
107           
108        try:
109            # Check for expected cookie morsels
110            sessID = self.__cookie[SessionCookie.tags[0]].value
111            encrSessionMgrURI = self.__cookie[SessionCookie.tags[1]].value
112           
113        except KeyError:
114            try:
115                # if not, check for setting from keywords
116                sessID = cookieTagKw[SessionCookie.tags[0]]
117                encrSessionMgrURI = cookieTagKw[SessionCookie.tags[1]]
118               
119            except KeyError:           
120                tags = SessionCookie.tags
121                msg = len(tags) > 1 and \
122                    's %s and %s' % (', '.join(tags[:-1]), tags[-1]) \
123                    or ' ' + tags[-1]
124                raise SessionCookieError, "Missing Cookie morsel%s" % msg
125
126           
127        if len(sessID) < SessionCookie.sessIDlen:
128            SessionCookieError, "Session ID has an invalid length"
129           
130        if encrSessionMgrURI[:7] == 'http://' or \
131           encrSessionMgrURI[:8] == 'https://':
132            SessionCookieError, "Input Session Manager URI does not " + \
133                                "appear to have been encrypted"
134                             
135        if dtExpiry:
136            if not isinstance(dtExpiry, datetime):
137                SessionCookieError, \
138                    "Expecting valid datetime object with dtExpiry keyword"
139               
140            expiryStr = dtExpiry.strftime(self.__sessCookieExpiryFmt)
141           
142        elif not expiryStr or not isinstance(expiryStr, basestring):
143            try:
144                # Check for expiry already set in SimpleCookie type - this
145                # would be true if str keyword was set
146                exp = \
147                self.__cookie[SessionCookie.tags[0]][self.__cookieExpiryTag]
148            except KeyError:
149                raise SessionCookieError, "No cookie expiry was set"
150           
151           
152        try:             
153            tagValues = (sessID, encrSessionMgrURI)
154            i=0
155            for tag in SessionCookie.tags:
156               
157                if tag not in self.__cookie:
158                    self.__cookie[tag] = tagValues[i]
159               
160                # Use standard format for cookie path and expiry
161                self.__cookie[tag][self.__cookiePathTag] = \
162                                            cookiePath or self.__cookiePath
163                                                           
164                if expiryStr:
165                    self.__cookie[tag][self.__cookieExpiryTag] = expiryStr
166                                           
167                # Default domain is the host.  This is the safest option from
168                # a security perspective
169                if cookieDomain:
170                    self.__cookie[tag][self.__cookieDomainTag] = cookieDomain
171                   
172                i += 1
173           
174        except Exception, e:
175            raise SessionCookieError, "Creating Session Cookie: %s" % e
176       
177   
178    def asSimpleCookie(self):
179        return self.__cookie
180   
181    def asString(self):
182        return self.__cookie.output()
183   
184    def __call__(self):
185        return self.asSimpleCookie()
186   
187    def __str__(self):
188        return self.asString()
189   
190    def __repr__(self):
191        return self.asString()
192
193
194    #_________________________________________________________________________
195    def __setCookieDomain(self, cookieDomain):
196        """Set domain for cookie - set to None to assume domain of web server
197        """
198
199        if not isinstance(cookieDomain, basestring) and \
200           cookieDomain is not None:
201            raise SessionCookieError, \
202                "Expecting string or None type for \"cookieDomain\""
203                       
204        self.__cookieDomain = cookieDomain
205
206    cookieDomain = property(fset=__setCookieDomain, doc="Set cookie domain")
207       
208
209    #_________________________________________________________________________
210    def __getSessionID(self):
211        """Return the session ID from the cookie"""
212        return self.__cookie[SessionCookie.tags[0]].value
213   
214    sessionID = property(fget=__getSessionID, doc="Get session ID")
215
216    #_________________________________________________________________________
217    def __getEncrSessionMgrURI(self):
218        """Return the Encrypted Session manager URI from the cookie"""
219        return self.__cookie[SessionCookie.tags[1]].value
220
221    encrSessionMgrURI = property(fget=__getEncrSessionMgrURI, 
222                                 doc="Get encrypted Session Manager URI")
223
224   
225    #_________________________________________________________________________
226    @classmethod   
227    def isValid(cls, cookie, raiseExcep=False):
228        """Check cookie has the expected session keys.  Cookie may be a
229        string or SimpleCookie type"""
230       
231        if isinstance(cookie, basestring):
232            cookie = SimpleCookie(cookie)
233           
234        elif not isinstance(cookie, SimpleCookie):
235            if raiseExcep:
236                raise SessionCookieError,"Input cookie must be a string or "+\
237                                        "SimpleCookie type"
238            else:
239                return False
240       
241        missingTags = [tag for tag in self.tags if tag not in cookie]
242        if missingTags:
243            if raiseExcep:
244                raise SessionCookieError, \
245            "Input cookie missing security tag(s): " + ", ".join(missingTags)
246            else:
247                return False
248
249        if len(cookie[self.tags[0]].value) < cls.sessIDlen:
250            if raiseExcep:
251                raise SessionCookieError, "Session ID has an invalid length"
252            else:
253                return False
254       
255        return True
Note: See TracBrowser for help on using the repository browser.