diff --git a/kmip/core/messages/contents.py b/kmip/core/messages/contents.py index 8d4ebb4..f30a4b4 100644 --- a/kmip/core/messages/contents.py +++ b/kmip/core/messages/contents.py @@ -265,37 +265,120 @@ class TimeStamp(DateTime): super(TimeStamp, self).__init__(value, enums.Tags.TIME_STAMP) -# 6.6 class Authentication(Struct): + """ + A struct representing an Authentication bundle. - def __init__(self, credential=None): + Attributes: + credentials: A list of Credential structs to be used for + authentication. + """ + + def __init__(self, credentials=None): + """ + Construct an Authentication struct. + + Args: + credentials (list): A list of Credential structs to be used for + authentication. Optional, defaults to None. + """ super(Authentication, self).__init__(enums.Tags.AUTHENTICATION) - self.credential = credential - def read(self, istream): - super(Authentication, self).read(istream) - tstream = utils.BytearrayStream(istream.read(self.length)) + self._credentials = [] + self.credentials = credentials - # Read the credential - self.credential = objects.Credential() - self.credential.read(tstream) + @property + def credentials(self): + return self._credentials - self.is_oversized(tstream) + @credentials.setter + def credentials(self, value): + if value is None: + self._credentials = [] + elif isinstance(value, list): + credentials = [] + for i in range(len(value)): + credential = value[i] + if not isinstance(credential, objects.Credential): + raise TypeError( + "Credentials must be a list of Credential structs. " + "Item {} has type: {}".format(i + 1, type(credential)) + ) + credentials.append(credential) + self._credentials = credentials + else: + raise TypeError( + "Credentials must be a list of Credential structs." + ) - def write(self, ostream): - tstream = utils.BytearrayStream() + def read(self, input_stream): + """ + Read the data encoding the Authentication struct and decode it into + its constituent parts. - # Write the credential - self.credential.write(tstream) + Args: + input_stream (stream): A data stream containing encoded object + data, supporting a read method; usually a BytearrayStream + object. + """ + super(Authentication, self).read(input_stream) + local_stream = utils.BytearrayStream(input_stream.read(self.length)) - # Write the length and value of the protocol version - self.length = tstream.length() - super(Authentication, self).write(ostream) - ostream.write(tstream.buffer) + credentials = [] + while self.is_tag_next(enums.Tags.CREDENTIAL, local_stream): + credential = objects.Credential() + credential.read(local_stream) + credentials.append(credential) + if len(credentials) == 0: + raise ValueError("Authentication encoding missing credentials.") + self._credentials = credentials - def validate(self): - # TODO (peter-hamilton) Finish implementation. - pass + self.is_oversized(local_stream) + + def write(self, output_stream): + """ + Write the data encoding the Authentication struct to a stream. + + Args: + output_stream (stream): A data stream in which to encode object + data, supporting a write method; usually a BytearrayStream + object. + """ + local_stream = utils.BytearrayStream() + + if len(self._credentials) == 0: + raise ValueError("Authentication struct missing credentials.") + for credential in self._credentials: + credential.write(local_stream) + + self.length = local_stream.length() + super(Authentication, self).write(output_stream) + output_stream.write(local_stream.buffer) + + def __eq__(self, other): + if isinstance(other, Authentication): + if self.credentials != other.credentials: + return False + else: + return True + else: + return NotImplemented + + def __ne__(self, other): + if isinstance(other, Authentication): + return not (self == other) + else: + return NotImplemented + + def __repr__(self): + args = ", ".join([ + "credentials={}".format([x for x in self.credentials]) + ]) + return "Authentication({})".format(args) + + def __str__(self): + credentials = ", ".join([str(x) for x in self.credentials]) + return "{'credentials': [" + credentials + "]}" # 6.7 diff --git a/kmip/services/kmip_client.py b/kmip/services/kmip_client.py index d145403..5b84e20 100644 --- a/kmip/services/kmip_client.py +++ b/kmip/services/kmip_client.py @@ -1348,7 +1348,7 @@ class KMIPProxy(KMIP): authentication = None if credential is not None: - authentication = Authentication(credential) + authentication = Authentication([credential]) batch_count = BatchCount(len(batch_items)) req_header = messages.RequestHeader(protocol_version=protocol_version, diff --git a/kmip/services/server/engine.py b/kmip/services/server/engine.py index 3d6cdf1..92768a2 100644 --- a/kmip/services/server/engine.py +++ b/kmip/services/server/engine.py @@ -328,7 +328,10 @@ class KmipEngine(object): # Process the authentication credentials if header.authentication: - auth_credentials = header.authentication.credential + if header.authentication.credentials: + auth_credentials = header.authentication.credentials[0] + else: + auth_credentials = None else: auth_credentials = None diff --git a/kmip/tests/unit/core/messages/contents/test_authentication.py b/kmip/tests/unit/core/messages/contents/test_authentication.py new file mode 100644 index 0000000..9a052ca --- /dev/null +++ b/kmip/tests/unit/core/messages/contents/test_authentication.py @@ -0,0 +1,988 @@ +# Copyright (c) 2018 The Johns Hopkins University/Applied Physics Laboratory +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import testtools + +from kmip.core import enums +from kmip.core import objects +from kmip.core import utils +from kmip.core.messages import contents + + +class TestAuthentication(testtools.TestCase): + """ + Test suite for the Authentication struct. + """ + + def setUp(self): + super(TestAuthentication, self).setUp() + + # Encoding obtained from the KMIP 1.1 testing document, Section 11.1. + # + # This encoding matches the following set of values: + # Authentication + # Credential + # CredentialType - Username and Password + # CredentialValue + # Username - Fred + # Password - password1 + self.username_password_encoding = utils.BytearrayStream( + b'\x42\x00\x0C\x01\x00\x00\x00\x48' + b'\x42\x00\x23\x01\x00\x00\x00\x40' + b'\x42\x00\x24\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x25\x01\x00\x00\x00\x28' + b'\x42\x00\x99\x07\x00\x00\x00\x04' + b'\x46\x72\x65\x64\x00\x00\x00\x00' + b'\x42\x00\xA1\x07\x00\x00\x00\x09' + b'\x70\x61\x73\x73\x77\x6F\x72\x64\x31\x00\x00\x00\x00\x00\x00\x00' + ) + self.encoding_missing_credentials = utils.BytearrayStream( + b'\x42\x00\x0C\x01\x00\x00\x00\x00' + ) + + # Encoding obtained from the KMIP 1.1 testing document, Section 11.2. + # + # This encoding matches the following set of values: + # Authentication + # Credential + # CredentialType - Device + # CredentialValue + # Device Serial Number - serNum123456 + # Password - secret + # Device Identifier - devID2233 + # Network Identifier - netID9000 + # Machine Identifier - machineID1 + # Media Identifier - mediaID313 + self.device_encoding = utils.BytearrayStream( + b'\x42\x00\x0C\x01\x00\x00\x00\xA8' + b'\x42\x00\x23\x01\x00\x00\x00\xA0' + b'\x42\x00\x24\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + b'\x42\x00\x25\x01\x00\x00\x00\x88' + b'\x42\x00\xB0\x07\x00\x00\x00\x0C' + b'\x73\x65\x72\x4E\x75\x6D\x31\x32\x33\x34\x35\x36\x00\x00\x00\x00' + b'\x42\x00\xA1\x07\x00\x00\x00\x06' + b'\x73\x65\x63\x72\x65\x74\x00\x00' + b'\x42\x00\xA2\x07\x00\x00\x00\x09' + b'\x64\x65\x76\x49\x44\x32\x32\x33\x33\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xAB\x07\x00\x00\x00\x09' + b'\x6E\x65\x74\x49\x44\x39\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xA9\x07\x00\x00\x00\x0A' + b'\x6D\x61\x63\x68\x69\x6E\x65\x49\x44\x31\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xAA\x07\x00\x00\x00\x0A' + b'\x6D\x65\x64\x69\x61\x49\x44\x33\x31\x33\x00\x00\x00\x00\x00\x00' + ) + + # Encoding obtained from the KMIP 1.1 testing document, combining + # encodings from Sections 11.1 and 11.2. + # + # This encoding matches the following set of values: + # Authentication + # Credential + # CredentialType - Username and Password + # CredentialValue + # Username - Fred + # Password - password1 + # Credential + # CredentialType - Device + # CredentialValue + # Device Serial Number - serNum123456 + # Password - secret + # Device Identifier - devID2233 + # Network Identifier - netID9000 + # Machine Identifier - machineID1 + # Media Identifier - mediaID313 + self.multiple_credentials_encoding = utils.BytearrayStream( + b'\x42\x00\x0C\x01\x00\x00\x00\xF0' + b'\x42\x00\x23\x01\x00\x00\x00\x40' + b'\x42\x00\x24\x05\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x00' + b'\x42\x00\x25\x01\x00\x00\x00\x28' + b'\x42\x00\x99\x07\x00\x00\x00\x04' + b'\x46\x72\x65\x64\x00\x00\x00\x00' + b'\x42\x00\xA1\x07\x00\x00\x00\x09' + b'\x70\x61\x73\x73\x77\x6F\x72\x64\x31\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\x23\x01\x00\x00\x00\xA0' + b'\x42\x00\x24\x05\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00' + b'\x42\x00\x25\x01\x00\x00\x00\x88' + b'\x42\x00\xB0\x07\x00\x00\x00\x0C' + b'\x73\x65\x72\x4E\x75\x6D\x31\x32\x33\x34\x35\x36\x00\x00\x00\x00' + b'\x42\x00\xA1\x07\x00\x00\x00\x06' + b'\x73\x65\x63\x72\x65\x74\x00\x00' + b'\x42\x00\xA2\x07\x00\x00\x00\x09' + b'\x64\x65\x76\x49\x44\x32\x32\x33\x33\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xAB\x07\x00\x00\x00\x09' + b'\x6E\x65\x74\x49\x44\x39\x30\x30\x30\x00\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xA9\x07\x00\x00\x00\x0A' + b'\x6D\x61\x63\x68\x69\x6E\x65\x49\x44\x31\x00\x00\x00\x00\x00\x00' + b'\x42\x00\xAA\x07\x00\x00\x00\x0A' + b'\x6D\x65\x64\x69\x61\x49\x44\x33\x31\x33\x00\x00\x00\x00\x00\x00' + ) + + def tearDown(self): + super(TestAuthentication, self).tearDown() + + def test_init(self): + """ + Test that an Authentication struct can be constructed without + arguments. + """ + authentication = contents.Authentication() + + self.assertEqual([], authentication.credentials) + + def test_init_with_args(self): + """ + Test that an Authentication struct can be constructed with arguments. + """ + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="John", + password="abc123" + ) + ) + ] + ) + + self.assertEqual(1, len(authentication.credentials)) + self.assertEqual( + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="John", + password="abc123" + ) + ), + authentication.credentials[0] + ) + + def test_invalid_credentials(self): + """ + Test that a TypeError is raised when an invalid value is used to set + the credentials of an Authentication struct. + """ + kwargs = {'credentials': 'invalid'} + self.assertRaisesRegexp( + TypeError, + "Credentials must be a list of Credential structs.", + contents.Authentication, + **kwargs + ) + + authentication = contents.Authentication() + args = (authentication, "credentials", 'invalid') + self.assertRaisesRegexp( + TypeError, + "Credentials must be a list of Credential structs.", + setattr, + *args + ) + + def test_invalid_credentials_list(self): + """ + Test that a TypeError is raised when an invalid list is used to set + the credentials of an Authentication struct. + """ + kwargs = { + 'credentials': [ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="John", + password="abc123" + ) + ), + 'invalid' + ] + } + self.assertRaisesRegexp( + TypeError, + "Credentials must be a list of Credential structs. Item 2 has " + "type: {}".format(type('invalid')), + contents.Authentication, + **kwargs + ) + + authentication = contents.Authentication() + args = ( + authentication, + "credentials", + [ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="John", + password="abc123" + ) + ), + 'invalid' + ] + ) + self.assertRaisesRegexp( + TypeError, + "Credentials must be a list of Credential structs. Item 2 has " + "type: {}".format(type('invalid')), + setattr, + *args + ) + + def test_read(self): + """ + Test that an Authentication struct can be read from a data stream. + """ + # Test with a single UsernamePasswordCredential. + authentication = contents.Authentication() + + self.assertEqual([], authentication.credentials) + + authentication.read(self.username_password_encoding) + + self.assertEqual(1, len(authentication.credentials)) + self.assertEqual( + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + authentication.credentials[0] + ) + + # Test with a single DeviceCredential. + authentication = contents.Authentication() + + self.assertEqual([], authentication.credentials) + + authentication.read(self.device_encoding) + + self.assertEqual(1, len(authentication.credentials)) + self.assertEqual( + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ), + authentication.credentials[0] + ) + + # Test with multiple Credentials. + authentication = contents.Authentication() + + self.assertEqual([], authentication.credentials) + + authentication.read(self.multiple_credentials_encoding) + + self.assertEqual(2, len(authentication.credentials)) + self.assertEqual( + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + authentication.credentials[0] + ) + self.assertEqual( + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ), + authentication.credentials[1] + ) + + def test_read_missing_credentials(self): + """ + Test that a ValueError gets raised when attempting to read an + Authentication struct from a data stream missing credentials data. + """ + authentication = contents.Authentication() + + self.assertEqual([], authentication.credentials) + + args = (self.encoding_missing_credentials, ) + self.assertRaisesRegexp( + ValueError, + "Authentication encoding missing credentials.", + authentication.read, + *args + ) + + def test_write(self): + """ + Test that an Authentication struct can be written to a data stream. + """ + # Test with a single UsernamePasswordCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + stream = utils.BytearrayStream() + + authentication.write(stream) + + self.assertEqual(len(self.username_password_encoding), len(stream)) + self.assertEqual(str(self.username_password_encoding), str(stream)) + + # Test with a single DeviceCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + stream = utils.BytearrayStream() + + authentication.write(stream) + + self.assertEqual(len(self.device_encoding), len(stream)) + self.assertEqual(str(self.device_encoding), str(stream)) + + # Test with multiple Credentials. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + stream = utils.BytearrayStream() + + authentication.write(stream) + + self.assertEqual(len(self.multiple_credentials_encoding), len(stream)) + self.assertEqual(str(self.multiple_credentials_encoding), str(stream)) + + def test_write_missing_credentials(self): + """ + Test that a ValueError gets raised when attempting to write a + Authentication struct missing credentials data to a data stream. + """ + authentication = contents.Authentication() + stream = utils.BytearrayStream() + + args = (stream, ) + self.assertRaisesRegexp( + ValueError, + "Authentication struct missing credentials.", + authentication.write, + *args + ) + + def test_equal_on_equal(self): + """ + Test that the equality operator returns True when comparing two + Authentication structs with the same data. + """ + a = contents.Authentication() + b = contents.Authentication() + + self.assertTrue(a == b) + self.assertTrue(b == a) + + # Test with a single UsernamePasswordCredential. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + # Test with a single DeviceCredential. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + # Test with multiple Credentials. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertTrue(a == b) + self.assertTrue(b == a) + + def test_equal_on_not_equal_credentials(self): + """ + Test that the equality operator returns False when comparing two + Authentication structs with different credentials. + """ + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_equal_on_type_mismatch(self): + """ + Test that the equality operator returns False when comparing two + Authentication structs with different types. + """ + a = contents.Authentication() + b = 'invalid' + + self.assertFalse(a == b) + self.assertFalse(b == a) + + def test_not_equal_on_equal(self): + """ + Test that the inequality operator returns False when comparing two + Authentication structs with the same data. + """ + a = contents.Authentication() + b = contents.Authentication() + + self.assertFalse(a != b) + self.assertFalse(b != a) + + # Test with a single UsernamePasswordCredential. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + # Test with a single DeviceCredential. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + # Test with multiple Credentials. + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertFalse(a != b) + self.assertFalse(b != a) + + def test_not_equal_on_not_equal_credentials(self): + """ + Test that the inequality operator returns True when comparing two + Authentication structs with different credentials. + """ + a = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + b = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_not_equal_on_type_mismatch(self): + """ + Test that the inequality operator returns True when comparing two + Authentication structs with different types. + """ + a = contents.Authentication() + b = 'invalid' + + self.assertTrue(a != b) + self.assertTrue(b != a) + + def test_repr(self): + """ + Test that repr can be applied to an Authentication struct. + """ + # Test with a UsernamePasswordCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + expected = ( + "Authentication(" + "credentials=[" + "Credential(" + "credential_type=CredentialType.USERNAME_AND_PASSWORD, " + "credential_value=UsernamePasswordCredential(" + "username='Fred', " + "password='password1'))])" + ) + observed = repr(authentication) + + self.assertEqual(expected, observed) + + # Test with a DeviceCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + expected = ( + "Authentication(" + "credentials=[" + "Credential(" + "credential_type=CredentialType.DEVICE, " + "credential_value=DeviceCredential(" + "device_serial_number='serNum123456', " + "password='secret', " + "device_identifier='devID2233', " + "network_identifier='netID9000', " + "machine_identifier='machineID1', " + "media_identifier='mediaID313'))])" + ) + observed = repr(authentication) + + self.assertEqual(expected, observed) + + # Test with multiple Credentials. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + expected = ( + "Authentication(" + "credentials=[" + "Credential(" + "credential_type=CredentialType.USERNAME_AND_PASSWORD, " + "credential_value=UsernamePasswordCredential(" + "username='Fred', " + "password='password1')), " + "Credential(" + "credential_type=CredentialType.DEVICE, " + "credential_value=DeviceCredential(" + "device_serial_number='serNum123456', " + "password='secret', " + "device_identifier='devID2233', " + "network_identifier='netID9000', " + "machine_identifier='machineID1', " + "media_identifier='mediaID313'))])" + ) + observed = repr(authentication) + + self.assertEqual(expected, observed) + + def test_str(self): + """ + Test that str can be applied to an Authentication struct. + """ + # Test with a UsernamePasswordCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ) + ] + ) + expected = str({ + "credentials": [ + { + "credential_type": + enums.CredentialType.USERNAME_AND_PASSWORD, + "credential_value": str({ + "username": "Fred", + "password": "password1" + }) + } + ] + }) + observed = str(authentication) + + self.assertEqual(expected, observed) + + # Test with a DeviceCredential. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + expected = str({ + "credentials": [ + { + "credential_type": enums.CredentialType.DEVICE, + "credential_value": str({ + "device_serial_number": "serNum123456", + "password": "secret", + "device_identifier": "devID2233", + "network_identifier": "netID9000", + "machine_identifier": "machineID1", + "media_identifier": "mediaID313" + }) + } + ] + }) + observed = str(authentication) + + self.assertEqual(expected, observed) + + # Test with multiple Credentials. + authentication = contents.Authentication( + credentials=[ + objects.Credential( + credential_type=enums.CredentialType.USERNAME_AND_PASSWORD, + credential_value=objects.UsernamePasswordCredential( + username="Fred", + password="password1" + ) + ), + objects.Credential( + credential_type=enums.CredentialType.DEVICE, + credential_value=objects.DeviceCredential( + device_serial_number="serNum123456", + password="secret", + device_identifier="devID2233", + network_identifier="netID9000", + machine_identifier="machineID1", + media_identifier="mediaID313" + ) + ) + ] + ) + expected = str({ + "credentials": [ + { + "credential_type": + enums.CredentialType.USERNAME_AND_PASSWORD, + "credential_value": str({ + "username": "Fred", + "password": "password1" + }) + }, + { + "credential_type": enums.CredentialType.DEVICE, + "credential_value": str({ + "device_serial_number": "serNum123456", + "password": "secret", + "device_identifier": "devID2233", + "network_identifier": "netID9000", + "machine_identifier": "machineID1", + "media_identifier": "mediaID313" + }) + } + ] + }) + observed = str(authentication) + + self.assertEqual(expected, observed)