Changeset 792

Show
Ignore:
Timestamp:
03/05/07 14:35:33 (2 years ago)
Author:
mfenniak
Message:

Set svn:ignore to pyc files. Add MD5 authentication support to library, untested.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • pg8000/trunk

    • Property svn:ignore set to
      *.pyc
  • pg8000/trunk/pg8000.py

    r790 r792  
    11import socket 
    22import struct 
     3import md5 
    34 
    45apilevel = '2.0' 
     
    3536class NotSupportedError(DatabaseError): 
    3637    pass 
    37  
    3838 
    3939class Cursor(object): 
     
    8888 
    8989class Connection(object): 
    90     def __init__(self, host, user, port=5432, database=None): 
     90    def __init__(self, host, user, port=5432, database=None, password=None): 
    9191        try: 
    9292            self.c = Protocol.Connection(host, port) 
    9393            self.c.connect() 
    94             self.c.authenticate(user) 
     94            if not self.c.authenticate(user, password=password, database=database): 
     95                raise InterfaceError("authentication method failed or not supported") 
    9596        except socket.error, e: 
    96             raise InterfaceError("socket.error", *e.args
     97            raise InterfaceError("communication error", e
    9798        self._cursor = Cursor(self.c) 
    9899 
     
    138139            return val 
    139140 
     141    class PasswordMessage(object): 
     142        def __init__(self, pwd): 
     143            self.pwd = pwd 
     144 
     145        def serialize(self): 
     146            val = self.pwd + "\x00" 
     147            val = struct.pack("!i", len(val) + 4) + val 
     148            val = "p" + val 
     149            return val 
     150 
    140151    class AuthenticationRequest(object): 
     152        def __init__(self, data): 
     153            pass 
     154 
    141155        def createFromData(data): 
    142156            ident = struct.unpack("!i", data[:4])[0] 
    143             if ident == 0: 
    144                 return Protocol.AuthenticationOk() 
     157            klass = Protocol.authentication_codes.get(ident, None) 
     158            if klass != None: 
     159                return klass(data[4:]) 
    145160            else: 
    146                 return Protocol.AuthenticationRequest(
    147         createFromData = staticmethod(createFromData) 
    148  
    149         def ok(self): 
    150             return False 
     161                raise InterfaceError("authentication method %r not supported" % (ident,)
     162        createFromData = staticmethod(createFromData) 
     163 
     164        def ok(self, conn, user, **kwargs): 
     165            raise NotImplementedError("ok method should be overridden on AuthenticationRequest instance") 
    151166 
    152167    class AuthenticationOk(AuthenticationRequest): 
    153         def ok(self): 
     168        def ok(self, conn, user, **kwargs): 
    154169            return True 
     170 
     171    class AuthenticationMD5Password(AuthenticationRequest): 
     172        def __init__(self, data): 
     173            self.salt = "".join(struct.unpack("4c", data)) 
     174 
     175        def ok(self, conn, user, password=None, **kwargs): 
     176            if password == None: 
     177                raise InterfaceError("server requesting MD5 password authentication, but no password was provided") 
     178            pwd = "md5" + md5.new(md5.new(password + user).hexdigest() + self.salt).hexdigest() 
     179            conn._send(Protocol.PasswordMessage(pwd)) 
     180            msg = conn._read_message() 
     181            if isinstance(msg, Protocol.AuthenticationRequest): 
     182                return msg.ok(conn, user) 
     183            elif isinstance(msg, Protocol.ErrorResponse): 
     184                if msg.code == "28000": 
     185                    raise InterfaceError("md5 password authentication failed") 
     186                else: 
     187                    raise InternalError("server returned unexpected error %r" % msg) 
     188            else: 
     189                raise InternalError("server returned unexpected response %r" % msg) 
     190 
     191    authentication_codes = { 
     192        0: AuthenticationOk, 
     193        5: AuthenticationMD5Password, 
     194    } 
    155195 
    156196    class ParameterStatus(object): 
     
    207247                elif s[0] == "M": 
    208248                    args["msg"] = s[1:] 
    209             return ErrorResponse(**args) 
     249            return Protocol.ErrorResponse(**args) 
    210250        createFromData = staticmethod(createFromData) 
    211251 
     
    264304        def verifyState(self, state): 
    265305            if self.state != state: 
    266                 raise ProgrammingError, "connection state must be %s, is %s" % (state, self.state) 
     306                raise InternalError, "connection state must be %s, is %s" % (state, self.state) 
    267307 
    268308        def _send(self, msg): 
     
    282322            self.state = "noauth" 
    283323 
    284         def authenticate(self, user): 
     324        def authenticate(self, user, **kwargs): 
    285325            self.verifyState("noauth") 
    286             self._send(Protocol.StartupMessage(user)) 
     326            self._send(Protocol.StartupMessage(user, database=kwargs.get("database",None))) 
    287327            msg = self._read_message() 
    288             if isinstance(msg, Protocol.AuthenticationOk): 
    289                 self.state = "auth" 
    290                 self._waitForReady() 
    291                 return True 
     328            if isinstance(msg, Protocol.AuthenticationRequest): 
     329                if msg.ok(self, user, **kwargs): 
     330                    self.state = "auth" 
     331                    self._waitForReady() 
     332                else: 
     333                    raise InterfaceError("authentication method %s failed" % msg.__class__.__name__) 
     334            else: 
     335                raise InternalError("StartupMessage was responded to with non-AuthenticationRequest msg") 
    292336 
    293337        def _waitForReady(self): 
  • pg8000/trunk/pg8000-test.py

    r790 r792  
    33import pg8000 
    44 
    5 db = pg8000.connect(host='localhost', user='mfenniak') 
     5db = pg8000.connect(host='localhost', user='laotzu') 
    66cur = db.cursor() 
    77