def setUp(self): super().setUp() Config.objects.set_config('external_auth_url', 'https://auth.example.com') Config.objects.set_config('external_auth_admin_group', 'admins') self.auth = MacaroonAPIAuthentication() self.mock_service_key_request() self.mock_validate = self.patch(maasserver.macaroon_auth, 'validate_user_external_auth') self.mock_validate.return_value = True
class TestMacaroonAPIAuthentication(MAASServerTestCase, MacaroonBakeryMockMixin): def setUp(self): super().setUp() Config.objects.set_config('external_auth_url', 'https://auth.example.com') self.auth = MacaroonAPIAuthentication() self.mock_service_key_request() def get_request(self): request = factory.make_fake_request('/') # add external_auth_info to the request ExternalAuthInfoMiddleware().process_request(request) return request def test_is_authenticated_no_external_auth(self): # authentication details are provided self.mock_auth_info(username=factory.make_string()) # ... but external auth is disabled Config.objects.set_config('external_auth_url', '') self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_no_auth_details(self): self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth(self): user = factory.make_User() self.mock_auth_info(username=user.username) self.assertTrue(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth_creates_user(self): username = factory.make_string() self.mock_auth_info(username=username) self.assertTrue(self.auth.is_authenticated(self.get_request())) user = User.objects.get(username=username) self.assertIsNotNone(user.id) self.assertTrue(user.is_superuser) def test_challenge_no_external_auth(self): Config.objects.set_config('external_auth_url', '') response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) def test_challenge(self): response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) payload = json.loads(response.content) self.assertEqual(payload['Code'], 'macaroon discharge required') macaroon = payload['Info']['Macaroon'] # macaroon is requested for this service self.assertEqual(macaroon['location'], 'http://testserver/') # a third party caveat is added for the external authentication service third_party_urls = [ caveat['cl'] for caveat in macaroon['caveats'] if 'cl' in caveat ] self.assertEqual(third_party_urls, ['https://auth.example.com'])
class TestMacaroonAPIAuthentication(MAASServerTestCase, MacaroonBakeryMockMixin): def setUp(self): super().setUp() Config.objects.set_config('external_auth_url', 'https://auth.example.com') Config.objects.set_config('external_auth_admin_group', 'admins') self.auth = MacaroonAPIAuthentication() self.mock_service_key_request() self.mock_validate = self.patch(maasserver.macaroon_auth, 'validate_user_external_auth') self.mock_validate.return_value = True def get_request(self): request = factory.make_fake_request('/') # add external_auth_info to the request return ExternalAuthInfoMiddleware(lambda request: request)(request) def test_is_authenticated_no_external_auth(self): # authentication details are provided self.mock_auth_info(username=factory.make_string()) # ... but external auth is disabled Config.objects.set_config('external_auth_url', '') self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_no_auth_details(self): self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth(self): user = factory.make_User() self.mock_auth_info(username=user.username) self.assertTrue(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth_creates_user(self): username = factory.make_string() self.mock_auth_info(username=username) self.assertTrue(self.auth.is_authenticated(self.get_request())) user = User.objects.get(username=username) self.assertIsNotNone(user.id) self.assertFalse(user.is_superuser) self.assertFalse(user.userprofile.is_local) self.mock_validate.assert_called_with( user, ExternalAuthInfo(type='candid', url='https://auth.example.com', domain='', admin_group='admins')) def test_is_authenticated_user_exists_but_local(self): user = factory.make_User() user.userprofile.is_local = True user.userprofile.save() self.mock_auth_info(username=user.username) self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_validate_if_exists(self): user = factory.make_User() self.mock_auth_info(username=user.username) self.assertTrue(self.auth.is_authenticated(self.get_request())) self.mock_validate.assert_called() def test_is_authenticated_fails_if_not_validated(self): self.mock_validate.return_value = False user = factory.make_User() self.mock_auth_info(username=user.username) self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_challenge_no_external_auth(self): Config.objects.set_config('external_auth_url', '') response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) def test_challenge(self): response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) payload = json.loads(response.content) self.assertEqual(payload['Code'], 'macaroon discharge required') macaroon = payload['Info']['Macaroon'] # macaroon is requested for this service self.assertEqual(macaroon['location'], 'http://testserver/') # a third party caveat is added for the external authentication service third_party_urls = [ caveat['cl'] for caveat in macaroon['caveats'] if 'cl' in caveat ] self.assertEqual(third_party_urls, ['https://auth.example.com'])
if user.username not in SYSTEM_USERS: external_auth_info = request.external_auth_info is_local_user = user.userprofile.is_local if external_auth_info: if is_local_user: return False if not validate_user_external_auth( user, external_auth_info): return False elif not is_local_user: return False request.user = user request.consumer = consumer request.throttle_extra = token.consumer.id return True return False def challenge(self, request): # Beware: this returns 401: Unauthorized, not 403: Forbidden # as the name implies. return rc.FORBIDDEN # OAuth and macaroon-based authentication for the APIs. api_auth = ( MAASAPIAuthentication(realm="MAAS API"), MacaroonAPIAuthentication(), )
class TestMacaroonAPIAuthentication( MAASServerTestCase, MacaroonBakeryMockMixin ): def setUp(self): super().setUp() Config.objects.set_config( "external_auth_url", "https://auth.example.com" ) Config.objects.set_config("external_auth_admin_group", "admins") self.auth = MacaroonAPIAuthentication() self.mock_service_key_request() self.mock_validate = self.patch( maasserver.macaroon_auth, "validate_user_external_auth" ) self.mock_validate.return_value = True def get_request(self): request = factory.make_fake_request("/") # add external_auth_info to the request return ExternalAuthInfoMiddleware(lambda request: request)(request) def test_is_authenticated_no_external_auth(self): # authentication details are provided self.mock_auth_info(username=factory.make_string()) # ... but external auth is disabled Config.objects.set_config("external_auth_url", "") self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_no_auth_details(self): self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth(self): user = factory.make_User() self.mock_auth_info(username=user.username) self.assertTrue(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_with_auth_creates_user(self): username = factory.make_string() self.mock_auth_info(username=username) self.assertTrue(self.auth.is_authenticated(self.get_request())) user = User.objects.get(username=username) self.assertIsNotNone(user.id) self.assertFalse(user.is_superuser) self.assertFalse(user.userprofile.is_local) self.mock_validate.assert_called_with( user, ExternalAuthInfo( type="candid", url="https://auth.example.com", domain="", admin_group="admins", ), ) def test_is_authenticated_user_exists_but_local(self): user = factory.make_User() user.userprofile.is_local = True user.userprofile.save() self.mock_auth_info(username=user.username) self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_is_authenticated_validate_if_exists(self): user = factory.make_User() self.mock_auth_info(username=user.username) self.assertTrue(self.auth.is_authenticated(self.get_request())) self.mock_validate.assert_called() def test_is_authenticated_fails_if_not_validated(self): self.mock_validate.return_value = False user = factory.make_User() self.mock_auth_info(username=user.username) self.assertFalse(self.auth.is_authenticated(self.get_request())) def test_challenge_no_external_auth(self): Config.objects.set_config("external_auth_url", "") response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) def test_challenge(self): response = self.auth.challenge(self.get_request()) self.assertEqual(response.status_code, 401) payload = json.loads(response.content) self.assertEqual(payload["Code"], "macaroon discharge required") macaroon = payload["Info"]["Macaroon"] # macaroon is requested for this service self.assertEqual(macaroon["location"], "http://testserver/") # a third party caveat is added for the external authentication service third_party_urls = [ caveat["cl"] for caveat in macaroon["caveats"] if "cl" in caveat ] self.assertEqual(third_party_urls, ["https://auth.example.com"])
def setUp(self): super().setUp() Config.objects.set_config('external_auth_url', 'https://auth.example.com') self.auth = MacaroonAPIAuthentication() self.mock_service_key_request()