diff --git a/python/samba/tests/blackbox/claims.py b/python/samba/tests/blackbox/claims.py index ac8fac79418..1c6cddcec24 100755 --- a/python/samba/tests/blackbox/claims.py +++ b/python/samba/tests/blackbox/claims.py @@ -205,6 +205,128 @@ class ClaimsSupportTests(BlackboxTestCase): device_password=device_password, ) + def test_device_and_server_silo_restrictions(self): + client_password = "T3stPassword0nly" + target_password = "T3stC0mputerPassword" + device_password = "T3stD3vicePassword" + + # Create target computer. + self.check_run("computer create claims-server") + self.addCleanup(self.run_command, "computer delete claims-server") + self.check_run(rf"user setpassword claims-server\$ --newpassword={target_password}") + + # Create device computer. + self.check_run("computer create claims-device") + self.addCleanup(self.run_command, "computer delete claims-device") + self.check_run(rf"user setpassword claims-device\$ --newpassword={device_password}") + + # Create a user. + self.check_run(f"user create claimstestuser {client_password}") + self.addCleanup(self.run_command, "user delete claimstestuser") + + # Create an authentication policy. + self.check_run("domain auth policy create --enforce --name=allowed-devices-only-pol") + self.addCleanup(self.run_command, + "domain auth policy delete --name=allowed-devices-only-pol") + + # Create an authentication silo. + self.check_run("domain auth silo create --enforce --name=allowed-devices-only-silo " + "--user-authentication-policy=allowed-devices-only-pol " + "--computer-authentication-policy=allowed-devices-only-pol " + "--service-authentication-policy=allowed-devices-only-pol") + self.addCleanup(self.run_command, + "domain auth silo delete --name=allowed-devices-only-silo") + + # Set allowed to authenticate from (where the login can happen) and to + # (server requires silo that in term has this rule, so knows the user + # was required to authenticate from). + # If we assigned services to the silo we would need to add + # --service-allowed-to-authenticate-to/from options as well. + # Likewise, if there are services running in user accounts, we need + # --user-allowed-to-authenticate-to + self.check_run(f"domain auth policy modify --name=allowed-devices-only-pol " + "--user-allowed-to-authenticate-from-device-silo=allowed-devices-only-silo " + "--computer-allowed-to-authenticate-to-by-silo=allowed-devices-only-silo") + + # Grant access to silo. + self.check_run(r"domain auth silo member grant --name=allowed-devices-only-silo --member=claims-device\$") + self.check_run(r"domain auth silo member grant --name=allowed-devices-only-silo --member=claims-server\$") + self.check_run("domain auth silo member grant --name=allowed-devices-only-silo --member=claimstestuser") + + # However with nothing assigned, allow-by-default still applies + self.verify_access( + client_username="claimstestuser", + client_password=client_password, + target_hostname="claims-server", + target_username="claims-server", + target_password=target_password, + ) + + # Show that adding a FAST armor from the device doesn't change + # things either way + self.verify_access( + client_username="claimstestuser", + client_password=client_password, + target_hostname="claims-server", + target_username="claims-server", + target_password=target_password, + device_username="claims-device", + device_password=device_password, + ) + + self.check_run(r"user auth silo assign claims-server\$ --silo=allowed-devices-only-silo") + + # We fail, as the server now requires the silo but the client is not in it + with self.assertRaises(NTSTATUSError) as error: + self.verify_access( + client_username="claimstestuser", + client_password=client_password, + target_hostname="claims-server", + target_username="claims-server", + target_password=target_password, + device_username="claims-device", + device_password=device_password, + ) + + self.assertEqual(error.exception.args[0], NT_STATUS_LOGON_FAILURE) + self.assertEqual( + error.exception.args[1], + "The attempted logon is invalid. This is either due to a " + "bad username or authentication information.") + + # Assign silo to the user. + self.check_run("user auth silo assign claimstestuser --silo=allowed-devices-only-silo") + + # We fail, as the KDC now requires the silo but the client not is using an approved device + with self.assertRaises(NTSTATUSError) as error: + self.verify_access( + client_username="claimstestuser", + client_password=client_password, + target_hostname="claims-server", + target_username="claims-server", + target_password=target_password, + device_username="claims-device", + device_password=device_password, + ) + + self.assertEqual(error.exception.args[0], NT_STATUS_UNSUCCESSFUL) + self.assertIn( + "The requested operation was unsuccessful.", + error.exception.args[1]) + + # Assign silo to the device. + self.check_run(r"user auth silo assign claims-device\$ --silo=allowed-devices-only-silo") + + self.verify_access( + client_username="claimstestuser", + client_password=client_password, + target_hostname="claims-server", + target_username="claims-server", + target_password=target_password, + device_username="claims-device", + device_password=device_password, + ) + def test_user_group_access(self): """An example use with groups.""" client_password = "T3stPassword0nly" @@ -242,7 +364,7 @@ class ClaimsSupportTests(BlackboxTestCase): target_password=target_password, ) - self.assertEqual(error.exception.args[0], 3221225581) + self.assertEqual(error.exception.args[0], NT_STATUS_LOGON_FAILURE) self.assertEqual( error.exception.args[1], "The attempted logon is invalid. This is either due to a " @@ -313,7 +435,7 @@ class ClaimsSupportTests(BlackboxTestCase): target_password=target_password, ) - self.assertEqual(error.exception.args[0], 3221225581) + self.assertEqual(error.exception.args[0], NT_STATUS_LOGON_FAILURE) self.assertEqual( error.exception.args[1], "The attempted logon is invalid. This is either due to a "