Merge lp:~alisonken1/openlp/bug-1593883-projector-authentication into lp:openlp

Proposed by Ken Roberts
Status: Merged
Merged at revision: 2678
Proposed branch: lp:~alisonken1/openlp/bug-1593883-projector-authentication
Merge into: lp:openlp
Diff against target: 172 lines (+74/-12)
5 files modified
openlp/core/common/__init__.py (+4/-3)
openlp/core/lib/projector/pjlink1.py (+16/-5)
openlp/plugins/presentations/lib/powerpointcontroller.py (+1/-1)
tests/functional/openlp_core_common/test_projector_utilities.py (+2/-2)
tests/functional/openlp_core_lib/test_projector_pjlink1.py (+51/-1)
To merge this branch: bzr merge lp:~alisonken1/openlp/bug-1593883-projector-authentication
Reviewer Review Type Date Requested Status
Tomas Groth Approve
Tim Bentley Approve
Review via email: mp+297819@code.launchpad.net

Commit message

Bugfix 1593882 and 1593883 - projector authorization

Description of the change

Bugfix 1593882 and 1593883 - projector authorization

- Fix exception when authenticated connection requested and pin is None
- Fix pjlink authentication (use python hash instead of qt hash)
- Fix md5_hash functions
- Fix qmd5hash functions
- Added tests for bugfixes
Tested with test server and Eiki XL200 projector

--------------------------------
lp:~alisonken1/openlp/bug-1593883-projector-authentication (revision 2684)
[SUCCESS] https://ci.openlp.io/job/Branch-01-Pull/1629/
[SUCCESS] https://ci.openlp.io/job/Branch-02-Functional-Tests/1540/
[SUCCESS] https://ci.openlp.io/job/Branch-03-Interface-Tests/1478/
[SUCCESS] https://ci.openlp.io/job/Branch-04a-Windows_Functional_Tests/1247/
[SUCCESS] https://ci.openlp.io/job/Branch-04b-Windows_Interface_Tests/837/
[SUCCESS] https://ci.openlp.io/job/Branch-05a-Code_Analysis/905/
[SUCCESS] https://ci.openlp.io/job/Branch-05b-Test_Coverage/773/

To post a comment you must log in.
Revision history for this message
Tim Bentley (trb143) :
review: Approve
2685. By Ken Roberts

Format fix

Revision history for this message
Tomas Groth (tomasgroth) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'openlp/core/common/__init__.py'
2--- openlp/core/common/__init__.py 2016-05-05 19:37:48 +0000
3+++ openlp/core/common/__init__.py 2016-06-27 00:09:03 +0000
4@@ -226,10 +226,11 @@
5 log.debug('qmd5_hash(salt="{text}"'.format(text=salt))
6 hash_obj = QHash(QHash.Md5)
7 hash_obj.addData(salt)
8- hash_obj.addData(data)
9+ if data:
10+ hash_obj.addData(data)
11 hash_value = hash_obj.result().toHex()
12- log.debug('qmd5_hash() returning "{text}"'.format(text=hash_value))
13- return hash_value.data()
14+ log.debug('qmd5_hash() returning "{hash}"'.format(hash=hash_value))
15+ return hash_value
16
17
18 def clean_button_text(button_text):
19
20=== modified file 'openlp/core/lib/projector/pjlink1.py'
21--- openlp/core/lib/projector/pjlink1.py 2016-05-28 05:50:31 +0000
22+++ openlp/core/lib/projector/pjlink1.py 2016-06-27 00:09:03 +0000
23@@ -49,7 +49,7 @@
24 from PyQt5.QtCore import pyqtSignal, pyqtSlot
25 from PyQt5.QtNetwork import QAbstractSocket, QTcpSocket
26
27-from openlp.core.common import translate, qmd5_hash
28+from openlp.core.common import translate, md5_hash
29 from openlp.core.lib.projector.constants import *
30
31 # Shortcuts
32@@ -297,6 +297,8 @@
33 Processes the initial connection and authentication (if needed).
34 Starts poll timer if connection is established.
35
36+ NOTE: Qt md5 hash function doesn't work with projector authentication. Use the python md5 hash function.
37+
38 :param data: Optional data if called from another routine
39 """
40 log.debug('({ip}) check_login(data="{data}")'.format(ip=self.ip, data=data))
41@@ -344,16 +346,25 @@
42 return
43 elif data_check[1] == '0' and self.pin is not None:
44 # Pin set and no authentication needed
45+ log.warning('({ip}) Regular connection but PIN set'.format(ip=self.name))
46 self.disconnect_from_host()
47 self.change_status(E_AUTHENTICATION)
48- log.debug('({ip}) emitting projectorNoAuthentication() signal'.format(ip=self.name))
49+ log.debug('({ip}) Emitting projectorNoAuthentication() signal'.format(ip=self.name))
50 self.projectorNoAuthentication.emit(self.name)
51 return
52 elif data_check[1] == '1':
53 # Authenticated login with salt
54- log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2]))
55- log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin))
56- salt = qmd5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii'))
57+ if self.pin is None:
58+ log.warning('({ip}) Authenticated connection but no pin set'.format(ip=self.name))
59+ self.disconnect_from_host()
60+ self.change_status(E_AUTHENTICATION)
61+ log.debug('({ip}) Emitting projectorAuthentication() signal'.format(ip=self.name))
62+ self.projectorAuthentication.emit(self.name)
63+ return
64+ else:
65+ log.debug('({ip}) Setting hash with salt="{data}"'.format(ip=self.ip, data=data_check[2]))
66+ log.debug('({ip}) pin="{data}"'.format(ip=self.ip, data=self.pin))
67+ salt = md5_hash(salt=data_check[2].encode('ascii'), data=self.pin.encode('ascii'))
68 else:
69 salt = None
70 # We're connected at this point, so go ahead and do regular I/O
71
72=== modified file 'openlp/plugins/presentations/lib/powerpointcontroller.py'
73--- openlp/plugins/presentations/lib/powerpointcontroller.py 2016-05-21 18:19:18 +0000
74+++ openlp/plugins/presentations/lib/powerpointcontroller.py 2016-06-27 00:09:03 +0000
75@@ -362,7 +362,7 @@
76 # it is the powerpoint presentation window.
77 (left, top, right, bottom) = win32gui.GetWindowRect(hwnd)
78 window_title = win32gui.GetWindowText(hwnd)
79- log.debug('window size: left=left:d}, top={top:d}, '
80+ log.debug('window size: left={left:d}, top={top:d}, '
81 'right={right:d}, bottom={bottom:d}'.format(left=left, top=top, right=right, bottom=bottom))
82 log.debug('compare size: {y:d} and {top:d}, {height:d} and {vertical:d}, '
83 '{x:d} and {left}, {width:d} and {horizontal:d}'.format(y=size.y(),
84
85=== modified file 'tests/functional/openlp_core_common/test_projector_utilities.py'
86--- tests/functional/openlp_core_common/test_projector_utilities.py 2016-04-17 18:48:50 +0000
87+++ tests/functional/openlp_core_common/test_projector_utilities.py 2016-06-27 00:09:03 +0000
88@@ -147,7 +147,7 @@
89 hash_ = qmd5_hash(salt=salt.encode('ascii'), data=pin.encode('ascii'))
90
91 # THEN: Validate return has is same
92- self.assertEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a good hash')
93+ self.assertEquals(hash_, test_hash, 'Qt-MD5 should have returned a good hash')
94
95 def test_qmd5_hash_bad(self):
96 """
97@@ -157,7 +157,7 @@
98 hash_ = qmd5_hash(salt=pin.encode('ascii'), data=salt.encode('ascii'))
99
100 # THEN: return data is different
101- self.assertNotEquals(hash_.decode('ascii'), test_hash, 'Qt-MD5 should have returned a bad hash')
102+ self.assertNotEquals(hash_, test_hash, 'Qt-MD5 should have returned a bad hash')
103
104 def test_md5_non_ascii_string(self):
105 """
106
107=== modified file 'tests/functional/openlp_core_lib/test_projector_pjlink1.py'
108--- tests/functional/openlp_core_lib/test_projector_pjlink1.py 2016-05-31 21:40:13 +0000
109+++ tests/functional/openlp_core_lib/test_projector_pjlink1.py 2016-06-27 00:09:03 +0000
110@@ -30,7 +30,7 @@
111 S_COOLDOWN, PJLINK_POWR_STATUS
112
113 from tests.functional import patch
114-from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE
115+from tests.resources.projector.data import TEST_PIN, TEST_SALT, TEST_CONNECT_AUTHENTICATE, TEST_HASH
116
117 pjlink_test = PJLink1(name='test', ip='127.0.0.1', pin=TEST_PIN, no_poll=True)
118
119@@ -332,3 +332,53 @@
120 self.assertFalse(pjlink.send_busy, 'Projector send_busy should be False')
121 self.assertTrue(mock_timer.called, 'Projector timer.stop() should have been called')
122 self.assertTrue(mock_socket_timer.called, 'Projector socket_timer.stop() should have been called')
123+
124+ @patch.object(pjlink_test, 'send_command')
125+ @patch.object(pjlink_test, 'waitForReadyRead')
126+ @patch.object(pjlink_test, 'projectorAuthentication')
127+ @patch.object(pjlink_test, 'timer')
128+ @patch.object(pjlink_test, 'socket_timer')
129+ def test_bug_1593882_no_pin_authenticated_connection(self, mock_socket_timer,
130+ mock_timer,
131+ mock_authentication,
132+ mock_ready_read,
133+ mock_send_command):
134+ """
135+ Test bug 1593882 no pin and authenticated request exception
136+ """
137+ # GIVEN: Test object and mocks
138+ pjlink = pjlink_test
139+ pjlink.pin = None
140+ mock_ready_read.return_value = True
141+
142+ # WHEN: call with authentication request and pin not set
143+ pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
144+
145+ # THEN: No Authentication signal should have been sent
146+ mock_authentication.emit.assert_called_with(pjlink.name)
147+
148+ @patch.object(pjlink_test, 'waitForReadyRead')
149+ @patch.object(pjlink_test, 'state')
150+ @patch.object(pjlink_test, '_send_command')
151+ @patch.object(pjlink_test, 'timer')
152+ @patch.object(pjlink_test, 'socket_timer')
153+ def test_bug_1593883_pjlink_authentication(self, mock_socket_timer,
154+ mock_timer,
155+ mock_send_command,
156+ mock_state,
157+ mock_waitForReadyRead):
158+ """
159+ Test bugfix 1593883 pjlink authentication
160+ """
161+ # GIVEN: Test object and data
162+ pjlink = pjlink_test
163+ pjlink.pin = TEST_PIN
164+ mock_state.return_value = pjlink.ConnectedState
165+ mock_waitForReadyRead.return_value = True
166+
167+ # WHEN: Athenticated connection is called
168+ pjlink.check_login(data=TEST_CONNECT_AUTHENTICATE)
169+
170+ # THEN: send_command should have the proper authentication
171+ self.assertEquals("{test}".format(test=mock_send_command.call_args),
172+ "call(data='{hash}%1CLSS ?\\r')".format(hash=TEST_HASH))