From 228f4a69209b1549c79fd6631a1cfa35b306d94b Mon Sep 17 00:00:00 2001 From: wangxiyuan Date: Tue, 7 Jun 2016 15:17:38 +0800 Subject: [PATCH] Clean the auth app after authentication failure Now with websocket deployment, if we authenticate again after once authentication failure. zaqar doesn't authenticate and always return 403. The reason is that we didn't clean the _auth_app after the failure. Change-Id: I7febfcca600e08b5b0f7e58ddb17e83f30f35f34 Closes-bug: #1589825 --- .../unit/transport/websocket/v2/test_auth.py | 28 +++++++++++++++++++ zaqar/transport/websocket/protocol.py | 4 +++ 2 files changed, 32 insertions(+) diff --git a/zaqar/tests/unit/transport/websocket/v2/test_auth.py b/zaqar/tests/unit/transport/websocket/v2/test_auth.py index a2c7fa3e..13d79104 100644 --- a/zaqar/tests/unit/transport/websocket/v2/test_auth.py +++ b/zaqar/tests/unit/transport/websocket/v2/test_auth.py @@ -124,6 +124,34 @@ class AuthTest(base.V2Base): self.assertIn('cancelled', repr(handle)) self.assertNotIn('cancelled', repr(self.protocol._deauth_handle)) + def test_reauth_after_auth_failure(self): + headers = self.headers.copy() + headers['X-Auth-Token'] = 'wrong_token' + req = json.dumps({'action': 'authenticate', 'headers': headers}) + + msg_mock = mock.patch.object(self.protocol, 'sendMessage') + self.addCleanup(msg_mock.stop) + msg_mock = msg_mock.start() + # after authenticate failure, the _auth_app will be None and the + # request will raise 401 error. + self.protocol.onMessage(req, False) + self.protocol._auth_response('401 error', 'Failed') + resp = json.loads(msg_mock.call_args[0][0]) + + self.assertEqual(401, resp['headers']['status']) + self.assertEqual('authenticate', resp['request']['action']) + self.assertIsNone(self.protocol._auth_app) + + # try to authenticate again, "onMessage" should not return 403 because + # that the _auth_app was cleaned after auth failure. + headers['X-Auth-Token'] = 'mytoken' + req = json.dumps({'action': 'authenticate', 'headers': headers}) + self.protocol.onMessage(req, False) + + self.protocol._auth_response('200 OK', 'authenticate success') + resp = json.loads(msg_mock.call_args[0][0]) + self.assertEqual(200, resp['headers']['status']) + @ddt.data(True, False) def test_auth_response_serialization_format(self, in_binary): dumps, loads, create_req = test_utils.get_pack_tools(binary=in_binary) diff --git a/zaqar/transport/websocket/protocol.py b/zaqar/transport/websocket/protocol.py index b786ecab..304ef6f2 100644 --- a/zaqar/transport/websocket/protocol.py +++ b/zaqar/transport/websocket/protocol.py @@ -175,6 +175,10 @@ class MessagingProtocol(websocket.WebSocketServerProtocol): code = int(status.split()[0]) req = self._handler.create_request({'action': 'authenticate'}) if code != 200: + # NOTE(wangxiyuan): _auth_app should be cleaned up the after the + # authentication failure so that the client can be authenticated + # again. + self._auth_app = None body = {'error': 'Authentication failed.'} resp = self._handler.create_response(code, body, req) self._send_response(resp, self._auth_in_binary)