示例#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)

        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 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
示例#3
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
示例#4
0
    def verify_tenant_dev_present(self,
                                  identity,
                                  present=True,
                                  tenant='foobar'):
        """Assert that device with `identity` is present (or not)"""

        # request was rejected, device should not be listed
        mc = SimpleManagementClient()

        if tenant:
            token = make_fake_tenant_token(tenant=tenant)
            dev = mc.find_device_by_identity(identity,
                                             Authorization='Bearer ' + token)
        else:
            # use default auth
            dev = mc.find_device_by_identity(identity)

        if present:
            assert dev
        else:
            assert not dev
示例#5
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
        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

        # delete our device
        # use a predetermined request id to correlate with executed workflows
        self.delete_device(ourdev.id, {'X-MEN-RequestID': 'delete_device'})
        found = mc.find_device_by_identity(dev.identity)
        assert not found

        # verify workflow was executed
        cc = ConductorClient()
        r = cc.get_workflows('decommission_device')
        assert r.status_code == 200

        res = r.json()
        assert res['totalHits'] == 1

        wf = [
            x for x in res['results'] if x['input'] == '{device_id=' +
            ourdev.id + ', request_id=delete_device}'
        ]
        assert len(wf) == 1
示例#6
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
        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
示例#7
0
def management_api():
    yield SimpleManagementClient()
示例#8
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
示例#9
0
def management_api(request):
    yield SimpleManagementClient(
        request.config.getoption("--host"),
        request.config.getoption("--management-spec"),
    )