def make_accepted_device(utoken, devauthd, tenant_token=''): devauthm = ApiClient(deviceauth_v2.URL_MGMT) dev = make_pending_device(utoken, tenant_token=tenant_token) aset_id = dev.authsets[0].id change_authset_status(devauthm, dev.id, aset_id, 'accepted', utoken) aset = dev.authsets[0] aset.status = 'accepted' # obtain auth token body, sighdr = deviceauth_v1.auth_req(aset.id_data, aset.pubkey, aset.privkey, tenant_token) r = devauthd.call('POST', deviceauth_v1.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 200 dev.token = r.text dev.status = 'accepted' return dev
def test_accepted_dev_cant_authenticate(self, tenants_users_devices): dacd = ApiClient(deviceauth.URL_DEVICES) devauthm = ApiClient(deviceauth_v2.URL_MGMT) uc = ApiClient(useradm.URL_MGMT) tc = ApiClient(tenantadm.URL_INTERNAL) # accept a dev device = tenants_users_devices[0].devices[0] user = tenants_users_devices[0].users[0] r = uc.call('POST', useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text aset = device.authsets[0] change_authset_status(devauthm, aset.did, aset.id, 'accepted', utoken) # suspend r = tc.call('PUT', tenantadm.URL_INTERNAL_SUSPEND, tenantadm.req_status('suspended'), path_params={'tid': tenants_users_devices[0].id}) assert r.status_code == 200 time.sleep(10) # try requesting auth body, sighdr = deviceauth.auth_req( aset.id_data, aset.pubkey, aset.privkey, tenants_users_devices[0].tenant_token) r = dacd.call('POST', deviceauth.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 401 assert r.json()['error'] == 'Account suspended'
def test_device_audit_log_events(self, event_type: str, tenant_users: Tenant): """Test if device events are loggged with correct fields.""" user = tenant_users.users[0] device = make_pending_device( self.devauthd, self.devauthm, user.token, tenant_token=tenant_users.tenant_token, ) if event_type == "decommission": response = self.devauthm.with_auth(user.token).call( "DELETE", deviceauth.URL_DEVICE, path_params={"id": device.id}) assert response.status_code == 204 elif event_type == "reject": for auth_set in device.authsets: change_authset_status(self.devauthm, device.id, auth_set.id, "rejected", user.token) for _ in redo.retrier(attempts=3, sleeptime=1): res = self.alogs.with_auth(user.token).call( "GET", auditlogs.URL_LOGS + "?object_type=device&object_id=" + device.id) assert res.status_code == 200 if len(res.json()) == 1: break else: assert False, f"max GET /logs retries hit, logs returned: {res.json()}" expected = event_device(user, device, event_type=event_type) check_log(res.json()[0], expected)
def test_authenticated_dev_is_rejected(self, tenants_users_devices): dacd = ApiClient(deviceauth.URL_DEVICES) devauthm = ApiClient(deviceauth_v2.URL_MGMT) uc = ApiClient(useradm.URL_MGMT) tc = ApiClient(tenantadm.URL_INTERNAL) dc = ApiClient(deployments.URL_DEVICES) # accept a dev user = tenants_users_devices[0].users[0] r = uc.call('POST', useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text aset = tenants_users_devices[0].devices[0].authsets[0] change_authset_status(devauthm, aset.did, aset.id, 'accepted', utoken) # request auth body, sighdr = deviceauth.auth_req(aset.id_data, aset.pubkey, aset.privkey, tenants_users_devices[0].tenant_token) r = dacd.call('POST', deviceauth.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 200 dtoken = r.text # check device can access APIs r = dc.with_auth(dtoken).call('GET', deployments.URL_NEXT, qs_params={'device_type': 'foo', 'artifact_name': 'bar'}) assert r.status_code == 204 # suspend r = tc.call('PUT', tenantadm.URL_INTERNAL_SUSPEND, tenantadm.req_status('suspended'), path_params={'tid': tenants_users_devices[0].id}) assert r.status_code == 200 time.sleep(10) # check device is rejected r = dc.with_auth(dtoken).call('GET', deployments.URL_NEXT, qs_params={'device_type': 'foo', 'artifact_name': 'bar'}) assert r.status_code == 401
def make_rejected_device(utoken, num_auth_sets=1, tenant_token=""): devauthm = ApiClient(deviceauth_v2.URL_MGMT) dev = make_pending_device(utoken, num_auth_sets, tenant_token=tenant_token) for i in range(num_auth_sets): aset_id = dev.authsets[i].id change_authset_status(devauthm, dev.id, aset_id, "rejected", utoken) dev.authsets[i].status = "rejected" dev.status = "rejected" return dev
def test_accepted_dev_cant_authenticate(self, tenants_users_devices): dacd = ApiClient(deviceauth.URL_DEVICES) devauthm = ApiClient(deviceauth.URL_MGMT) uc = ApiClient(useradm.URL_MGMT) tc = ApiClient(tenantadm.URL_INTERNAL, host=tenantadm.HOST, schema="http://") # accept a dev device = tenants_users_devices[0].devices[0] user = tenants_users_devices[0].users[0] r = uc.call("POST", useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text aset = device.authsets[0] change_authset_status(devauthm, aset.did, aset.id, "accepted", utoken) # suspend r = tc.call( "PUT", tenantadm.URL_INTERNAL_SUSPEND, tenantadm.req_status("suspended"), path_params={"tid": tenants_users_devices[0].id}, ) assert r.status_code == 200 time.sleep(10) # try requesting auth body, sighdr = deviceauth.auth_req( aset.id_data, aset.pubkey, aset.privkey, tenants_users_devices[0].tenant_token, ) r = dacd.call("POST", deviceauth.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 401 assert r.json()["error"] == "Account suspended"
def do_test_ok(self, user, device, tenant_token=None): devauthd = ApiClient(deviceauth.URL_DEVICES) devauthm = ApiClient(deviceauth_v2.URL_MGMT) useradmm = ApiClient(useradm.URL_MGMT) deploymentsd = ApiClient(deployments.URL_DEVICES) inventoryd = ApiClient(inventory.URL_DEV) inventorym = ApiClient(inventory.URL_MGMT) r = useradmm.call("POST", useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text aset = device.authsets[0] change_authset_status(devauthm, aset.did, aset.id, "accepted", utoken) # request auth body, sighdr = deviceauth.auth_req(aset.id_data, aset.pubkey, aset.privkey, tenant_token) r = devauthd.call("POST", deviceauth.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 200 dtoken = r.text # wait for the device provisioning workflow to do its job timeout = time.time() + 60 while time.time() < timeout: r = inventorym.with_auth(utoken).call("GET", inventory.URL_DEVICE, path_params={"id": aset.did}) if r.status_code == 200: break else: logger.debug( "waiting for the device to be added to inventory...") time.sleep(1) else: assert False, "device not added to the inventory" # check if the device can access API by patching device inventory payload = [{"name": "mac", "value": "foo"}] r = inventoryd.with_auth(dtoken).call("PATCH", inventory.URL_DEVICE_ATTRIBUTES, payload) assert r.status_code == 200 # decommission r = devauthm.with_auth(utoken).call( "DELETE", deviceauth_v2.URL_DEVICE.format(id=aset.did)) # check device is rejected r = deploymentsd.with_auth(dtoken).call( "GET", deployments.URL_NEXT, qs_params={ "device_type": "foo", "artifact_name": "bar" }, ) assert r.status_code == 401 # check device gone from inventory # this may take some time because it's done as an async job (workflow) timeout = time.time() + (60 * 3) while time.time() < timeout: r = inventorym.with_auth(utoken).call("GET", inventory.URL_DEVICE, path_params={"id": aset.did}) if r.status_code == 404: break else: logger.debug( "waiting for the device to be removed from inventory...") time.sleep(1) else: assert False, "device not removed from the inventory" # check device gone from deviceauth timeout = time.time() + 60 while time.time() < timeout: r = devauthm.with_auth(utoken).call( "GET", deviceauth_v2.URL_DEVICE.format(id=aset.did)) if r.status_code == 404: break else: logger.debug( "waiting for the device to be removed from deviceauth...") time.sleep(1) else: assert False, "device not removed from the deviceauth"
def do_test_put_status_reject(self, devs_authsets, user, tenant_token=""): devauthm = ApiClient(deviceauth_v2.URL_MGMT) devauthd = ApiClient(deviceauth_v1.URL_DEVICES) useradmm = ApiClient(useradm.URL_MGMT) deploymentsd = ApiClient(deployments.URL_DEVICES) # log in user r = useradmm.call("POST", useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text devs = [] for status in ["pending", "accepted", "preauthorized"]: found = filter_and_page_devs(devs_authsets, status=status) devs.extend(found) for dev in devs: aset = None dtoken = None # for accepted or preauthd devs, reject the accepted/preauthd set # otherwise just select something if dev.status in ["accepted", "preauthorized"]: aset = [a for a in dev.authsets if a.status == dev.status] assert len(aset) == 1 aset = aset[0] else: aset = dev.authsets[0] # for accepted devs, also have an active device and check it loses api access if dev.status == "accepted": body, sighdr = deviceauth_v1.auth_req( aset.id_data, aset.pubkey, aset.privkey, tenant_token ) r = devauthd.call( "POST", deviceauth_v1.URL_AUTH_REQS, body, headers=sighdr ) assert r.status_code == 200 dtoken = r.text # reject the authset change_authset_status(devauthm, dev.id, aset.id, "rejected", utoken) # the given authset always changes to 'rejected' aset.status = "rejected" # if all other asets are also rejected, the device becomes too # otherwise it's 'pending' rej_asets = [ a for a in dev.authsets if a.id != aset.id and a.status == "rejected" ] if len(rej_asets) == len(dev.authsets) - 1: dev.status = "rejected" else: dev.status = "pending" # check if the api device is consistent self.verify_dev_after_status_update(dev, utoken) # if we rejected an accepted, active device, check that it lost access if dtoken is not None: r = deploymentsd.with_auth(dtoken).call( "GET", deployments.URL_NEXT, qs_params={"device_type": "foo", "artifact_name": "bar"}, ) assert r.status_code == 401
def do_test_put_status_accept(self, devs_authsets, user, tenant_token=""): devauthm = ApiClient(deviceauth_v2.URL_MGMT) devauthd = ApiClient(deviceauth_v1.URL_DEVICES) useradmm = ApiClient(useradm.URL_MGMT) deploymentsd = ApiClient(deployments.URL_DEVICES) # log in user r = useradmm.call("POST", useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text # select interesting devices - pending, rejected, or accepted/preauthd with extra authsets devs = [] for status in ["pending", "rejected", "accepted", "preauthorized"]: found = filter_and_page_devs(devs_authsets, status=status) if status == "accepted" or status == "preauthorized": found = [d for d in found if len(d.authsets) > 1] devs.extend(found) # test acceptance for various kinds of devs for dev in devs: # for accepted devs - first actually get a device token dtoken = None if dev.status == "accepted": accepted = [a for a in dev.authsets if a.status == "accepted"][0] body, sighdr = deviceauth_v1.auth_req( accepted.id_data, accepted.pubkey, accepted.privkey, tenant_token ) r = devauthd.call( "POST", deviceauth_v1.URL_AUTH_REQS, body, headers=sighdr ) assert r.status_code == 200 dtoken = r.text # find some pending or rejected authset aset = [ a for a in dev.authsets if a.status == "pending" or a.status == "rejected" ][0] # accept the authset change_authset_status(devauthm, dev.id, aset.id, "accepted", utoken) # in case of originally preauthd/accepted devs: the original authset must be rejected now if dev.status in ["accepted", "preauthorized"]: aset_to_reject = [a for a in dev.authsets if a.status == dev.status] assert len(aset_to_reject) == 1 aset_to_reject[0].status = "rejected" # in all cases, device is now 'accepted', along with the just accepted authset dev.status = "accepted" aset.status = "accepted" # verify device is correct in the api self.verify_dev_after_status_update(dev, utoken) # if the device used to be accepted - check it lost access if dtoken is not None: r = deploymentsd.with_auth(dtoken).call( "GET", deployments.URL_NEXT, qs_params={"device_type": "foo", "artifact_name": "bar"}, ) assert r.status_code == 401 # device should also be provisioned in inventory time.sleep(1) self.verify_dev_provisioned(dev, utoken)
def test_authenticated_dev_is_rejected(self, tenants_users_devices): dacd = ApiClient(deviceauth.URL_DEVICES) devauthm = ApiClient(deviceauth.URL_MGMT) uc = ApiClient(useradm.URL_MGMT) tc = ApiClient(tenantadm.URL_INTERNAL, host=tenantadm.HOST, schema="http://") dc = ApiClient(deployments.URL_DEVICES) # accept a dev user = tenants_users_devices[0].users[0] r = uc.call("POST", useradm.URL_LOGIN, auth=(user.name, user.pwd)) assert r.status_code == 200 utoken = r.text aset = tenants_users_devices[0].devices[0].authsets[0] change_authset_status(devauthm, aset.did, aset.id, "accepted", utoken) # request auth body, sighdr = deviceauth.auth_req( aset.id_data, aset.pubkey, aset.privkey, tenants_users_devices[0].tenant_token, ) r = dacd.call("POST", deviceauth.URL_AUTH_REQS, body, headers=sighdr) assert r.status_code == 200 dtoken = r.text # check device can access APIs r = dc.with_auth(dtoken).call( "GET", deployments.URL_NEXT, qs_params={ "device_type": "foo", "artifact_name": "bar" }, ) assert r.status_code == 204 # suspend r = tc.call( "PUT", tenantadm.URL_INTERNAL_SUSPEND, tenantadm.req_status("suspended"), path_params={"tid": tenants_users_devices[0].id}, ) assert r.status_code == 200 time.sleep(10) # check device is rejected r = dc.with_auth(dtoken).call( "GET", deployments.URL_NEXT, qs_params={ "device_type": "foo", "artifact_name": "bar" }, ) assert r.status_code == 401