def make_SASLContinue(client_nonce, salt, iter_num): if type(iter_num) is int: iter_num = b'%d' % iter_num server_nonce = base64.b64encode(gen_random_bytes(SCRAM_NONCE_LEN)) data = b'r=%s%s,s=%s,i=%s' % (client_nonce, server_nonce, salt, iter_num) msg = p.Authentication(authtype=p.AuthType.AT_SASLContinue, data=data) msg.server_nonce = server_nonce return msg
def go(self): if self.status == 0: self.status = 1 sasl = p.SASL.make('SCRAM-SHA-256') m = p.Authentication(authtype=p.AuthType.AT_SASL, data=bytes(sasl)) self.write_msgs((m,)) return self.go() if self.status == 1: m = self._read_next_msg() if type(m) is str: return m # m is AuthResponse(SASLInitialResponse) self.status = 2 self.sasl_init_resp_msg = p.SASLInitialResponse(m.data) if bytes(self.sasl_init_resp_msg.name) != b'SCRAM-SHA-256': self.status = 100 self.result = AUTH_FAIL return self.result scram.parse_SASLInitialResponse(self.sasl_init_resp_msg) # send SASLContinue to client self.sasl_continue_msg = scram.make_SASLContinue(self.sasl_init_resp_msg.client_nonce, self.shadow[2], self.shadow[1]) self.write_msgs((self.sasl_continue_msg,)) return self.go() if self.status == 2: m = self._read_next_msg() if type(m) is str: return m # m is AuthResponse(SASLReponse) self.status = 3 self.sasl_resp_msg = p.SASLResponse(m.data) scram.parse_SASLResponse(self.sasl_resp_msg) if self.sasl_resp_msg.nonce != self.sasl_init_resp_msg.client_nonce + self.sasl_continue_msg.server_nonce: self.status = 100 self.result = AUTH_FAIL return self.result storedkey = b64decode(self.shadow[3]) if not scram.verify_SASLResponse(storedkey, self.sasl_init_resp_msg, self.sasl_continue_msg, self.sasl_resp_msg): self.status = 100 self.result = AUTH_FAIL return self.result # send SASLFinal to client serverkey = b64decode(self.shadow[4]) self.sasl_final_msg = scram.make_SASLFinal(serverkey, self.sasl_init_resp_msg, self.sasl_continue_msg, self.sasl_resp_msg) self.write_msgs((self.sasl_final_msg,)) return self.go() if self.status == 3: if self.write_msgs(): return 'pollout' self.status = 4 self.result = AUTH_OK return self.result return self.result
def go(self): if self.status == 0: self.status = 1 m = p.Authentication(authtype=p.AuthType.AT_MD5Password, data=self.salt) self.write_msgs((m,)) return self.go() if self.status == 1: m = self._read_next_msg() if type(m) is str: return m self.status = 2 m = p.PasswordMessage(m.data) self.result = AUTH_OK if bytes(m.password) == b'md5' + p.md5(self.shadow[1] + self.salt) else AUTH_FAIL return self.result return self.result
def go(self): if self.status == 0: self.status = 1 m = p.Authentication(authtype=p.AuthType.AT_CleartextPassword, data=b'') self.write_msgs((m,)) return self.go() if self.status == 1: m = self._read_next_msg() if type(m) is str: return m self.status = 2 m = p.PasswordMessage(m.data) self.result = AUTH_OK if self._check(bytes(m.password)) else AUTH_FAIL return self.result return self.result
return pgscramauth(cnn, user, shadow) else: raise RuntimeError('unknown shadow:%s' % shadow) elif authtype == 'scram-sha-256': if shadow[0] == MD5_PREFIX: return pgdenyauth(cnn, user,shadow) elif shadow[0] == SCRAM_PREFIX: return pgscramauth(cnn, user, shadow) else: raise RuntimeError('unknown shadow:%s' % shadow) else: raise RuntimeError('unknown authtype in hba:%s' % hba_res) # main auth_fail_msgs = [p.ErrorResponse.make((b'S', b'FATAL'), (b'V', b'FATAL'), (b'M', b'authentication fail')), ] auth_ok_msgs = [ p.Authentication(authtype=p.AuthType.AT_Ok, data=b''), p.ParameterStatus(name=b'application_name', val=b'pghba'), p.ParameterStatus(name=b'client_encoding', val=b'UTF8'), p.ParameterStatus(name=b'DateStyle', val=b'ISO, MDY'), p.ParameterStatus(name=b'integer_datetimes', val=b'on'), p.ParameterStatus(name=b'IntervalStyle', val=b'postgres'), p.ParameterStatus(name=b'is_superuser', val=b'on'), p.ParameterStatus(name=b'server_encoding', val=b'UTF8'), p.ParameterStatus(name=b'server_version', val=b'11devel'), p.ParameterStatus(name=b'session_authorization', val=b'zhb'), p.ParameterStatus(name=b'standard_conforming_strings', val=b'on'), p.ParameterStatus(name=b'TimeZone', val=b'Asia/Hong_Kong'), p.BackendKeyData(pid=1234, skey=1234), p.ReadyForQuery(trans_status=b'I'), ] if __name__ == '__main__':
def make_SASLFinal(serverkey, sasl_init_resp_msg, sasl_continue_msg, sasl_resp_msg): server_sig = hmac_sha256(serverkey, sasl_init_resp_msg.response_bare, b',', sasl_continue_msg.data, b',', sasl_resp_msg.data_without_proof) server_sig = base64.b64encode(server_sig) return p.Authentication(authtype=p.AuthType.AT_SASLFinal, data = b'v='+server_sig)