Exemplo n.º 1
0
def _validate_user_rbac(auth_info, username, client=None):
    """Check if a user is active and/or superuser via RBAC."""
    if client is None:
        from maasserver.rbac import RBACClient

        client = RBACClient()

    try:
        is_admin = bool(
            client.allowed_for_user("maas", username, "admin")["admin"]
        )
        access_to_pools = any(
            client.allowed_for_user(
                "resource-pool",
                username,
                "view",
                "view-all",
                "deploy-machines",
                "admin-machines",
            ).values()
        )
        user_details = client.get_user_details(username)
    except APIError:
        raise UserValidationFailed()

    return (is_admin or access_to_pools, is_admin, user_details)
Exemplo n.º 2
0
class TestRBACClient(MAASServerTestCase):
    def setUp(self):
        super().setUp()
        key = PrivateKey.deserialize(
            "x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY=")
        agent = Agent(url="https://auth.example.com", username="******")
        auth_info = AuthInfo(key=key, agents=[agent])
        url = "https://rbac.example.com/"

        self.mock_request = self.patch(requests, "request")
        self.client = RBACClient(url=url, auth_info=auth_info)

    def test_default_config_from_settings(self):
        Config.objects.set_config("rbac_url", "https://rbac.example.com")
        Config.objects.set_config("external_auth_url",
                                  "https://auth.example.com")
        Config.objects.set_config("external_auth_user", "user@candid")
        Config.objects.set_config(
            "external_auth_key",
            "x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY=")
        client = RBACClient()
        self.assertEqual(client._url, "https://rbac.example.com")
        self.assertEqual(
            client._auth_info.key,
            PrivateKey.deserialize(
                "x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY="),
        )
        [agent] = client._auth_info.agents
        self.assertEqual(agent.url, "https://auth.example.com")
        self.assertEqual(agent.username, "user@candid")

    def test_get_user(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {
            "username": "******",
            "name": "A user",
            "email": "*****@*****.**",
        }
        self.mock_request.return_value = response
        details = self.client.get_user_details("user")
        self.assertEqual(details.username, "user")
        self.assertEqual(details.fullname, "A user")
        self.assertEqual(details.email, "*****@*****.**")
        self.mock_request.assert_called_once_with(
            "GET",
            "https://rbac.example.com/api/service/v1/user/user",
            auth=mock.ANY,
            cookies=mock.ANY,
            json=None,
        )

    def test_get_resources(self):
        resources = [
            {
                "identifier": "1",
                "name": "pool-1"
            },
            {
                "identifier": "2",
                "name": "pool-2"
            },
        ]
        response = mock.MagicMock(status_code=200)
        response.json.return_value = resources
        self.mock_request.return_value = response
        self.assertCountEqual(
            self.client.get_resources("resource-pool"),
            [
                Resource(identifier="1", name="pool-1"),
                Resource(identifier="2", name="pool-2"),
            ],
        )
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith(
                "GET",
                "https://rbac.example.com/api/"
                "service/v1/resources/resource-pool",
                auth=mock.ANY,
                cookies=mock.ANY,
                json=None,
            ),
        )

    def test_update_resources(self):
        updates = [
            Resource(identifier="1", name="pool-1"),
            Resource(identifier="2", name="pool-2"),
        ]
        removals = [11, 22, 33]
        json = {
            "last-sync-id":
            "a-b-c",
            "updates": [
                {
                    "identifier": "1",
                    "name": "pool-1"
                },
                {
                    "identifier": "2",
                    "name": "pool-2"
                },
            ],
            "removals": ["11", "22", "33"],
        }
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {"sync-id": "x-y-z"}
        self.mock_request.return_value = response
        sync_id = self.client.update_resources(
            "resource-pool",
            updates=updates,
            removals=removals,
            last_sync_id="a-b-c",
        )
        self.assertEqual(sync_id, "x-y-z")
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith(
                "POST",
                "https://rbac.example.com/api/"
                "service/v1/resources/resource-pool",
                auth=mock.ANY,
                cookies=mock.ANY,
                json=json,
            ),
        )

    def test_update_resources_no_sync_id(self):
        updates = [
            Resource(identifier="1", name="pool-1"),
            Resource(identifier="2", name="pool-2"),
        ]
        removals = [11, 22, 33]
        # removals are ignored
        json = {
            "last-sync-id":
            None,
            "updates": [
                {
                    "identifier": "1",
                    "name": "pool-1"
                },
                {
                    "identifier": "2",
                    "name": "pool-2"
                },
            ],
            "removals": [],
        }
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {"sync-id": "x-y-z"}
        self.mock_request.return_value = response
        sync_id = self.client.update_resources("resource-pool",
                                               updates=updates,
                                               removals=removals)
        self.assertEqual(sync_id, "x-y-z")
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith(
                "POST",
                "https://rbac.example.com/api/"
                "service/v1/resources/resource-pool",
                auth=mock.ANY,
                cookies=mock.ANY,
                json=json,
            ),
        )

    def test_update_resources_sync_conflict(self):
        updates = [
            Resource(identifier="1", name="pool-1"),
            Resource(identifier="2", name="pool-2"),
        ]
        removals = [11, 22, 33]
        response = mock.MagicMock(status_code=int(http.client.CONFLICT))
        response.json.return_value = {"sync-id": "x-y-z"}
        self.mock_request.return_value = response
        self.assertRaises(
            SyncConflictError,
            self.client.update_resources,
            "resource-pool",
            updates=updates,
            removals=removals,
            last_sync_id="a-b-c",
        )

    def test_allowed_for_user_all_resources(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {"admin": [""]}
        self.mock_request.return_value = response

        user = factory.make_name("user")
        self.assertEqual(
            {"admin": ALL_RESOURCES},
            self.client.allowed_for_user("maas", user, "admin"),
        )
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith(
                "GET",
                "https://rbac.example.com/api/"
                "service/v1/resources/maas/"
                "allowed-for-user?u={}&p=admin".format(user),
                auth=mock.ANY,
                cookies=mock.ANY,
                json=None,
            ),
        )

    def test_allowed_for_user_resource_ids(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {"admin": ["1", "2", "3"]}
        self.mock_request.return_value = response

        user = factory.make_name("user")
        self.assertEqual(
            {"admin": [1, 2, 3]},
            self.client.allowed_for_user("maas", user, "admin"),
        )
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith(
                "GET",
                "https://rbac.example.com/api/"
                "service/v1/resources/maas/"
                "allowed-for-user?u={}&p=admin".format(user),
                auth=mock.ANY,
                cookies=mock.ANY,
                json=None,
            ),
        )
Exemplo n.º 3
0
class TestRBACClient(MAASServerTestCase):
    def setUp(self):
        super().setUp()
        key = PrivateKey.deserialize(
            'x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY=')
        agent = Agent(url='https://auth.example.com', username='******')
        auth_info = AuthInfo(key=key, agents=[agent])
        url = 'https://rbac.example.com/'

        self.mock_request = self.patch(requests, 'request')
        self.client = RBACClient(url=url, auth_info=auth_info)

    def test_default_config_from_settings(self):
        Config.objects.set_config('rbac_url', 'https://rbac.example.com')
        Config.objects.set_config('external_auth_url',
                                  'https://auth.example.com')
        Config.objects.set_config('external_auth_user', 'user@candid')
        Config.objects.set_config(
            'external_auth_key',
            'x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY=')
        client = RBACClient()
        self.assertEqual(client._url, 'https://rbac.example.com')
        self.assertEqual(
            client._auth_info.key,
            PrivateKey.deserialize(
                'x0NeASLPFhOFfq3Q9M0joMveI4HjGwEuJ9dtX/HTSRY='))
        [agent] = client._auth_info.agents
        self.assertEqual(agent.url, 'https://auth.example.com')
        self.assertEqual(agent.username, 'user@candid')

    def test_get_user(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {
            'username': '******',
            'name': 'A user',
            'email': '*****@*****.**'
        }
        self.mock_request.return_value = response
        details = self.client.get_user_details('user')
        self.assertEqual(details.username, 'user')
        self.assertEqual(details.fullname, 'A user')
        self.assertEqual(details.email, '*****@*****.**')
        self.mock_request.assert_called_once_with(
            'GET',
            'https://rbac.example.com/api/service/v1/user/user',
            auth=mock.ANY,
            cookies=mock.ANY,
            json=None)

    def test_get_resources(self):
        resources = [
            {
                'identifier': '1',
                'name': 'pool-1',
            },
            {
                'identifier': '2',
                'name': 'pool-2',
            },
        ]
        response = mock.MagicMock(status_code=200)
        response.json.return_value = resources
        self.mock_request.return_value = response
        self.assertCountEqual(self.client.get_resources('resource-pool'), [
            Resource(identifier='1', name='pool-1'),
            Resource(identifier='2', name='pool-2'),
        ])
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith('GET', 'https://rbac.example.com/api/'
                               'service/v1/resources/resource-pool',
                               auth=mock.ANY,
                               cookies=mock.ANY,
                               json=None))

    def test_update_resources(self):
        updates = [
            Resource(identifier='1', name='pool-1'),
            Resource(identifier='2', name='pool-2'),
        ]
        removals = [11, 22, 33]
        json = {
            'last-sync-id':
            'a-b-c',
            'updates': [
                {
                    'identifier': '1',
                    'name': 'pool-1',
                },
                {
                    'identifier': '2',
                    'name': 'pool-2',
                },
            ],
            'removals': ['11', '22', '33']
        }
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'sync-id': 'x-y-z'}
        self.mock_request.return_value = response
        sync_id = self.client.update_resources('resource-pool',
                                               updates=updates,
                                               removals=removals,
                                               last_sync_id='a-b-c')
        self.assertEqual(sync_id, 'x-y-z')
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith('POST', 'https://rbac.example.com/api/'
                               'service/v1/resources/resource-pool',
                               auth=mock.ANY,
                               cookies=mock.ANY,
                               json=json))

    def test_update_resources_no_sync_id(self):
        updates = [
            Resource(identifier='1', name='pool-1'),
            Resource(identifier='2', name='pool-2'),
        ]
        removals = [11, 22, 33]
        # removals are ignored
        json = {
            'last-sync-id':
            None,
            'updates': [
                {
                    'identifier': '1',
                    'name': 'pool-1',
                },
                {
                    'identifier': '2',
                    'name': 'pool-2',
                },
            ],
            'removals': []
        }
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {'sync-id': 'x-y-z'}
        self.mock_request.return_value = response
        sync_id = self.client.update_resources('resource-pool',
                                               updates=updates,
                                               removals=removals)
        self.assertEqual(sync_id, 'x-y-z')
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith('POST', 'https://rbac.example.com/api/'
                               'service/v1/resources/resource-pool',
                               auth=mock.ANY,
                               cookies=mock.ANY,
                               json=json))

    def test_update_resources_sync_conflict(self):
        updates = [
            Resource(identifier='1', name='pool-1'),
            Resource(identifier='2', name='pool-2'),
        ]
        removals = [11, 22, 33]
        response = mock.MagicMock(status_code=int(http.client.CONFLICT))
        response.json.return_value = {'sync-id': 'x-y-z'}
        self.mock_request.return_value = response
        self.assertRaises(SyncConflictError,
                          self.client.update_resources,
                          'resource-pool',
                          updates=updates,
                          removals=removals,
                          last_sync_id='a-b-c')

    def test_allowed_for_user_all_resources(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {
            'admin': [''],
        }
        self.mock_request.return_value = response

        user = factory.make_name('user')
        self.assertEqual({'admin': ALL_RESOURCES},
                         self.client.allowed_for_user('maas', user, 'admin'))
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith('GET',
                               'https://rbac.example.com/api/'
                               'service/v1/resources/maas/'
                               'allowed-for-user?u={}&p=admin'.format(user),
                               auth=mock.ANY,
                               cookies=mock.ANY,
                               json=None))

    def test_allowed_for_user_resource_ids(self):
        response = mock.MagicMock(status_code=200)
        response.json.return_value = {
            'admin': ['1', '2', '3'],
        }
        self.mock_request.return_value = response

        user = factory.make_name('user')
        self.assertEqual({'admin': [1, 2, 3]},
                         self.client.allowed_for_user('maas', user, 'admin'))
        self.assertThat(
            self.mock_request,
            MockCalledOnceWith('GET',
                               'https://rbac.example.com/api/'
                               'service/v1/resources/maas/'
                               'allowed-for-user?u={}&p=admin'.format(user),
                               auth=mock.ANY,
                               cookies=mock.ANY,
                               json=None))