示例#1
0
    def test_get_devices(self):
        url = self.devapi.make_api_url("auth_requests")

        mc = SimpleManagementClient()

        devs = mc.list_devices()
        self.log.debug('devices; %s', devs)

        with deviceadm.run_fake_for_device(deviceadm.ANY_DEVICE) as server:
            devcount = 50
            for _ in range(devcount):
                dev = Device()
                da = DevAuthorizer()
                # poke devauth so that device appears
                rsp = device_auth_req(url, da, dev)
                assert rsp.status_code == 401

        # try to get a maximum number of devices
        devs = mc.list_devices(page=1, per_page=500)
        self.log.debug('got %d devices', len(devs))
        assert 500 >= len(devs) >= devcount

        # we have added at least `devcount` devices, so listing some lower
        # number of device should return exactly that number of entries
        plimit = devcount // 2
        devs = mc.list_devices(page=1, per_page=plimit)
        self.log.debug('got %d devices', len(devs))
        assert len(devs) == plimit
示例#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

    # poke devauth so that device appears
    with deviceadm.run_fake_for_device(d) as server:
        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

    try:
        with inventory.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)
示例#3
0
    def test_device_new(self, device_api, clean_migrated_db):
        d = Device()
        da = DevAuthorizer()

        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(device_api.auth_requests_url, da, d)
            assert rsp.status_code == 401
示例#4
0
    def test_id_data_formatting(self, device_api, management_api,
                                clean_migrated_db):
        reference_id_data = [
            '{"attribute_foo":"foo"}',
            '{"attribute_bar":2, "attribute_foo":1}',
            '{"attribute_foo":"foo","mac": "00:00:00:01","sn": "0001"}',
        ]

        reformatted_id_data = [
            '{"attribute_foo": "foo"}',
            ' { "attribute_foo": "foo" }',
            '{"attribute_foo":1, "attribute_bar":2}',
            '{ "attribute_foo":1, "attribute_bar":2}',
            '{"sn": "0001","mac": "00:00:00:01","attribute_foo":"foo"}',
        ]

        # submit first auth req with 'reference data', second with 'reformatted' data
        # must result in only 3 devices
        with deviceadm.run_fake_for_device(deviceadm.ANY_DEVICE) as server:
            for reference in reference_id_data:
                dev = Device(reference)
                da = DevAuthorizer()
                rsp = device_auth_req(device_api.auth_requests_url, da, dev)
                assert rsp.status_code == 401

        devs = management_api.list_devices()
        assert len(devs) == 3

        with deviceadm.run_fake_for_device(deviceadm.ANY_DEVICE) as server:
            for reformatted in reformatted_id_data:
                dev = Device(reformatted)
                da = DevAuthorizer()
                rsp = device_auth_req(device_api.auth_requests_url, da, dev)
                assert rsp.status_code == 401

        devs = management_api.list_devices()
        assert len(devs) == 3

        # verify we have the correct id data
        json_reference_id_data = [json.loads(i) for i in reference_id_data]
        for d in devs:
            api_id_data = json.loads(d.id_data)
            found_in_reference = [
                x for x in json_reference_id_data if x == api_id_data
            ]
            assert len(found_in_reference) == 1
示例#5
0
    def test_device_accept_reject(self):
        d = Device()
        da = DevAuthorizer()
        url = self.devapi.make_api_url("auth_requests")

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

        # determine device ID by listing all devices and finding one with
        # matching public key
        mc = SimpleManagementClient()
        dev = mc.find_device_by_identity(d.identity)

        assert dev
        devid = dev.id

        self.log.debug('found matching device with ID: %s', dev.id)
        aid = dev.auth_sets[0].id

        try:
            with inventory.run_fake_for_device_id(devid) as server:
                self.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
        rsp = device_auth_req(url, da, d)
        assert rsp.status_code == 200

        da.parse_rsp_payload(d, rsp.text)

        assert len(d.token) > 0
        self.log.info("device token: %s", d.token)

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

        # device is rejected, should get unauthorized
        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(url, da, d)
            assert rsp.status_code == 401
示例#6
0
def request_token(device, dev_auth, url):
    # device is accepted, we should get a token now
    with deviceadm.run_fake_for_device(device) as server:
        rsp = device_auth_req(url, dev_auth, device)
        assert rsp.status_code == 200

    dev_auth.parse_rsp_payload(device, rsp.text)
    return device.token
示例#7
0
    def test_device_new(self):
        d = Device()
        da = DevAuthorizer()
        url = self.devapi.make_api_url("auth_requests")
        self.log.error("device URL: %s", url)

        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(self.devapi.make_api_url("auth_requests"),
                                  da, d)
            assert rsp.status_code == 401
示例#8
0
    def test_auth_req_bad_key(self, device_api, management_api,
                              clean_migrated_db):
        d = Device()
        da = DevAuthorizer()

        # corrupt the autogenerated public key
        d.public_key = 'invalid'

        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(device_api.auth_requests_url, da, d)
            assert rsp.status_code == 400
            assert rsp.json(
            )['error'] == 'invalid auth request: cannot decode public key'
示例#9
0
    def test_delete_device(self):
        # try delete a nonexistent device
        try:
            self.delete_device('some-devid-foo')
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 404

        # try delete an existing device, verify decommissioning workflow was started
        # setup single device and poke devauth
        dev = Device()
        da = DevAuthorizer()
        # poke devauth so that device appears
        with deviceadm.run_fake_for_device(dev) as server:
            rsp = device_auth_req(self.devapi.make_api_url("auth_requests"),
                                  da, dev)
            assert rsp.status_code == 401

        mc = SimpleManagementClient()
        ourdev = mc.find_device_by_identity(dev.identity)
        assert ourdev

        # handler for orchestrator's job endpoint
        def decommission_device_handler(request):
            dreq = json.loads(request.body.decode())
            self.log.info('decommision request %s', dreq)
            # verify that devauth tries to decommision correct device
            assert dreq.get('device_id', None) == ourdev.id
            # test is enforcing particular request ID
            assert dreq.get('request_id', None) == 'delete_device'
            # test is enforcing particular request ID
            assert dreq.get('authorization', None) == 'Bearer foobar'
            return (200, {}, '')

        handlers = [
            ('POST', '/api/workflow/decommission_device',
             decommission_device_handler),
        ]
        with mockserver.run_fake(get_fake_orchestrator_addr(),
                                 handlers=handlers) as server:

            rsp = self.delete_device(
                ourdev.id, {
                    'X-MEN-RequestID': 'delete_device',
                    'Authorization': 'Bearer foobar',
                })
            self.log.info('decommission request finished with status: %s',
                          rsp.status_code)
            assert rsp.status_code == 204

        found = mc.find_device_by_identity(dev.identity)
        assert not found
示例#10
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)
示例#11
0
def request_token(device, dev_auth, url):
    handlers = [
        ('POST', '/api/internal/v1/tenantadm/tenants/verify', lambda _:
         (200, {}, {
             'id': '507f191e810c19729de860ea',
             'name': 'Acme',
         })),
    ]
    with mockserver.run_fake(get_fake_tenantadm_addr(),
                             handlers=handlers) as fake:
        with deviceadm.run_fake_for_device(device) as server:
            rsp = device_auth_req(url, dev_auth, device)
            assert rsp.status_code == 200
    dev_auth.parse_rsp_payload(device, rsp.text)
    return device.token
示例#12
0
def make_devices(device_api, devcount=1, tenant_token=""):
    print('device count to generate', devcount)

    url = device_api.auth_requests_url

    out_devices = []
    with deviceadm.run_fake_for_device(deviceadm.ANY_DEVICE) 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
示例#13
0
    def test_device_new(self, device_api, management_api, clean_migrated_db):
        d = Device()
        da = DevAuthorizer()

        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(device_api.auth_requests_url, da, d)
            assert rsp.status_code == 401

        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)
示例#14
0
    def test_auth_req_fake_tenantadm_valid_tenant_token(self):
        d = Device()
        da = DevAuthorizer(tenant_token=make_fake_tenant_token(
            tenant='foobar'))
        url = self.devapi.make_api_url("/auth_requests")

        handlers = [
            ('POST', '/api/internal/v1/tenantadm/tenants/verify', lambda _:
             (200, {}, {
                 'id': '507f191e810c19729de860ea',
                 'name': 'Acme',
             })),
        ]
        with mockserver.run_fake(get_fake_tenantadm_addr(),
                                 handlers=handlers) as fake:
            with deviceadm.run_fake_for_device(d) as fakedevadm:
                rsp = device_auth_req(url, da, d)
                assert rsp.status_code == 401

        # device should be appear in devices listing
        self.verify_tenant_dev_present(d.identity, tenant='foobar')
示例#15
0
    def test_get_single_device(self):
        mc = SimpleManagementClient()

        try:
            mc.get_device(id='some-devid-foo')
        except bravado.exception.HTTPError as e:
            assert e.response.status_code == 404

        # setup single device and poke devauth
        dev = Device()
        da = DevAuthorizer()
        # poke devauth so that device appears
        with deviceadm.run_fake_for_device(dev) as server:
            rsp = device_auth_req(self.devapi.make_api_url("auth_requests"),
                                  da, dev)
            assert rsp.status_code == 401

        # try to find our devices in all devices listing
        mc = SimpleManagementClient()
        ourdev = mc.find_device_by_identity(dev.identity)

        authdev = mc.get_device(id=ourdev.id)
        assert authdev == ourdev
示例#16
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 inventory.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
        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
        with deviceadm.run_fake_for_device(d) as server:
            rsp = device_auth_req(url, da, d)
            assert rsp.status_code == 401
示例#17
0
    def test_token(self):
        d = Device()
        da = DevAuthorizer()
        url = self.devapi.make_api_url("/auth_requests")

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

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

        self.log.debug('found matching device with ID: %s', dev.id)
        devid = dev.id
        # extract authentication data set ID
        aid = dev.auth_sets[0].id

        try:
            with inventory.run_fake_for_device_id(devid) as server:
                self.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
        with deviceadm.run_fake_for_device(d) 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
        self.log.info("device token: %s", 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
        # TODO: signature verification?

        # verify token; the token is to be placed in the Authorization header
        # and it looks like bravado cannot handle a POST request with no data
        # in body, hence we fall back to sending request directly
        verify_url = self.intclient.make_api_url("/tokens/verify")
        self.log.info("verify URL: %s", verify_url)
        auth_hdr = 'Bearer {}'.format(d.token)

        # no auth header should raise an error
        rsp = requests.post(verify_url, data='')
        assert rsp.status_code == 401

        # successful verification
        rsp = requests.post(verify_url,
                            data='',
                            headers={'Authorization': auth_hdr})
        assert rsp.status_code == 200

        # use a bogus token that is not a valid JWT
        rsp = requests.post(verify_url,
                            data='',
                            headers={'Authorization': 'bogus'})
        assert rsp.status_code == 401

        # or a correct token with data appended at the end
        rsp = requests.post(verify_url,
                            data='',
                            headers={'Authorization': auth_hdr + "==foo"})
        assert rsp.status_code == 401

        # bravado cannot handle DELETE requests either
        #   self.client.tokens.delete_tokens_id(id=tclaims['jti'])
        # use requests instead
        rsp = requests.delete(
            self.make_api_url('/tokens/{}'.format(tclaims['jti'])))
        assert rsp.status_code == 204

        # unsuccessful verification
        rsp = requests.post(verify_url,
                            data='',
                            headers={'Authorization': auth_hdr})
        assert rsp.status_code == 401
示例#18
0
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',
                     })),
                ]
                with mockserver.run_fake(get_fake_tenantadm_addr(),
                                         handlers=handlers) as fake:
                    with deviceadm.run_fake_for_device(d) as fakedevadm:
                        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, 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)
                except bravado.exception.HTTPError as e:
                    assert e.response.status_code == 204

                token = request_token(d, da, device_api.auth_requests_url)
                assert len(token) > 0

            assert dev
            tenant_devices.append(d)

        tenants_devices[tenant] = tenant_devices
    yield tenants_devices