From 4d9b3c914196163264d47d26147568ebf9b9b484 Mon Sep 17 00:00:00 2001 From: Thomas Herve Date: Mon, 17 Aug 2015 16:51:40 +0200 Subject: [PATCH] Fix WS deauthenticate Properly handle timezones in the WebSocket deauthenticate call. It also updates the example to handle auth, and pass the proper action in results. Change-Id: I7b3b38764e6d275f9c2b29c8a09a6a947bf9bebf --- examples/websocket.html | 61 +++++++++++++++++-- .../transport/websocket/v1_1/test_auth.py | 1 + zaqar/transport/websocket/protocol.py | 18 +++--- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/examples/websocket.html b/examples/websocket.html index fc79efe45..9f1e13991 100644 --- a/examples/websocket.html +++ b/examples/websocket.html @@ -16,6 +16,11 @@ margin: 0; padding: 1em; } + + #login { + background-color: #c7e8f2; + padding-left: 1em; + } #queues { padding-left: 1em; background-color: #bbb; @@ -38,7 +43,11 @@ var project = 'cf38008b72d04b89a505b9d66d1d5768'; var client_id = '31209ff3-ba03-4cec-b4ca-655f4899f8f4'; socket.onopen = function(evt) { - list_queues(); + var node = document.createElement('div'); + var msg = new Date().toUTCString(); + msg += " Connection opened" + node.appendChild(document.createTextNode(msg)); + $('#log').append(node); } socket.onmessage = function(evt) { var node = document.createElement('div'); @@ -57,12 +66,44 @@ } else if (action == 'message_list') { var messages = data['body']['messages']; display_messages(messages); - } else if (action == 'queue_create' || action == 'queue_delete') { + } else if (action == 'queue_create' || action == 'queue_delete' || action == 'authenticate') { list_queues(); } else if (action == 'message_post' || action == 'message_delete') { list_messages(); } } + login = function(frm) { + var data = { + 'auth': { + 'identity': { + 'methods': ['password'], + 'password': { + 'user': { + 'name': frm['user'].value, + 'domain': {'id': 'default'}, + 'password': frm['password'].value + } + } + } + } + } + $.ajax({ + 'type': 'POST', + 'url': 'http://localhost:5000/v3/auth/tokens', + 'data': JSON.stringify(data), + 'contentType': 'application/json', + 'dataType': 'json', + 'success': function(data, code, response) { + var token = response.getResponseHeader('X-Subject-Token') + var msg = {'action': 'authenticate', + 'headers': {'X-Auth-Token': token, + 'Client-ID': client_id, + 'X-Project-ID': project}} + socket.send(JSON.stringify(msg)); + } + }); + return false; + } send_message = function(action, body) { var msg = {'action': action, 'headers': {'Client-ID': client_id, 'X-Project-ID': project}} @@ -122,12 +163,22 @@

Zaqar WebSocket example

+
+
+
+ + + +
+
+
+

Queues

- +
@@ -145,8 +196,8 @@

Messages

- - + +
diff --git a/zaqar/tests/unit/transport/websocket/v1_1/test_auth.py b/zaqar/tests/unit/transport/websocket/v1_1/test_auth.py index 7b8ab771e..b5eb54b0b 100644 --- a/zaqar/tests/unit/transport/websocket/v1_1/test_auth.py +++ b/zaqar/tests/unit/transport/websocket/v1_1/test_auth.py @@ -89,6 +89,7 @@ class AuthTest(base.V1_1Base): self.assertEqual(1, msg_mock.call_count) resp = json.loads(msg_mock.call_args[0][0]) self.assertEqual(resp['headers']['status'], 401) + self.assertEqual(resp['request']['action'], 'authenticate') def test_reauth(self): headers = self.headers.copy() diff --git a/zaqar/transport/websocket/protocol.py b/zaqar/transport/websocket/protocol.py index 06b237a80..2335a951a 100644 --- a/zaqar/transport/websocket/protocol.py +++ b/zaqar/transport/websocket/protocol.py @@ -23,8 +23,6 @@ import pytz LOG = logging.getLogger(__name__) -_EPOCH = datetime.datetime(1970, 1, 1, tzinfo=pytz.UTC) - class MessagingProtocol(websocket.WebSocketServerProtocol): @@ -76,7 +74,7 @@ class MessagingProtocol(websocket.WebSocketServerProtocol): if self._auth_strategy and not self._authentified: if self._auth_app or payload.get('action') != 'authenticate': body = {'error': 'Not authentified.'} - resp = self._handler.create_response(403, body) + resp = self._handler.create_response(403, body, req) else: return self._authenticate(payload) elif payload.get('action') == 'authenticate': @@ -101,27 +99,29 @@ class MessagingProtocol(websocket.WebSocketServerProtocol): self._auth_app = None expire = env['keystone.token_info']['token']['expires_at'] expire_time = timeutils.parse_isotime(expire) - timestamp = (expire_time - _EPOCH).total_seconds() + now = datetime.datetime.now(tz=pytz.UTC) + delta = (expire_time - now).total_seconds() if self._deauth_handle is not None: self._deauth_handle.cancel() - self._deauth_handle = self._loop.call_at( - timestamp, self._deauthenticate) + self._deauth_handle = self._loop.call_later( + delta, self._deauthenticate) start_response('200 OK', []) def _deauthenticate(self): self._authentified = False - self.sendClose(403, 'Authentication expired.') + self.sendClose(4003, u'Authentication expired.') def _auth_response(self, status, message): code = int(status.split()[0]) + req = self._handler.create_request({'action': 'authenticate'}) if code != 200: body = {'error': 'Authentication failed.'} - resp = self._handler.create_response(code, body) + resp = self._handler.create_response(code, body, req) self._send_response(resp) else: body = {'message': 'Authentified.'} - resp = self._handler.create_response(200, body) + resp = self._handler.create_response(200, body, req) self._send_response(resp) def _header_to_env_var(self, key):