Beispiel #1
0
def accept_device(device_api, management_api, tenant_token=None):
    d = Device()
    da = DevAuthorizer(tenant_token)
    url = device_api.auth_requests_url
    kwargs = {}
    if tenant_token is not None:
        kwargs["Authorization"] = "Bearer " + tenant_token
    try:
        with orchestrator.run_fake_for_device_id(1) as server:
            with mock_tenantadm_auth():
                # poke devauth so that device appears
                rsp = device_auth_req(url, da, d)
                assert rsp.status_code == 401

            # try to find our devices in all devices listing
            dev = management_api.find_device_by_identity(d.identity, **kwargs)
            assert dev is not None

            print("found matching device with ID", dev.id)
            devid = dev.id
            # extract authentication data set ID
            aid = dev.auth_sets[0].id

        with orchestrator.run_fake_for_device_id(devid) as server:
            management_api.accept_device(devid, aid, **kwargs)
    except bravado.exception.HTTPError as e:
        assert e.response.status_code == 204

    return devid, d, da
Beispiel #2
0
def accepted_device(device_api, management_api, clean_migrated_db):
    """Fixture that sets up an accepted device. Yields a tuple:
       (device ID, instance of Device, instance of DevAuthorizer)"""
    d = Device()
    da = DevAuthorizer()
    url = device_api.auth_requests_url

    try:
        with orchestrator.run_fake_for_device_id(1) as server:
            # poke devauth so that device appears
            rsp = device_auth_req(url, da, d)
            assert rsp.status_code == 401

            # try to find our devices in all devices listing
            dev = management_api.find_device_by_identity(d.identity)

            print('found matching device with ID', dev.id)
            devid = dev.id
            # extract authentication data set ID
            aid = dev.auth_sets[0].id

        with orchestrator.run_fake_for_device_id(devid) as server:
            management_api.accept_device(devid, aid)
    except bravado.exception.HTTPError as e:
        assert e.response.status_code == 204

    yield (devid, d, da)
Beispiel #3
0
    def test_token_addons(
        self, test_case, clean_migrated_db, device_api, management_api, internal_api
    ):
        tenant_token = make_fake_tenant_token(
            "123456789012345678901234",
        )
        dev_auth = DevAuthorizer(tenant_token=tenant_token)
        jwt = None
        dev = accept_device(device_api, management_api, tenant_token)[1]
        with orchestrator.run_fake_for_device_id(1) as server:
            jwt = request_token(
                dev, dev_auth, device_api.auth_requests_url, test_case["addons"]
            )
            assert len(jwt) > 0

        rsp = requests.post(
            internal_api.api_url + "tokens/verify",
            data="",
            headers={
                "Authorization": "Bearer " + jwt,
                "X-Forwarded-Uri": test_case.get("forwarded_uri"),
                "X-Forwarded-Method": test_case.get("method"),
            },
        )
        assert rsp.status_code == test_case.get("status_code", 200)
Beispiel #4
0
    def test_device_count_simple(self, devices, management_api):
        """We have 15 devices, each with a single auth set, verify that
        accepting/rejecting affects the count"""
        count = management_api.count_devices()

        assert count == 15

        pending_count = management_api.count_devices(status='pending')
        assert pending_count == 15

        # accept device[0] and reject device[1]
        for idx, (d, da) in enumerate(devices[0:2]):
            dev = management_api.find_device_by_identity(d.identity)

            assert dev
            devid = dev.id

            print('found matching device with ID:', dev.id)
            aid = dev.auth_sets[0].id

            try:
                with orchestrator.run_fake_for_device_id(devid) as server:
                    if idx == 0:
                        management_api.accept_device(devid, aid)
                    elif idx == 1:
                        management_api.reject_device(devid, aid)
            except bravado.exception.HTTPError as e:
                assert e.response.status_code == 204

        TestDevice.verify_device_count(management_api, 'pending', 13)
        TestDevice.verify_device_count(management_api, 'accepted', 1)
        TestDevice.verify_device_count(management_api, 'rejected', 1)
Beispiel #5
0
    def test_device_limit_applied(self, management_api, internal_api,
                                  tenant_foobar_devices, tenant_foobar):
        """Verify that max accepted devices limit is indeed applied. Since device
        limits can only be set on per-tenant basis, use fixtures that setup
        tenant 'foobar' with devices and a token
        """
        expected = 2
        internal_api.put_max_devices_limit('foobar', expected)

        accepted = 0
        try:
            with orchestrator.run_fake_for_device_id(orchestrator.ANY_DEVICE):
                for dev, dev_auth in tenant_foobar_devices:
                    auth = 'Bearer ' + tenant_foobar
                    fdev = management_api.find_device_by_identity(
                        dev.identity, Authorization=auth)
                    aid = fdev.auth_sets[0].id
                    management_api.accept_device(fdev.id,
                                                 aid,
                                                 Authorization=auth)
                    accepted += 1
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 422
        finally:
            if accepted > expected:
                pytest.fail(
                    "expected only {} devices to be accepted".format(expected))
Beispiel #6
0
    def _do_test_error_preauth_limit(self,
                                     management_api,
                                     device_api,
                                     tenant_token=""):
        auth = management_api.make_auth(tenant_token)
        devs = management_api.list_devices(**auth)
        assert len(devs) == 6

        limit = 3

        for i in range(limit):
            dev = devs[i]
            aid = dev.auth_sets[0].id
            with orchestrator.run_fake_for_device_id(dev.id):
                management_api.accept_device(dev.id, aid, **auth)

        try:
            d = Device(IDDATA)
            d.public_key = PUBKEY
            d.private_key = PRIVKEY

            da = DevAuthorizer(tenant_token)

            rsp = device_auth_req(device_api.auth_requests_url, da, d)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 401

        dev = management_api.find_device_by_identity(d.identity, **auth)
        assert dev.auth_sets[0].status == 'preauthorized'
    def test_auth_req_fake_tenantadm_valid_tenant_token(
            self, management_api, device_api, tenant_foobar):
        d = Device()
        da = DevAuthorizer(tenant_token=tenant_foobar)
        url = device_api.auth_requests_url

        handlers = [
            ('POST', '/api/internal/v1/tenantadm/tenants/verify', lambda _:
             (200, {}, {
                 'id': '507f191e810c19729de860ea',
                 'name': 'Acme',
             })),
        ]

        try:
            with orchestrator.run_fake_for_device_id(1) as server:
                with mockserver.run_fake(get_fake_tenantadm_addr(),
                                         handlers=handlers) as fake:
                    rsp = device_auth_req(url, da, d)
                    assert rsp.status_code == 401
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        # device should be appear in devices listing
        TestEnterprise.verify_tenant_dev_present(management_api,
                                                 d.identity,
                                                 tenant_foobar,
                                                 present=True)
Beispiel #8
0
    def change_status(self,
                      id,
                      device_id,
                      expected_initial,
                      expected_final,
                      expected_error_code=None,
                      auth=None):
        if auth is None:
            auth = self.uauth
        Status = self.client.get_model('Status')
        s = Status(status=expected_final)
        try:
            actual_initial = self.client.devices.get_devices_id(
                id=id, _request_options={
                    "headers": auth
                }).result()[0].status
            assert actual_initial == expected_initial
            with orchestrator.run_fake_for_device_id(device_id) as server:
                self.client.devices.put_devices_id_status(id=id,
                                                          status=s,
                                                          _request_options={
                                                              "headers": auth
                                                          }).result()
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == expected_error_code
            return
        else:
            if expected_error_code is not None:
                pytest.fail("Expected an exception, but didnt get any!")
                return

        assert self.client.devices.get_devices_id_status(
            id=id, _request_options={
                "headers": auth
            }).result()[0].status == expected_final
    def test_delete_device(self, management_api, devices):
        # try delete an existing device, verify decommissioning workflow was started
        # setup single device and poke devauth
        dev, _ = devices[0]
        ourdev = management_api.get_single_device()
        assert ourdev

        with orchestrator.run_fake_for_device_id(ourdev.id) as server:
            rsp = management_api.delete_device(
                ourdev.id,
                {
                    "X-MEN-RequestID": "delete_device",
                    "Authorization": "Bearer foobar",
                },
            )
        print("decommission request finished with status:", rsp.status_code)
        assert rsp.status_code == 204

        found = None
        status_code = None
        try:
            found = management_api.get_device(id=ourdev.id)
        except bravado.exception.HTTPError as e:
            status_code = e.response.status_code

        assert status_code == 404
        assert not found
    def test_device_accept_reject_cycle(self, devices, device_api,
                                        management_api):
        d, da = devices[0]
        url = device_api.auth_requests_url

        dev = management_api.get_single_device()

        assert dev
        devid = dev.id

        print("found device with ID:", dev.id)
        aid = dev.auth_sets[0].id

        with orchestrator.run_fake_for_device_id(devid) as server:
            _, rsp = management_api.accept_device(devid, aid)
            assert rsp.status_code == 204

            # device is accepted, we should get a token now
            rsp = device_auth_req(url, da, d)
            assert rsp.status_code == 200

            da.parse_rsp_payload(d, rsp.text)

            assert len(d.token) > 0

            # reject it now
            _, rsp = management_api.reject_device(devid, aid)
            print("RSP:", rsp)
            assert rsp.status_code == 204

            # device is rejected, should get unauthorized
            rsp = device_auth_req(url, da, d)
            assert rsp.status_code == 401
    def test_delete_tokens_by_non_existent_tenant_ok(self,
                                                     accepted_tenants_devices,
                                                     internal_api,
                                                     management_api,
                                                     device_api):
        try:
            td = accepted_tenants_devices

            tenant_foo_token = make_fake_tenant_token("foo")
            da_foo = DevAuthorizer(tenant_token=tenant_foo_token)
            d1_foo = td["foo"][0]
            with orchestrator.run_fake_for_device_id(1) as server:
                token1 = request_token(d1_foo, da_foo,
                                       device_api.auth_requests_url)
                assert len(token1) > 0
            d2_foo = td["foo"][1]
            with orchestrator.run_fake_for_device_id(2) as server:
                token2 = request_token(d2_foo, da_foo,
                                       device_api.auth_requests_url)
                assert len(token2) > 0

            tenant_bar_token = make_fake_tenant_token("bar")
            da_bar = DevAuthorizer(tenant_token=tenant_bar_token)
            d1_bar = td["bar"][0]
            with orchestrator.run_fake_for_device_id(1) as server:
                token3 = request_token(d1_bar, da_bar,
                                       device_api.auth_requests_url)
                assert len(token2) > 0

            verify_url = internal_api.make_api_url("/tokens/verify")
            verify_token(token1, 200, verify_url)
            verify_token(token2, 200, verify_url)
            verify_token(token3, 200, verify_url)

            dev1 = management_api.find_device_by_identity(
                d1_foo.identity, Authorization="Bearer " + tenant_foo_token)
            payload = {"tenant_id": "baz"}
            rsp = requests.delete(internal_api.make_api_url("/tokens"),
                                  params=payload)
            assert rsp.status_code == 204

            verify_token(token1, 200, verify_url)
            verify_token(token2, 200, verify_url)
            verify_token(token3, 200, verify_url)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204
    def test_delete_tokens_by_non_existent_device_ok(self,
                                                     accepted_tenants_devices,
                                                     internal_api,
                                                     management_api,
                                                     device_api):
        try:
            td = accepted_tenants_devices

            tenant_foo_token = make_fake_tenant_token('foo')
            da_foo = DevAuthorizer(tenant_token=tenant_foo_token)
            d1_foo = td['foo'][0]
            with orchestrator.run_fake_for_device_id(1) as server:
                token1 = request_token(d1_foo, da_foo,
                                       device_api.auth_requests_url)
                assert len(token1) > 0
            d2_foo = td['foo'][1]
            with orchestrator.run_fake_for_device_id(2) as server:
                token2 = request_token(d2_foo, da_foo,
                                       device_api.auth_requests_url)
                assert len(token2) > 0

            tenant_bar_token = make_fake_tenant_token('bar')
            da_bar = DevAuthorizer(tenant_token=tenant_bar_token)
            d1_bar = td['bar'][0]
            with orchestrator.run_fake_for_device_id(1) as server:
                token3 = request_token(d1_bar, da_bar,
                                       device_api.auth_requests_url)
                assert len(token2) > 0

            verify_url = internal_api.make_api_url("/tokens/verify")
            verify_token(token1, 200, verify_url)
            verify_token(token2, 200, verify_url)
            verify_token(token3, 200, verify_url)

            payload = {'device_id': 'foo', 'tenant_id': 'foo'}
            rsp = requests.delete(internal_api.make_api_url("/tokens"),
                                  params=payload)
            assert rsp.status_code == 204

            verify_token(token1, 200, verify_url)
            verify_token(token2, 200, verify_url)
            verify_token(token3, 200, verify_url)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204
Beispiel #13
0
def device_token(accepted_device, device_api):
    devid, d, da = accepted_device

    try:
        with orchestrator.run_fake_for_device_id(devid) as server:
            token = request_token(d, da, device_api.auth_requests_url)
    except bravado.exception.HTTPError as e:
        assert e.response.status_code == 204

    print("device token:", token)
    assert token
    yield token
Beispiel #14
0
    def test_device_accept_reject_cycle(self, devices, device_api,
                                        management_api):
        d, da = devices[0]
        url = device_api.auth_requests_url

        dev = management_api.find_device_by_identity(d.identity)

        assert dev
        devid = dev.id

        print("found matching device with ID:", dev.id)
        aid = dev.auth_sets[0].id

        try:
            with orchestrator.run_fake_for_device_id(devid) as server:
                management_api.accept_device(devid, aid)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        # device is accepted, we should get a token now
        try:
            with orchestrator.run_fake_for_device_id(devid) as server:
                rsp = device_auth_req(url, da, d)
                assert rsp.status_code == 200

                da.parse_rsp_payload(d, rsp.text)

                assert len(d.token) > 0

                # reject it now
                try:
                    management_api.reject_device(devid, aid)
                except bravado.exception.HTTPError as e:
                    assert e.response.status_code == 204

                # device is rejected, should get unauthorized
                rsp = device_auth_req(url, da, d)
                assert rsp.status_code == 401
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204
Beispiel #15
0
    def test_device_count_multiple_auth_sets(self, devices, management_api,
                                             device_api):
        """"Verify that auth sets are properly counted. Take a device, make sure it has
        2 auth sets, switch each auth sets between accepted/rejected/pending
        states
        """

        dev, dauth = devices[0]
        # pretend device rotates its keys
        dev.rotate_key()

        with deviceadm.run_fake_for_device(deviceadm.ANY_DEVICE) as server:
            device_auth_req(device_api.auth_requests_url, dauth, dev)

        # should have 2 auth sets now
        found_dev = management_api.find_device_by_identity(dev.identity)
        assert len(found_dev.auth_sets) == 2

        first_aid, second_aid = found_dev.auth_sets[0].id, found_dev.auth_sets[
            1].id

        # device [0] has 2 auth sets, but still counts as 1 device
        TestDevice.verify_device_count(management_api, 'pending', 5)

        devid = found_dev.id
        with orchestrator.run_fake_for_device_id(
                orchestrator.ANY_DEVICE) as server:
            # accept first auth set
            management_api.accept_device(devid, first_aid)

            TestDevice.verify_device_count(management_api, 'pending', 4)
            TestDevice.verify_device_count(management_api, 'accepted', 1)
            TestDevice.verify_device_count(management_api, 'rejected', 0)

            # reject the other
            management_api.reject_device(devid, second_aid)
            TestDevice.verify_device_count(management_api, 'pending', 4)
            TestDevice.verify_device_count(management_api, 'accepted', 1)
            TestDevice.verify_device_count(management_api, 'rejected', 0)

            # reject both
            management_api.reject_device(devid, first_aid)
            TestDevice.verify_device_count(management_api, 'pending', 4)
            TestDevice.verify_device_count(management_api, 'accepted', 0)
            TestDevice.verify_device_count(management_api, 'rejected', 1)

            # switch the first back to pending, 2nd remains rejected
            management_api.put_device_status(devid, first_aid, 'pending')
            TestDevice.verify_device_count(management_api, 'pending', 5)
            TestDevice.verify_device_count(management_api, 'accepted', 0)
            TestDevice.verify_device_count(management_api, 'rejected', 0)
    def test_delete_device_ochestrator_failure(self, management_api, devices):
        # try delete an existing device, verify it is failing when orchestrator
        # is failing
        dev, _ = devices[0]
        ourdev = management_api.get_single_device()
        assert ourdev

        with orchestrator.run_fake_for_device_id(ourdev.id, 500) as server:
            rsp = management_api.delete_device(
                ourdev.id, {
                    'X-MEN-RequestID': 'delete_device',
                    'Authorization': 'Bearer foobar',
                })
        print('decommission request finished with status:', rsp.status_code)
        assert rsp.status_code == 500
Beispiel #17
0
def make_devices(device_api, devcount=1, tenant_token=""):
    url = device_api.auth_requests_url

    out_devices = []

    with orchestrator.run_fake_for_device_id(1) as server:
        for _ in range(devcount):
            dev = Device()
            da = DevAuthorizer(tenant_token=tenant_token)
            # poke devauth so that device appears
            rsp = device_auth_req(url, da, dev)
            assert rsp.status_code == 401
            out_devices.append((dev, da))

    return out_devices
Beispiel #18
0
    def _test_delete_authset_OK(self, management_api, devices, **kwargs):
        d, da = devices[0]

        dev = management_api.find_device_by_identity(d.identity, **kwargs)
        assert dev

        print("found matching device with ID:", dev.id)
        aid = dev.auth_sets[0].id

        with orchestrator.run_fake_for_device_id(dev.id) as server:
            rsp = management_api.delete_authset(dev.id, aid, **kwargs)
            assert rsp.status_code == 204

        found = management_api.get_device(id=dev.id, **kwargs)
        assert found

        assert len(found.auth_sets) == 0
Beispiel #19
0
    def test_token_claims(self, accepted_device, management_api, device_api):
        devid, d, da = accepted_device

        try:
            with orchestrator.run_fake_for_device_id(devid) as server:
                token = request_token(d, da, device_api.auth_requests_url)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        assert len(token) > 0
        print("device token:", d.token)

        thdr, tclaims, tsign = explode_jwt(d.token)
        assert "typ" in thdr and thdr["typ"] == "JWT"

        assert "jti" in tclaims
        assert "exp" in tclaims
        assert "sub" in tclaims and tclaims["sub"] == devid
        assert "iss" in tclaims and tclaims["iss"] == "Mender"
        assert "mender.device" in tclaims and tclaims["mender.device"] == True
Beispiel #20
0
    def test_token_claims(self, accepted_device, management_api, device_api):
        devid, d, da = accepted_device

        try:
            with orchestrator.run_fake_for_device_id(devid) as server:
                token = request_token(d, da, device_api.auth_requests_url)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        assert len(token) > 0
        print("device token:", d.token)

        thdr, tclaims, tsign = explode_jwt(d.token)
        assert 'typ' in thdr and thdr['typ'] == 'JWT'

        assert 'jti' in tclaims
        assert 'exp' in tclaims
        assert 'sub' in tclaims and tclaims['sub'] == devid
        assert 'iss' in tclaims and tclaims['iss'] == 'Mender'
        assert 'mender.device' in tclaims and tclaims['mender.device'] == True
    def test_device_accept_orchestrator_failure(self, devices, device_api,
                                                management_api):
        d, da = devices[0]
        url = device_api.auth_requests_url

        dev = management_api.get_single_device()

        assert dev
        devid = dev.id

        print("found device with ID:", dev.id)
        aid = dev.auth_sets[0].id

        status = None
        try:
            with orchestrator.run_fake_for_device_id(devid, 500) as server:
                management_api.accept_device(devid, aid)
        except bravado.exception.HTTPError as e:
            status = e.response.status_code
        assert status == 500
Beispiel #22
0
    def test_device_new(self, device_api, management_api, clean_migrated_db):
        d = Device()
        da = DevAuthorizer()

        try:
            with orchestrator.run_fake_for_device_id(1) as server:
                rsp = device_auth_req(device_api.auth_requests_url, da, d)
                assert rsp.status_code == 401
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        devs = management_api.list_devices()

        assert len(devs) == 1
        dev = devs[0]

        assert len(dev.auth_sets) == 1
        aset = dev.auth_sets[0]

        assert compare_keys(aset.pubkey, d.public_key)
Beispiel #23
0
    def test_delete_device(self, management_api, devices):
        # try delete an existing device, verify decommissioning workflow was started
        # setup single device and poke devauth
        dev, _ = devices[0]
        ourdev = management_api.find_device_by_identity(dev.identity)
        assert ourdev

        try:
            with orchestrator.run_fake_for_device_id(ourdev.id) as server:
                rsp = management_api.delete_device(
                    ourdev.id, {
                        'X-MEN-RequestID': 'delete_device',
                        'Authorization': 'Bearer foobar',
                    })
            print('decommission request finished with status:',
                  rsp.status_code)
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 204

        found = management_api.find_device_by_identity(dev.identity)
        assert not found
Beispiel #24
0
    def _do_test_ok_preauth(self, management_api, device_api, tenant_token=""):
        d = Device(IDDATA)
        d.public_key = PUBKEY
        d.private_key = PRIVKEY

        da = DevAuthorizer(tenant_token=tenant_token)

        # get the authset id - need it for the url
        auth = management_api.make_auth(tenant_token)

        dbg = management_api.list_devices()
        print(dbg)

        dev = management_api.find_device_by_identity(d.identity, **auth)
        assert dev

        with devadm_fake_status_update(AID), \
             orchestrator.run_fake_for_device_id(DEVID):
            rsp = device_auth_req(device_api.auth_requests_url, da, d)
            assert rsp.status_code == 200

        dev = management_api.get_device(id=dev.id, **auth)
        assert dev.auth_sets[0].status == 'accepted'
def accepted_tenants_devices(device_api, management_api, clean_migrated_db,
                             cli, request):
    """Fixture that sets up an accepted devices for tenants. The fixture can
    be parametrized with a tenants, number of devices and number of authentication sets.
    Yields a dict:
    [tenant ID: [device object, ...], ]"""

    requested = request.param

    tenants_devices = dict()
    url = device_api.auth_requests_url

    for (tenant, dev_count, auth_count) in requested:

        tenant_devices = []
        cli.migrate(tenant=tenant)
        tenant_token = make_fake_tenant_token(tenant)
        for _ in range(int(dev_count)):
            d = Device()
            for i in range(int(auth_count)):
                d.rotate_key()
                da = DevAuthorizer(tenant_token=tenant_token)

                # poke devauth so that device appears
                handlers = [
                    (
                        "POST",
                        "/api/internal/v1/tenantadm/tenants/verify",
                        lambda _: (
                            200,
                            {},
                            {
                                "id": "507f191e810c19729de860ea",
                                "name": "Acme",
                            },
                        ),
                    ),
                ]

                try:
                    with orchestrator.run_fake_for_device_id(1) as server:
                        with mockserver.run_fake(get_fake_tenantadm_addr(),
                                                 handlers=handlers) as fake:
                            rsp = device_auth_req(url, da, d)
                            assert rsp.status_code == 401
                except bravado.exception.HTTPError as e:
                    assert e.response.status_code == 204

                # try to find our devices in all devices listing
                dev = management_api.find_device_by_identity(
                    d.identity, Authorization="Bearer " + tenant_token)

                devid = dev.id
                for a in dev.auth_sets:
                    if compare_keys(a.pubkey, d.public_key):
                        aid = a.id
                        break

                try:
                    with orchestrator.run_fake_for_device_id(devid) as server:
                        management_api.accept_device(devid,
                                                     aid,
                                                     Authorization="Bearer " +
                                                     tenant_token)
                        token = request_token(d, da,
                                              device_api.auth_requests_url)
                        assert len(token) > 0
                except bravado.exception.HTTPError as e:
                    assert e.response.status_code == 204

            assert dev
            tenant_devices.append(d)

        tenants_devices[tenant] = tenant_devices
    yield tenants_devices