diff --git a/.github/workflows/flake8_and_black.yml b/.github/workflows/flake8_and_black.yml index 88c468e..4af2cba 100644 --- a/.github/workflows/flake8_and_black.yml +++ b/.github/workflows/flake8_and_black.yml @@ -12,14 +12,14 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - - name: Set up Python 3.6 + - name: Set up Python 3.11 uses: actions/setup-python@v2 with: - python-version: 3.6.15 + python-version: 3.11.10 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml index 2949bdf..33f87bc 100644 --- a/.github/workflows/unittest.yml +++ b/.github/workflows/unittest.yml @@ -12,14 +12,14 @@ on: jobs: build: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v2 - - name: Set up Python 3.6 + - name: Set up Python 3.11 uses: actions/setup-python@v2 with: - python-version: 3.6.15 + python-version: 3.11.10 - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 751c3ac..fd04dcb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,12 +1,12 @@ fail_fast: true repos: - repo: https://github.com/timothycrosley/isort - rev: 5.7.0 + rev: 5.12.0 hooks: - id: isort additional_dependencies: [toml] - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 22.3.0 hooks: - id: black args: [--config=./pyproject.toml] diff --git a/iam/__version__.py b/iam/__version__.py index 918e7a1..c285769 100644 --- a/iam/__version__.py +++ b/iam/__version__.py @@ -1,3 +1,2 @@ # -*- coding: utf-8 -*- - -__version__ = "1.3.6" +__version__ = "2.0.0" diff --git a/iam/api/client.py b/iam/api/client.py index efd511b..4c4c2d8 100644 --- a/iam/api/client.py +++ b/iam/api/client.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -21,7 +21,6 @@ from cachetools import TTLCache, cached from requests.models import PreparedRequest -from iam.exceptions import AuthAPIError from .http import http_delete, http_get, http_post, http_put logger = logging.getLogger("iam") @@ -34,29 +33,17 @@ class Client(object): input: json """ - def __init__(self, app_code, app_secret, bk_iam_host=None, bk_paas_host=None, bk_apigateway_url=None): + def __init__(self, app_code, app_secret, bk_apigateway_url, bk_tenant_id=""): """ - 如果有 APIGateway 且权限中心网关接入, 则可以统一API请求全部走APIGateway - - 没有APIGateway的用法: Client(app_code, app_secret, bk_iam_host, bk_paas_host) - - 有APIGateway的用法: Client(app_code, app_secret, bk_apigateway_url) - - NOTE: 未来将会下线`没有 APIGateway的用法` + :param app_code: 蓝鲸应用唯一标识 + :param app_secret: 蓝鲸应用密钥 + :param bk_apigateway_url: bk-iam 网关地址,如 https://bkapi.example.com/api/bk-iam/prod/ + :param bk_tenant_id: 多租户模式下的租户 id,必填;对于非多租户用户无需关注 """ self._app_code = app_code self._app_secret = app_secret - - # enabled apigateway - self._apigateway_on = False - if bk_apigateway_url: - self._apigateway_on = True - # replace the host - self._host = bk_apigateway_url.rstrip("/") - else: - if not (bk_iam_host and bk_paas_host): - raise AuthAPIError("init client fail, bk_iam_host and bk_paas_host should not be empty") - - self._host = bk_iam_host - self._bk_paas_host = bk_paas_host + self._host = bk_apigateway_url.rstrip("/") + self._bk_tenant_id = bk_tenant_id # will add ?debug=true in url, for debug api/policy, show the details is_api_debug_enabled = ( @@ -102,71 +89,35 @@ def _call_api(self, http_func, host, path, data, headers, timeout=None): def _call_apigateway_api(self, http_func, path, data, timeout=None): """ - 统一后, 所有接口调用走APIGateway + 统一后,所有接口调用走 APIGateway """ headers = { "X-Bkapi-Authorization": json.dumps({"bk_app_code": self._app_code, "bk_app_secret": self._app_secret}), "X-Bk-IAM-Version": BK_IAM_VERSION, } - return self._call_api(http_func, self._host, path, data, headers, timeout=timeout) - - def _call_iam_api(self, http_func, path, data, timeout=None): - """ - 兼容切换到apigateway, 统一后, 这个方法应该去掉 - """ - if self._apigateway_on: - return self._call_apigateway_api(http_func, path, data, timeout) - - # call directly - headers = { - "X-BK-APP-CODE": self._app_code, - "X-BK-APP-SECRET": self._app_secret, - "X-Bk-IAM-Version": BK_IAM_VERSION, - } + if self._bk_tenant_id: + headers["X-Bk-Tenant-Id"] = self._bk_tenant_id return self._call_api(http_func, self._host, path, data, headers, timeout=timeout) - def _call_esb_api(self, http_func, path, data, bk_token, bk_username, timeout=None): - """ - 兼容切换到apigateway, 统一后, 这个方法应该去掉 - """ - if self._apigateway_on: - apigw_path = path.replace("/api/c/compapi/v2/iam/", "/api/v1/open/") - if not apigw_path.startswith("/api/v1/open/"): - raise AuthAPIError("can't find the matched apigateway path, the esb api path is %s" % path) - - return self._call_apigateway_api(http_func, apigw_path, data, timeout) - - # call esb - headers = {} - data.update( - { - "bk_app_code": self._app_code, - "bk_app_secret": self._app_secret, - "bk_token": bk_token, - "bk_username": bk_username, - } - ) - return self._call_api(http_func, self._bk_paas_host, path, data, headers, timeout=timeout) - # ---------- system def add_system(self, data): # data.id required path = "/api/v1/model/systems" - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) # if alreay exists, return true return ok, message def update_system(self, system_id, data): # data.id required path = "/api/v1/model/systems/{system_id}".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_put, path, data) + ok, message, data = self._call_apigateway_api(http_put, path, data) return ok, message # ---------- resource_type def batch_add_resource_types(self, system_id, data): path = "/api/v1/model/systems/{system_id}/resource-types".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) # if alreay exists, return true return ok, message @@ -175,67 +126,67 @@ def update_resource_type(self, system_id, resource_type_id, data): system_id=system_id, resource_type_id=resource_type_id ) - ok, message, data = self._call_iam_api(http_put, path, data) + ok, message, data = self._call_apigateway_api(http_put, path, data) return ok, message def batch_delete_resource_types(self, system_id, data): path = "/api/v1/model/systems/{system_id}/resource-types?check_existence=false".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_delete, path, data) + ok, message, data = self._call_apigateway_api(http_delete, path, data) return ok, message # ---------- action def batch_add_actions(self, system_id, data): path = "/api/v1/model/systems/{system_id}/actions".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message def update_action(self, system_id, action_id, data): path = "/api/v1/model/systems/{system_id}/actions/{action_id}".format(system_id=system_id, action_id=action_id) - ok, message, data = self._call_iam_api(http_put, path, data) + ok, message, data = self._call_apigateway_api(http_put, path, data) return ok, message def batch_delete_actions(self, system_id, data): path = "/api/v1/model/systems/{system_id}/actions?check_existence=false".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_delete, path, data) + ok, message, data = self._call_apigateway_api(http_delete, path, data) return ok, message # register create association permission action. def add_resource_creator_actions(self, system_id, data): path = "/api/v1/model/systems/{system_id}/configs/resource_creator_actions".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message # update create association permission action. def update_resource_creator_actions(self, system_id, data): path = "/api/v1/model/systems/{system_id}/configs/resource_creator_actions".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_put, path, data) + ok, message, data = self._call_apigateway_api(http_put, path, data) return ok, message - # return resource instance creator to iam, esb needed. - def grant_resource_creator_actions(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/resource_creator_action/" + # return resource instance creator to iam + def grant_resource_creator_actions(self, data): + path = "/api/v1/open/authorization/resource_creator_action/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message return True, "success" - # return resource instance creator action attribute to iam, esb needed. - def grant_resource_creator_action_attributes(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/resource_creator_action_attribute/" + # return resource instance creator action attribute to iam + def grant_resource_creator_action_attributes(self, data): + path = "/api/v1/open/authorization/resource_creator_action_attribute/" - ok, message, data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + ok, message, data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message return True, "success" - # return resource instance creator to iam, esb needed. - def grant_batch_resource_creator_actions(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/batch_resource_creator_action/" + # return resource instance creator to iam + def grant_batch_resource_creator_actions(self, data): + path = "/api/v1/open/authorization/batch_resource_creator_action/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message @@ -246,7 +197,7 @@ def add_action_topology(self, system_id, action_type, data): path = "/api/v1/model/systems/{system_id}/action-topologies/{action_type}".format( system_id=system_id, action_type=action_type ) - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) # if alreay exists, return true return ok, message @@ -254,14 +205,14 @@ def update_action_topology(self, system_id, action_type, data): path = "/api/v1/model/systems/{system_id}/action-topologies/{action_type}".format( system_id=system_id, action_type=action_type ) - ok, message, data = self._call_iam_api(http_put, path, data) + ok, message, data = self._call_apigateway_api(http_put, path, data) # if alreay exists, return true return ok, message # ---------- query def query(self, system_id): path = "/api/v1/model/systems/{system_id}/query".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_get, path, None) + ok, message, data = self._call_apigateway_api(http_get, path, None) return ok, message, data # ---------- ping @@ -292,7 +243,7 @@ def upsert_system(self, system_id, data): system_id_set, _, _ = self.query_all_models(system_id) if system_id not in system_id_set: - return self.add_system(system_id, data) + return self.add_system(data) return self.update_system(system_id, data) def upsert_resource_type(self, system_id, data): @@ -304,8 +255,8 @@ def upsert_resource_type(self, system_id, data): _, resource_id_set, _ = self.query_all_models(system_id) if d_resource_type_id not in resource_id_set: - return self.add_resource_type(system_id, data) - return self.update_resource_type(system_id, data) + return self.batch_add_resource_types(system_id, [data]) + return self.update_resource_type(system_id, d_resource_type_id, data) def upsert_action(self, system_id, data): d_action_id = data.get("id") @@ -315,80 +266,80 @@ def upsert_action(self, system_id, data): _, _, action_id_set = self.query_all_models(system_id) if d_action_id not in action_id_set: - return self.add_action(system_id, data) - return self.update_action(system_id, data) + return self.batch_add_actions(system_id, [data]) + return self.update_action(system_id, d_action_id, data) # --------- policy def policy_query(self, data): path = "/api/v1/policy/query" - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message, data # --------- policy v2 def v2_policy_query(self, system_id, data): path = f"/api/v2/policy/systems/{system_id}/query/" - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message, data def policy_query_by_actions(self, data): path = "/api/v1/policy/query_by_actions" - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message, data def v2_policy_query_by_actions(self, system_id, data): path = f"/api/v2/policy/systems/{system_id}/query_by_actions/" - ok, message, data = self._call_iam_api(http_post, path, data) + ok, message, data = self._call_apigateway_api(http_post, path, data) return ok, message, data def get_token(self, system_id): path = "/api/v1/model/systems/{system_id}/token".format(system_id=system_id) - ok, message, _data = self._call_iam_api(http_get, path, {}) + ok, message, _data = self._call_apigateway_api(http_get, path, {}) if not ok: return False, message, "" return True, "success", _data.get("token", "") # apply - def get_apply_url(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/application/" + def get_apply_url(self, data): + path = "/api/v1/open/application/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message, "" return True, "success", _data.get("url", "") - def instance_authorization(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/instance/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + def instance_authorization(self, data): + path = "/api/v1/open/authorization/instance/" + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message, "" return True, "success", _data.get("token", "") - def batch_instance_authorization(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/batch_instance/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + def batch_instance_authorization(self, data): + path = "/api/v1/open/authorization/batch_instance/" + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message, "" return True, "success", _data - def path_authorization(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/path/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + def path_authorization(self, data): + path = "/api/v1/open/authorization/path/" + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message, "" return True, "success", _data.get("token", "") - def batch_path_authorization(self, bk_token, bk_username, data): - path = "/api/c/compapi/v2/iam/authorization/batch_path/" - ok, message, _data = self._call_esb_api(http_post, path, data, bk_token, bk_username, timeout=5) + def batch_path_authorization(self, data): + path = "/api/v1/open/authorization/batch_path/" + ok, message, _data = self._call_apigateway_api(http_post, path, data, timeout=5) if not ok: return False, message, "" return True, "success", _data def query_policies_with_action_id(self, system_id, data): path = "/api/v1/systems/{system_id}/policies".format(system_id=system_id) - ok, message, data = self._call_iam_api(http_get, path, data) + ok, message, data = self._call_apigateway_api(http_get, path, data) if not ok: return False, message, "" return True, message, data diff --git a/iam/contrib/iam_migration/migrator.py b/iam/contrib/iam_migration/migrator.py index 386235d..d29dc6d 100644 --- a/iam/contrib/iam_migration/migrator.py +++ b/iam/contrib/iam_migration/migrator.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -38,15 +38,9 @@ def __init__(self, migration_json): self._bk_app_secret = settings.SECRET_KEY def migrate(self): - iam_host = "" - USE_APIGATEWAY = getattr(settings, "BK_IAM_USE_APIGATEWAY", False) - if USE_APIGATEWAY: - do_migrate.enable_use_apigateway() - iam_host = getattr(settings, "BK_IAM_APIGATEWAY_URL", "") - if iam_host == "": - raise exceptions.MigrationFailError("settings.BK_IAM_APIGATEWAY_URL should be set") - else: - iam_host = settings.BK_IAM_INNER_HOST + iam_host = getattr(settings, "BK_IAM_APIGATEWAY_URL", "") + if iam_host == "": + raise exceptions.MigrationFailError("settings.BK_IAM_APIGATEWAY_URL should be set") # only trigger migrator at db migrate if "migrate" not in sys.argv: diff --git a/iam/contrib/iam_migration/utils/do_migrate.py b/iam/contrib/iam_migration/utils/do_migrate.py index 05038bc..cf9e94b 100644 --- a/iam/contrib/iam_migration/utils/do_migrate.py +++ b/iam/contrib/iam_migration/utils/do_migrate.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -19,13 +19,11 @@ import requests - # NOTE: the usage doc https://bk.tencent.com/docs/document/6.0/160/8388 __version__ = "1.0.0" -BK_IAM_HOST = os.getenv("BK_IAM_V3_INNER_HOST", "http://bkiam.service.consul:5001") -USE_APIGATEWAY = os.getenv("BK_IAM_USE_APIGATEWAY", "false").lower() == "true" +BK_APIGATEWAY_URL = os.getenv("BK_IAM_APIGATEWAY_URL", "https://bkapi.example.com/api/bk-iam/prod/") APP_CODE = "" APP_SECRET = "" @@ -33,14 +31,9 @@ # =================== load json =================== -def enable_use_apigateway(): - global USE_APIGATEWAY - USE_APIGATEWAY = True - - def load_data(filename): """ - 解析JSON数据文件 + 解析 JSON 数据文件 """ data = {} try: @@ -136,23 +129,21 @@ def http_delete(url, data, headers=None, verify=False, cert=None, timeout=None, class Client(object): - def __init__(self, app_code, app_secret, bk_iam_host): + def __init__(self, app_code, app_secret, bk_apigateway_url): self.app_code = app_code self.app_secret = app_secret - self.bk_iam_host = bk_iam_host + self.bk_apigateway_url = bk_apigateway_url.rstrip("/") self.system_id_set = set() self.resource_id_set = set() self.action_id_set = set() # 调用权限中心方法 def _call_iam_api(self, http_func, path, data): - headers = {"X-BK-APP-CODE": self.app_code, "X-BK-APP-SECRET": self.app_secret} - if USE_APIGATEWAY: - headers = { - "X-Bkapi-Authorization": json.dumps({"bk_app_code": self.app_code, "bk_app_secret": self.app_secret}), - } + headers = { + "X-Bkapi-Authorization": json.dumps({"bk_app_code": self.app_code, "bk_app_secret": self.app_secret}), + } - url = "{host}{path}".format(host=self.bk_iam_host, path=path) + url = "{host}{path}".format(host=self.bk_apigateway_url, path=path) ok, _data = http_func(url, data, headers=headers) # TODO: add debug here if not ok: @@ -209,7 +200,7 @@ def _call_iam_api(self, http_func, path, data): "upsert_feature_shield_rules": "update_feature_shield_rules", "add_custom_frontend_settings": "add_custom_frontend_settings", "update_custom_frontend_settings": "update_custom_frontend_settings", - "upsert_custom_frontend_settings": "update_custom_frontend_settings" + "upsert_custom_frontend_settings": "update_custom_frontend_settings", } """ @@ -561,13 +552,13 @@ def setup_models(self, system_id_set, resource_id_set, action_id_set, instance_s # ---------- ping -def api_ping(bk_iam_host): - url = "{host}{path}".format(host=bk_iam_host, path="/ping") +def api_ping(bk_apigateway_url): + url = "{host}{path}".format(host=bk_apigateway_url, path="/ping") ok, data = http_get(url, None, timeout=5) return ok, data -def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_SECRET): +def do_migrate(data, bk_apigateway_url=BK_APIGATEWAY_URL, app_code=APP_CODE, app_secret=APP_SECRET): system_id = data.get("system_id") if not system_id: print("invald json. [system_id] required, and should not be empty") @@ -580,7 +571,7 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_ print("do migrate") - client = Client(app_code, app_secret, bk_iam_host) + client = Client(app_code, app_secret, bk_apigateway_url) # 1. query all data of the system system_ids, resource_type_ids, action_ids, instance_selection_ids = client.query_all_models(system_id) @@ -619,11 +610,8 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_ p.add_argument( "-t", action="store", - dest="bk_iam_host", - help=( - "bk_iam_host, i.e: http://iam.service.consul;" - "you can use bk_apigateway_url here, set with the '--apigateway' " - ), + dest="bk_apigateway_url", + help=("bk_apigateway_url, i.e: http://bkapi.example.com/api/bk-iam/prod/;"), required=True, ) p.add_argument( @@ -636,34 +624,17 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_ p.add_argument("-a", action="store", dest="app_code", help="app code", required=True) p.add_argument("-s", action="store", dest="app_secret", help="app secret", required=True) - p.add_argument( - "--apigateway", - action="store_true", - dest="use_apigateway", - help="you can use bk_apigateway_url in '-t', should set this flag", - ) args = p.parse_args() - BK_IAM_HOST = args.bk_iam_host.rstrip("/") - USE_APIGATEWAY = args.use_apigateway - if USE_APIGATEWAY: - print( - "use apigateway:", - args.use_apigateway, - ", please make sure '-t %s' is a valid bk_apigateway_url" % args.bk_iam_host, - ) - - if not BK_IAM_HOST.startswith("http://"): - BK_IAM_HOST = "http://%s" % BK_IAM_HOST - data_file = args.json_data_file APP_CODE = args.app_code APP_SECRET = args.app_secret + BK_APIGATEWAY_URL = args.bk_apigateway_url.rstrip("/") # test ping - ok, _ = api_ping(BK_IAM_HOST) + ok, _ = api_ping(BK_APIGATEWAY_URL) if not ok: - print("iam service is not available: %s" % BK_IAM_HOST) + print("iam service is not available: %s" % BK_APIGATEWAY_URL) exit(1) print("start migrate [%s]" % data_file) @@ -673,7 +644,7 @@ def do_migrate(data, bk_iam_host=BK_IAM_HOST, app_code=APP_CODE, app_secret=APP_ if not data: exit(1) - ok = do_migrate(data, BK_IAM_HOST, APP_CODE, APP_SECRET) + ok = do_migrate(data, BK_APIGATEWAY_URL, APP_CODE, APP_SECRET) if not ok: print("do migrate [%s] fail" % data_file) exit(1) diff --git a/iam/dummy_iam.py b/iam/dummy_iam.py index 8462d8c..bef9681 100644 --- a/iam/dummy_iam.py +++ b/iam/dummy_iam.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -26,8 +26,8 @@ class DummyIAM(object): input: object """ - def __init__(self, app_code, app_secret, bk_iam_host, bk_paas_host): - self._client = Client(app_code, app_secret, bk_iam_host, bk_paas_host) + def __init__(self, app_code, app_secret, bk_apigateway_url, bk_tenant_id=""): + self._client = Client(app_code, app_secret, bk_apigateway_url, bk_tenant_id) def _do_policy_query(self, request, with_resources=True): return [] @@ -55,7 +55,7 @@ def _build_object_set(self, system, resources, only_local=False): for resource in resources: # only local resource need to be calculated - # 跨系统资源依赖的策略在服务端就计算完了, 策略表达式中只会存在本系统的 + # 跨系统资源依赖的策略在服务端就计算完了,策略表达式中只会存在本系统的 if only_local and (resource.system != system): continue @@ -65,7 +65,7 @@ def _build_object_set(self, system, resources, only_local=False): resource_id_list.append((resource.type, resource.id)) - # 如果只有一个本地资源, 直接返回不带类型的ID; + # 如果只有一个本地资源,直接返回不带类型的 ID; # [("flow", "1")] => "1" # 如果存在层级资源 返回 {type},{id}/{type2},{id2} # [("cluster", "a"), ("area", "b")) => "cluster,a/area,b" @@ -105,7 +105,7 @@ def _validate_resources_list(self, resources_list): raise AuthInvalidParam("resources should be list of iam.auth.models.Resource") def _validate_resources_list_same_local_only(self, system, resources_list): - # 校验, resources_list中只能是本地同一类的资源 + # 校验,resources_list 中只能是本地同一类的资源 resource_types = {} for rs in resources_list: for r in rs: @@ -126,27 +126,27 @@ def is_allowed_with_cache(self, request): def is_allowed(self, request): """ 单个资源是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 - - 跨系统资源依赖 resources中有本地也有远程资源 (此时resoruces一定要传, 因为需要IAM帮助获取跨系统资源) + 支持: + - 本地资源 resources 中只有本地资源 + - 跨系统资源依赖 resources 中有本地也有远程资源 (此时 resoruces 一定要传,因为需要 IAM 帮助获取跨系统资源) """ return True def batch_is_allowed(self, request, resources_list): """ 多个资源是否有权限校验 - request中不会带resource到IAM, IAM不会会进行两阶段计算, 直接返回system+action+subejct的所有策略 + request 中不会带 resource 到 IAM, IAM 不会会进行两阶段计算,直接返回 system+action+subejct 的所有策略 然后逐一计算 - - 一次策略查询, 多次计算 + - 一次策略查询,多次计算 - 支持: - - 本地资源 resources中只有本地资源 + 支持: + - 本地资源 resources 中只有本地资源 - **不支持**跨系统资源依赖 """ - # NOTE: 不向服务端传任何resource + # NOTE: 不向服务端传任何 resource result = {} for resources in resources_list: _, resource_id = self._build_object_set(request.system, resources, only_local=False) @@ -155,12 +155,12 @@ def batch_is_allowed(self, request, resources_list): def resource_multi_actions_allowed(self, request): """ - 单个资源多个action是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + 单个资源多个 action 是否有权限校验 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 - - 跨系统资源依赖 resources中有本地也有远程资源 (此时resoruces一定要传, 因为需要IAM帮助获取跨系统资源) + 支持: + - 本地资源 resources 中只有本地资源 + - 跨系统资源依赖 resources 中有本地也有远程资源 (此时 resoruces 一定要传,因为需要 IAM 帮助获取跨系统资源) """ actions_allowed = {} for a in request.to_dict()["actions"]: @@ -170,11 +170,11 @@ def resource_multi_actions_allowed(self, request): def batch_resource_multi_actions_allowed(self, request, resources_list): """ - 批量资源多个action是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + 批量资源多个 action 是否有权限校验 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 + 支持: + - 本地资源 resources 中只有本地资源 - **不支持**跨系统资源依赖 """ resources_actions_perms = {} @@ -196,7 +196,7 @@ def get_token(self, system): def is_basic_auth_allowed(self, system, basic_auth): return True - def get_apply_url(self, application, bk_token=None, bk_username=None): + def get_apply_url(self, application): if isinstance(application, dict): data = application elif isinstance(application, Application): @@ -206,46 +206,37 @@ def get_apply_url(self, application, bk_token=None, bk_username=None): else: raise AuthInvalidRequest("application shuld be instance of dict or iam.apply.modles.Application") - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - # bool, message, url - return self._client.get_apply_url(bk_token, bk_username, data) + return self._client.get_apply_url(data) - def grant_resource_creator_actions(self, application, bk_token=None, bk_username=None): + def grant_resource_creator_actions(self, application): return True, "success" - def grant_resource_creator_action_attributes(self, application, bk_token=None, bk_username=None): + def grant_resource_creator_action_attributes(self, application): return True, "success" - def grant_batch_resource_creator_actions(self, application, bk_token=None, bk_username=None): + def grant_batch_resource_creator_actions(self, application): return True, "success" - def grant_or_revoke_instance_permission(self, request, bk_token=None, bk_username=None): + def grant_or_revoke_instance_permission(self, request): if not isinstance(request, ApiAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiAuthRequest") self._validate_request(request) data = request.to_dict() - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - - ok, message, policies = self._client.instance_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.instance_authorization(data) if not ok: raise AuthAPIError(message) return policies - def grant_or_revoke_path_permission(self, request, bk_token=None, bk_username=None): + def grant_or_revoke_path_permission(self, request): if not isinstance(request, ApiAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiAuthRequest") self._validate_request(request) data = request.to_dict() - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - - ok, message, policies = self._client.path_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.path_authorization(data) if not ok: raise AuthAPIError(message) return policies diff --git a/iam/iam.py b/iam/iam.py index b267c78..fbed006 100644 --- a/iam/iam.py +++ b/iam/iam.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -37,18 +37,8 @@ class IAM(object): input: object """ - def __init__( - self, app_code, app_secret, bk_iam_host=None, bk_paas_host=None, bk_apigateway_url=None, api_version="v2" - ): - """ - 如果有 APIGateway 且权限中心网关接入, 则可以统一API请求全部走APIGateway - - 没有APIGateway的用法: IAM(app_code, app_secret, bk_iam_host, bk_paas_host) - - 有APIGateway的用法: IAM(app_code, app_secret, bk_apigateway_url) - - NOTE: 未来将会下线`没有 APIGateway的用法` - TODO: 切换后, 所有暴露接口将不再依赖 bk_token/bk_username, 需考虑兼容调用方, 并文档说明 - """ - self._client = Client(app_code, app_secret, bk_iam_host, bk_paas_host, bk_apigateway_url) + def __init__(self, app_code, app_secret, bk_apigateway_url, bk_tenant_id="", api_version="v2"): + self._client = Client(app_code, app_secret, bk_apigateway_url, bk_tenant_id) self._api_version = api_version @@ -56,8 +46,8 @@ def _do_policy_query(self, request, with_resources=True): data = request.to_dict() logger.debug("the request: %s", data) - # NOTE: 不向服务端传任何resource, 用于统一类资源的批量鉴权 - # 将会返回所有策略, 然后遍历资源列表和策略列表, 逐一计算 + # NOTE: 不向服务端传任何 resource, 用于统一类资源的批量鉴权 + # 将会返回所有策略,然后遍历资源列表和策略列表,逐一计算 if not with_resources: data["resources"] = [] @@ -77,8 +67,8 @@ def _do_policy_query_by_actions(self, request, with_resources=True): data = request.to_dict() logger.debug("the request: %s", data) - # NOTE: 不向服务端传任何resource, 用于统一类资源的批量鉴权 - # 将会返回所有策略, 然后遍历资源列表和策略列表, 逐一计算 + # NOTE: 不向服务端传任何 resource, 用于统一类资源的批量鉴权 + # 将会返回所有策略,然后遍历资源列表和策略列表,逐一计算 if not with_resources: data["resources"] = [] @@ -121,7 +111,7 @@ def _build_object_set(self, system, resources, only_local=False): for resource in resources: # only local resource need to be calculated - # 跨系统资源依赖的策略在服务端就计算完了, 策略表达式中只会存在本系统的 + # 跨系统资源依赖的策略在服务端就计算完了,策略表达式中只会存在本系统的 if only_local and (resource.system != system): continue @@ -131,7 +121,7 @@ def _build_object_set(self, system, resources, only_local=False): resource_id_list.append((resource.type, resource.id)) - # 如果只有一个本地资源, 直接返回不带类型的ID; + # 如果只有一个本地资源,直接返回不带类型的 ID; # [("flow", "1")] => "1" # 如果存在层级资源 返回 {type},{id}/{type2},{id2} # [("cluster", "a"), ("area", "b")) => "cluster,a/area,b" @@ -171,7 +161,7 @@ def _validate_resources_list(self, resources_list): raise AuthInvalidParam("resources should be list of iam.auth.models.Resource") def _validate_resources_list_same_local_only(self, system, resources_list): - # 校验, resources_list中只能是本地同一类的资源 + # 校验,resources_list 中只能是本地同一类的资源 resource_types = {} for rs in resources_list: for r in rs: @@ -193,11 +183,11 @@ def is_allowed_with_cache(self, request): def is_allowed(self, request): """ 单个资源是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 - - 跨系统资源依赖 resources中有本地也有远程资源 (此时resoruces一定要传, 因为需要IAM帮助获取跨系统资源) + 支持: + - 本地资源 resources 中只有本地资源 + - 跨系统资源依赖 resources 中有本地也有远程资源 (此时 resoruces 一定要传,因为需要 IAM 帮助获取跨系统资源) """ logger.debug("calling IAM.is_allowed(request)......") @@ -221,11 +211,11 @@ def is_allowed(self, request): def is_allowed_with_policy_cache(self, request): """ - 单个资源是否有权限校验, 缓存查询得到的策略 - 同一个subject-system-action查询到的策略会被缓存 - 不同的实例使用同一份缓存的策略, 提升鉴权性能 + 单个资源是否有权限校验,缓存查询得到的策略 + 同一个 subject-system-action 查询到的策略会被缓存 + 不同的实例使用同一份缓存的策略,提升鉴权性能 - 策略缓存1分钟 + 策略缓存 1 分钟 """ # 1. validate self._validate_request(request) @@ -252,13 +242,13 @@ def is_allowed_with_policy_cache(self, request): def batch_is_allowed(self, request, resources_list): """ 多个资源是否有权限校验 - request中不会带resource到IAM, IAM不会会进行两阶段计算, 直接返回system+action+subejct的所有策略 + request 中不会带 resource 到 IAM, IAM 不会会进行两阶段计算,直接返回 system+action+subejct 的所有策略 然后逐一计算 - - 一次策略查询, 多次计算 + - 一次策略查询,多次计算 - 支持: - - 本地资源 resources中只有本地资源 + 支持: + - 本地资源 resources 中只有本地资源 - **不支持**跨系统资源依赖 """ logger.debug("calling IAM.batch_is_allowed(request, resources_list)......") @@ -272,7 +262,7 @@ def batch_is_allowed(self, request, resources_list): data = request.to_dict() logger.debug("the request: %s", data) - # NOTE: 不向服务端传任何resource + # NOTE: 不向服务端传任何 resource result = {} policies = self._do_policy_query(request, with_resources=False) logger.debug("the return policies: %s", policies) @@ -297,12 +287,12 @@ def batch_is_allowed(self, request, resources_list): def resource_multi_actions_allowed(self, request): """ - 单个资源多个action是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + 单个资源多个 action 是否有权限校验 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 - - 跨系统资源依赖 resources中有本地也有远程资源 (此时resoruces一定要传, 因为需要IAM帮助获取跨系统资源) + 支持: + - 本地资源 resources 中只有本地资源 + - 跨系统资源依赖 resources 中有本地也有远程资源 (此时 resoruces 一定要传,因为需要 IAM 帮助获取跨系统资源) """ logger.debug("calling IAM.resource_multi_actions_allowed(request)......") @@ -326,7 +316,7 @@ def resource_multi_actions_allowed(self, request): # 3. calculate perms obj_set, _ = self._build_object_set(request.system, request.resources, only_local=True) - # 4. 一个策略是一个表达式, 计算一次 + # 4. 一个策略是一个表达式,计算一次 for action_policy in action_policies: action = action_policy["action"]["id"] policies = action_policy["condition"] @@ -336,11 +326,11 @@ def resource_multi_actions_allowed(self, request): def batch_resource_multi_actions_allowed(self, request, resources_list): """ - 批量资源多个action是否有权限校验 - request中会带resource到IAM, IAM会进行两阶段计算, 即resources也会参与到计算中 + 批量资源多个 action 是否有权限校验 + request 中会带 resource 到 IAM, IAM 会进行两阶段计算,即 resources 也会参与到计算中 - 支持: - - 本地资源 resources中只有本地资源 + 支持: + - 本地资源 resources 中只有本地资源 - **不支持**跨系统资源依赖 """ logger.debug("calling IAM.batch_resource_multi_actions_allowed(request, resources_list)......") @@ -354,7 +344,7 @@ def batch_resource_multi_actions_allowed(self, request, resources_list): logger.debug("the request: %s", data) # 2. _client.policy_query_by_actions - # NOTE: 不向服务端传任何resource + # NOTE: 不向服务端传任何 resource action_policies = self._do_policy_query_by_actions(request, with_resources=False) resources_actions_perms = {} @@ -370,11 +360,11 @@ def batch_resource_multi_actions_allowed(self, request, resources_list): # 4. calculate perms for resources in resources_list: - # NOTE: 这里假设resources里面只有一个本地资源 + # NOTE: 这里假设 resources 里面只有一个本地资源 obj_set, resource_id = self._build_object_set(request.system, resources, only_local=False) - # FIXME: 未来这里会支持同一个系统的不同资源, 届时怎么表示? + # FIXME: 未来这里会支持同一个系统的不同资源,届时怎么表示? - # 一个策略是一个表达式, 计算一次 + # 一个策略是一个表达式,计算一次 for action_policy in action_policies: action = action_policy["action"]["id"] policies = action_policy["condition"] @@ -411,7 +401,7 @@ def make_filter(self, request, converter_class=DjangoQuerySetConverter, key_mapp # TODO: add the register model apis def get_token(self, system): - """获取token + """获取 token return bool, message, token """ return self._client.get_token(system) @@ -456,7 +446,7 @@ def is_basic_auth_allowed(self, system, basic_auth): return True - def get_apply_url(self, application, bk_token=None, bk_username=None): + def get_apply_url(self, application): if isinstance(application, dict): data = application elif isinstance(application, Application): @@ -466,49 +456,37 @@ def get_apply_url(self, application, bk_token=None, bk_username=None): else: raise AuthInvalidRequest("application shuld be instance of dict or iam.apply.modles.Application") - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - # bool, message, url - return self._client.get_apply_url(bk_token, bk_username, data) + return self._client.get_apply_url(data) - def grant_resource_creator_actions(self, application, bk_token=None, bk_username=None): + def grant_resource_creator_actions(self, application): if isinstance(application, dict): data = application else: raise AuthInvalidRequest("application should be instance of dict") - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - # bool, message, url - return self._client.grant_resource_creator_actions(bk_token, bk_username, data) + return self._client.grant_resource_creator_actions(data) - def grant_resource_creator_action_attributes(self, application, bk_token=None, bk_username=None): + def grant_resource_creator_action_attributes(self, application): if isinstance(application, dict): data = application else: raise AuthInvalidRequest("application should be instance of dict") - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - # bool, message - return self._client.grant_resource_creator_action_attributes(bk_token, bk_username, data) + return self._client.grant_resource_creator_action_attributes(data) - def grant_batch_resource_creator_actions(self, application, bk_token=None, bk_username=None): + def grant_batch_resource_creator_actions(self, application): if isinstance(application, dict): data = application else: raise AuthInvalidRequest("application should be instance of dict") - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - # bool, message, url - return self._client.grant_batch_resource_creator_actions(bk_token, bk_username, data) + return self._client.grant_batch_resource_creator_actions(data) - def grant_or_revoke_instance_permission(self, request, bk_token=None, bk_username=None): + def grant_or_revoke_instance_permission(self, request): if not isinstance(request, ApiAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiAuthRequest") @@ -516,30 +494,26 @@ def grant_or_revoke_instance_permission(self, request, bk_token=None, bk_usernam data = request.to_dict() logger.debug("the request: %s", data) - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - ok, message, policies = self._client.instance_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.instance_authorization(data) if not ok: raise AuthAPIError(message) return policies - def grant_or_revoke_path_permission(self, request, bk_token=None, bk_username=None): + def grant_or_revoke_path_permission(self, request): if not isinstance(request, ApiAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiAuthRequest") self._validate_request(request) data = request.to_dict() logger.debug("the request: %s", data) - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - ok, message, policies = self._client.path_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.path_authorization(data) if not ok: raise AuthAPIError(message) return policies - def batch_grant_or_revoke_instance_permission(self, request, bk_token=None, bk_username=None): + def batch_grant_or_revoke_instance_permission(self, request): if not isinstance(request, ApiBatchAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiBatchAuthRequest") @@ -547,15 +521,13 @@ def batch_grant_or_revoke_instance_permission(self, request, bk_token=None, bk_u data = request.to_dict() logger.debug("the request: %s", data) - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - ok, message, policies = self._client.batch_instance_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.batch_instance_authorization(data) if not ok: raise AuthAPIError(message) return policies - def batch_grant_or_revoke_path_permission(self, request, bk_token=None, bk_username=None): + def batch_grant_or_revoke_path_permission(self, request): if not isinstance(request, ApiBatchAuthRequest): raise AuthInvalidRequest("request should be a instance of iam.auth.models.ApiBatchAuthRequest") @@ -563,10 +535,8 @@ def batch_grant_or_revoke_path_permission(self, request, bk_token=None, bk_usern data = request.to_dict() logger.debug("the request: %s", data) - if not (bk_token or bk_username): - raise AuthInvalidRequest("bk_token and bk_username can not both be empty") - ok, message, policies = self._client.batch_path_authorization(bk_token, bk_username, data) + ok, message, policies = self._client.batch_path_authorization(data) if not ok: raise AuthAPIError(message) return policies diff --git a/main.py b/main.py index 3daa9c5..208e76a 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -18,8 +18,8 @@ 1. 实现 and/or 2. 实现所有类型的操作符 3. 实现递归求值 -4. 加入模板方法限制, 确保每个operator实现eval -5. 加入Enum类, 去除字面量 +4. 加入模板方法限制,确保每个 operator 实现 eval +5. 加入 Enum 类,去除字面量 """ from __future__ import print_function @@ -166,8 +166,13 @@ def convert_example(): print("the request: ", request.to_dict()) - iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", "http://127.0.0.1:8080", "https://{PAAS_DOMAIN}") - # recommend if got an APIGateway - # iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", bk_apigateway_url="http://{IAM_APIGATEWAY_URL}") + iam = IAM("bk_paas", "2353e89a-10a2-4f30-9f6b-8973e9cd1404", bk_apigateway_url="http://{IAM_APIGATEWAY_URL}") + # Tenant Enabled + # iam = IAM( + # "bk_paas", + # "2353e89a-10a2-4f30-9f6b-8973e9cd1404", + # bk_apigateway_url="http://{IAM_APIGATEWAY_URL}", + # bk_tenant_id="test_tenant_id", + # ) print("is_allowed: ", iam.is_allowed(request)) print("query: ", iam.make_filter(request)) diff --git a/requirements_test.txt b/requirements_test.txt index fb7a7c9..e363784 100644 --- a/requirements_test.txt +++ b/requirements_test.txt @@ -1,32 +1,21 @@ -atomicwrites==1.4.0 -attrs==19.3.0 -backports.functools-lru-cache==1.6.1; python_version < "3.2" -cachetools==3.1.1 -certifi==2020.4.5.2 -chardet==3.0.4 -colorama==0.4.3; sys_platform == "win32" and python_version != "3.4" -configparser==4.0.2; python_version < "3" -contextlib2==0.6.0.post1; python_version < "3.4" -coverage==5.1 -curlify==2.2.1 -django==1.11.29 -django-tastypie==0.14.3 -funcsigs==1.0.2; python_version < "3.3" -idna==2.9 -importlib-metadata==1.6.1; python_version < "3.8" -mock==3.0.5 -more-itertools==5.0.0; python_version <= "2.7" or python_version > "2.7" -packaging==20.4 -pathlib2==2.3.5; python_version < "3.6" -pluggy==0.13.1 -py==1.10.0 -pyparsing==2.4.7 -pytest==4.6.10 -pytest-cov==2.9.0 -pytz==2020.1 -requests==2.23.0 -scandir==1.10.0; python_version < "3.5" -six==1.14.0 -urllib3==1.25.9 -wcwidth==0.2.4 -zipp==1.2.0; python_version < "3.8" +asgiref==3.8.1 ; python_version >= "3.8" and python_version < "3.13" +backports-zoneinfo==0.2.1 ; python_version == "3.8" +cachetools==5.5.2 ; python_version >= "3.8" and python_version < "3.13" +certifi==2025.4.26 ; python_version >= "3.8" and python_version < "3.13" +charset-normalizer==3.4.2 ; python_version >= "3.8" and python_version < "3.13" +colorama==0.4.6 ; python_version >= "3.8" and python_version < "3.13" and sys_platform == "win32" +curlify==2.2.1 ; python_version >= "3.8" and python_version < "3.13" +django==4.2.21 ; python_version >= "3.8" and python_version < "3.13" +exceptiongroup==1.3.0 ; python_version >= "3.8" and python_version < "3.11" +idna==3.10 ; python_version >= "3.8" and python_version < "3.13" +iniconfig==2.1.0 ; python_version >= "3.8" and python_version < "3.13" +packaging==25.0 ; python_version >= "3.8" and python_version < "3.13" +pluggy==1.5.0 ; python_version >= "3.8" and python_version < "3.13" +pytest==8.3.5 ; python_version >= "3.8" and python_version < "3.13" +requests==2.32.3 ; python_version >= "3.8" and python_version < "3.13" +six==1.17.0 ; python_version >= "3.8" and python_version < "3.13" +sqlparse==0.5.3 ; python_version >= "3.8" and python_version < "3.13" +tomli==2.2.1 ; python_version >= "3.8" and python_version < "3.11" +typing-extensions==4.13.2 ; python_version >= "3.8" and python_version < "3.11" +tzdata==2025.2 ; python_version >= "3.8" and python_version < "3.13" and sys_platform == "win32" +urllib3==2.2.3 ; python_version >= "3.8" and python_version < "3.13" diff --git a/setup.py b/setup.py index 23a0ac3..4e5853e 100644 --- a/setup.py +++ b/setup.py @@ -32,12 +32,14 @@ packages=setuptools.find_packages(), install_requires=requires, classifiers=[ - "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", ], - python_requires=">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4", + python_requires=">3, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, <4", ) diff --git a/tests/api/test_client.py b/tests/api/test_client.py index b0d6a79..22615e6 100644 --- a/tests/api/test_client.py +++ b/tests/api/test_client.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -64,7 +64,7 @@ def _test_v2_ok_message_data(mock_request, call_func): @patch("iam.api.client.http_post") def test_client_policy_query(mock_post): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") _test_ok_message_data(mock_post, c.policy_query) @@ -73,7 +73,7 @@ def test_client_policy_query(mock_post): @patch("iam.api.client.http_post") def test_v2_client_policy_query(mock_post): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") _test_v2_ok_message_data(mock_post, c.v2_policy_query) @@ -101,7 +101,7 @@ def _test_ok_message(mock_request, call_func, kwargs): @patch("iam.api.client.http_post") def test_create(mock_post): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") _test_ok_message(mock_post, c.add_system, dict(data={})) @@ -114,7 +114,7 @@ def test_create(mock_post): @patch("iam.api.client.http_put") def test_update(mock_put): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") _test_ok_message(mock_put, c.update_system, dict(system_id="", data={})) @@ -127,7 +127,7 @@ def test_update(mock_put): @patch("iam.api.client.http_delete") def test_delete(mock_delete): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") _test_ok_message(mock_delete, c.batch_delete_resource_types, dict(system_id="", data={})) @@ -136,13 +136,13 @@ def test_delete(mock_delete): @patch.dict(os.environ, {"ABC": "true"}) def test_client_extra_url_params_empty(): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") assert not c._extra_url_params @patch.dict(os.environ, {"IAM_API_DEBUG": "true"}) def test_client_extra_url_params_debug_1(): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") assert c._extra_url_params assert len(c._extra_url_params) == 1 assert c._extra_url_params.get("debug") == "true" @@ -150,7 +150,7 @@ def test_client_extra_url_params_debug_1(): @patch.dict(os.environ, {"BKAPP_IAM_API_DEBUG": "true"}) def test_client_extra_url_params_debug_2(): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") assert c._extra_url_params assert len(c._extra_url_params) == 1 assert c._extra_url_params.get("debug") == "true" @@ -158,7 +158,7 @@ def test_client_extra_url_params_debug_2(): @patch.dict(os.environ, {"IAM_API_FORCE": "true"}) def test_client_extra_url_params_force_1(): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") assert c._extra_url_params assert len(c._extra_url_params) == 1 assert c._extra_url_params.get("force") == "true" @@ -166,7 +166,7 @@ def test_client_extra_url_params_force_1(): @patch.dict(os.environ, {"BKAPP_IAM_API_FORCE": "true"}) def test_client_extra_url_params_force_2(): - c = Client("bk_paas", "", "http://127.0.0.1:1234", "http://127.0.0.1:8000") + c = Client("bk_paas", "", "http://127.0.0.1:1234") assert c._extra_url_params assert len(c._extra_url_params) == 1 assert c._extra_url_params.get("force") == "true" diff --git a/tests/test_iam.py b/tests/test_iam.py index c92774b..a6a6db1 100644 --- a/tests/test_iam.py +++ b/tests/test_iam.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ TencentBlueKing is pleased to support the open source community by making -蓝鲸智云-权限中心Python SDK(iam-python-sdk) available. +蓝鲸智云 - 权限中心 Python SDK(iam-python-sdk) available. Copyright (C) 2017-2021 THL A29 Limited, a Tencent company. All rights reserved. Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://opensource.org/licenses/MIT @@ -27,7 +27,7 @@ def new_mock_iam(): - return IAM("test", "test", "iam_host", "paas_host", None) + return IAM("test", "test", "bk_iam_apigateway_url") def new_valid_request():