pvl/login/pubtkt.py
changeset 438 d45fc43c6073
parent 437 5100b359906c
child 439 6a8ea0d363c1
--- a/pvl/login/pubtkt.py	Tue Feb 24 12:47:09 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,291 +0,0 @@
-import base64
-import calendar
-import datetime
-import ipaddr
-import hashlib
-import M2Crypto
-
-import logging; log = logging.getLogger('pvl.login.pubtkt')
-
-def datetime2unix (dt) :
-    """
-        datetime.datetime -> float
-    """
-
-    return calendar.timegm(dt.utctimetuple())
-
-def unix2datetime (unix) :
-    return datetime.datetime.utcfromtimestamp(unix)
-
-class Error (Exception) :
-    """
-        Error
-    """
-
-    def __init__ (self, error) :
-        self.error = error
-
-    def __unicode__ (self) :
-        return u"{doc}: {self.error}".format(self=self, doc=self.__doc__.strip())
-
-class ParseError (Error) :
-    """
-        Unable to parse PubTkt from cookie
-    """
-
-class VerifyError (Error) :
-    """
-        Invalid login token sigunature
-    """
-
-    def __init__ (self, pubtkt, error) :
-        self.pubtkt = pubtkt
-        self.error = error
-
-class ExpiredError (Error) :
-    """
-        Login token has expired
-    """
-
-    def __init__ (self, pubtkt, expire) :
-        self.pubtkt = pubtkt
-        self.error = expire
-
-class RenewError (Error) :
-    """
-        Unable to renew login token
-    """
-
-class ServerError (Error) :
-    """
-        Login request from invalid server
-    """
-    
-class ServerKeys (object) :
-    @classmethod
-    def config (cls, public_key, private_key) :
-        return cls(
-                public  = M2Crypto.RSA.load_pub_key(public_key),
-                private = M2Crypto.RSA.load_key(private_key),
-        )
-
-    def __init__ (self, public, private) :
-        self.public = public
-        self.private = private
-
-class PubTkt (object) :
-    @staticmethod
-    def now () :
-        return datetime.datetime.utcnow()
-
-    @classmethod
-    def load (cls, cookie, public_key) :
-        """
-            Load and verify a pubtkt from a cookie.
-
-            Raise ParseError, VerifyError.
-        """
-        
-        pubtkt, hash, sig = cls.parse(cookie)
-
-        log.debug("parsed %s hash=%s sig=%s", pubtkt, hash.encode('hex'), sig.encode('hex'))
-        
-        try :
-            if not public_key.verify(hash, sig, 'sha1') :
-                raise VerifyError(pubtkt, "Unable to verify signature")
-        except M2Crypto.RSA.RSAError as ex :
-            raise VerifyError(pubtkt, str(ex))
-        
-
-        log.debug("checking expiry %s", pubtkt.validuntil)
-        
-        if not pubtkt.valid() :
-            raise ExpiredError(pubtkt, pubtkt.validuntil)
-
-        return pubtkt
-
-    @classmethod
-    def parse (cls, cookie) :
-        """
-            Load a pubtkt from a cookie
-
-            Raises ParseError.
-        """
-        
-        if ';sig=' in cookie :
-            data, sig = cookie.rsplit(';sig=', 1)
-        else :
-            raise ParseError("Missing signature")
-        
-        try :
-            sig = base64.b64decode(sig)
-        except (ValueError, TypeError) as ex :
-            raise ParseError("Invalid signature")
-
-        hash = hashlib.sha1(data).digest()
-
-        try :
-            attrs = dict(field.split('=', 1) for field in data.split(';'))
-        except ValueError as ex :
-            raise ParseError(str(ex))
-        
-        if 'uid' not in attrs or 'validuntil' not in attrs :
-            raise ParseError("Missing parameters in cookie (uid, validuntil)")
-
-        try :
-            return cls.build(**attrs), hash, sig
-        except TypeError as ex :
-            raise ParseError("Invalid or missing parameters in cookie")
-        except ValueError as ex :
-            raise ParseError(str(ex))
-    
-    @classmethod
-    def build (cls, uid, validuntil, cip=None, tokens=None, udata=None, graceperiod=None, bauth=None) :
-        """
-            Build a pubtkt from items.
-
-            Raises TypeError or ValueError..
-        """
-        
-        return cls(uid,
-                validuntil  = unix2datetime(int(validuntil)),
-                cip         = ipaddr.IPAddress(cip) if cip else None,
-                tokens      = tokens.split(',') if tokens else (),
-                udata       = udata,
-                graceperiod = unix2datetime(int(graceperiod)) if graceperiod else None,
-                bauth       = bauth,
-        )
-
-    @classmethod
-    def new (cls, uid, valid, grace=None, **opts) :
-        now = cls.now()
-
-        return cls(uid, now + valid,
-            graceperiod = now + grace if grace else None,
-            **opts
-        )
-
-    def update (self, valid, grace, cip=None, tokens=None, udata=None, bauth=None) :
-        now = self.now()
-
-        return type(self)(self.uid, now + valid,
-            graceperiod = now + grace if grace else None,
-            cip         = self.cip if cip is None else cip,
-            tokens      = self.tokens if tokens is None else tokens,
-            udata       = self.udata if udata is None else udata,
-            bauth       = self.bauth if bauth is None else bauth,
-        )
-
-    def __init__ (self, uid, validuntil, cip=None, tokens=(), udata=None, graceperiod=None, bauth=None) :
-        self.uid = uid
-        self.validuntil = validuntil
-        self.cip = cip
-        self.tokens = tokens
-        self.udata = udata
-        self.graceperiod = graceperiod
-        self.bauth = bauth
-
-    def iteritems (self) :
-        yield 'uid', self.uid
-        yield 'validuntil', int(datetime2unix(self.validuntil))
-
-        if self.cip :
-            yield 'cip', self.cip
-        
-        if self.tokens :
-            yield 'tokens', ','.join(str(token) for token in self.tokens)
-        
-        if self.udata :
-            yield 'udata', self.udata
-        
-        if self.graceperiod :
-            yield 'graceperiod', int(datetime2unix(self.graceperiod))
-        
-        if self.bauth :
-            yield 'bauth', self.bauth
-
-    def __str__ (self) :
-        """
-            The (unsigned) pubtkt
-        """
-
-        return ';'.join('%s=%s' % (key, value) for key, value in self.iteritems())
-
-    def sign (self, private_key) :
-        data = str(self)
-        hash = hashlib.sha1(data).digest()
-        sign = private_key.sign(hash, 'sha1')
-
-        return '%s;sig=%s' % (self, base64.b64encode(sign))
-
-    def valid (self) :
-        """
-            Return remaining ticket validity.
-        """
-
-        now = self.now()
-
-        if self.validuntil > now :
-            return self.validuntil - now
-        else :
-            return False
-
-    def grace (self) :
-        """
-            Return remaining grace period.
-        """
-        
-        now = self.now()
-        
-        if not self.graceperiod :
-            return None
-
-        elif now < self.graceperiod :
-            # still valid
-            return None
-
-        elif now < self.validuntil :
-            # positive
-            return self.validuntil - now
-
-        else :
-            # expired
-            return False
-
-    def remaining (self) :
-        """
-            Return remaining validity before grace.
-        """
-
-        now = self.now()
-        
-        if not self.graceperiod :
-            return self.valid()
-
-        elif now < self.graceperiod :
-            return self.graceperiod - now
-
-        else :
-            # expired
-            return False
-
-    def grace_period (self) :
-        """
-            Return the length of the grace period.
-        """
-
-        if self.graceperiod :
-            return self.validuntil - self.graceperiod
-        else :
-            return None
-    
-    def renew (self, valid, grace=None) :
-        if not self.valid() :
-            raise ExpiredError(self, "Unable to renew expired pubtkt")
-
-        now = self.now()
-
-        self.validuntil = now + valid
-        self.graceperiod = now + grace if grace else None
-
-