diff --git a/src/bk-login/bklogin/authentication/views.py b/src/bk-login/bklogin/authentication/views.py index a2f74ff13..60f6ca8c1 100644 --- a/src/bk-login/bklogin/authentication/views.py +++ b/src/bk-login/bklogin/authentication/views.py @@ -10,7 +10,7 @@ """ import logging from typing import Any, Callable, Dict, List -from urllib.parse import quote_plus, urljoin +from urllib.parse import quote_plus import pydantic from django.conf import settings @@ -35,6 +35,7 @@ UnexpectedDataError, ValidationError, ) +from bklogin.utils.url import urljoin from .constants import ALLOWED_SIGN_IN_TENANT_USERS_SESSION_KEY, REDIRECT_FIELD_NAME, SIGN_IN_TENANT_ID_SESSION_KEY from .manager import BkTokenManager diff --git a/src/bk-login/bklogin/component/bk_user/api.py b/src/bk-login/bklogin/component/bk_user/api.py index dc3ded776..c0e54edbd 100644 --- a/src/bk-login/bklogin/component/bk_user/api.py +++ b/src/bk-login/bklogin/component/bk_user/api.py @@ -10,13 +10,13 @@ """ import logging from typing import Any, Callable, Dict, List -from urllib.parse import urljoin from django.conf import settings from requests.auth import HTTPBasicAuth from bklogin.common.error_codes import error_codes from bklogin.component.http import HttpStatusCode, http_get, http_post +from bklogin.utils.url import urljoin from .models import GlobalSetting, IdpDetailInfo, IdpInfo, TenantInfo, TenantUserDetailInfo, TenantUserInfo diff --git a/src/bk-login/bklogin/utils/url.py b/src/bk-login/bklogin/utils/url.py new file mode 100644 index 000000000..1593d9ac7 --- /dev/null +++ b/src/bk-login/bklogin/utils/url.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) 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 +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + + +def urljoin(host: str, path: str) -> str: + """ + 拼接host, path生成url,核心是处理host, path有多余/的情况 + Q: 为什么不直接使用 urllib.parse.urljoin + A: urllib.parse.urljoin 会根据path是否带"/"前缀,对host的带部分path进行移除 + urllib.parse.urljoin("https://example.com/abc", "/efg/index.html") => "https://example.com/efg/index.html" + """ + return "{}/{}".format(host.rstrip("/"), path.lstrip("/")) diff --git a/src/bk-login/tests/utils/test_url.py b/src/bk-login/tests/utils/test_url.py new file mode 100644 index 000000000..df76075c7 --- /dev/null +++ b/src/bk-login/tests/utils/test_url.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) 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 +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +import pytest +from bklogin.utils.url import urljoin + + +@pytest.mark.parametrize( + ("host", "path", "excepted"), + [ + ("https://example.com/abc", "/efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc", "efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc/", "/efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc/", "efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com", "efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com", "/efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com/", "efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com/", "/efg/index.html", "https://example.com/efg/index.html"), + ], +) +def test_urljoin(host, path, excepted): + assert urljoin(host, path) == excepted diff --git a/src/bk-user/bkuser/apps/idp/models.py b/src/bk-user/bkuser/apps/idp/models.py index 21630b708..ff12c8a1c 100644 --- a/src/bk-user/bkuser/apps/idp/models.py +++ b/src/bk-user/bkuser/apps/idp/models.py @@ -9,7 +9,6 @@ specific language governing permissions and limitations under the License. """ from typing import List -from urllib.parse import urljoin from blue_krill.models.fields import EncryptField from django.conf import settings @@ -20,6 +19,7 @@ from bkuser.idp_plugins.base import BasePluginConfig, get_plugin_cfg_cls, get_plugin_type from bkuser.idp_plugins.constants import BuiltinIdpPluginEnum, PluginTypeEnum from bkuser.utils import dictx +from bkuser.utils.url import urljoin from bkuser.utils.uuid import generate_uuid from .constants import IdpStatus diff --git a/src/bk-user/bkuser/component/esb.py b/src/bk-user/bkuser/component/esb.py index 860fdf545..8b43df9fb 100644 --- a/src/bk-user/bkuser/component/esb.py +++ b/src/bk-user/bkuser/component/esb.py @@ -10,12 +10,13 @@ """ import json import logging -from urllib.parse import urljoin, urlparse +from urllib.parse import urlparse from django.conf import settings from bkuser.common.error_codes import error_codes from bkuser.common.local import local +from bkuser.utils.url import urljoin logger = logging.getLogger("component") diff --git a/src/bk-user/bkuser/component/login.py b/src/bk-user/bkuser/component/login.py index 58329bba7..479abb2e4 100644 --- a/src/bk-user/bkuser/component/login.py +++ b/src/bk-user/bkuser/component/login.py @@ -9,12 +9,13 @@ specific language governing permissions and limitations under the License. """ import logging -from urllib.parse import urljoin, urlparse +from urllib.parse import urlparse from django.conf import settings from bkuser.common.error_codes import error_codes from bkuser.common.local import local +from bkuser.utils.url import urljoin from .http import http_get diff --git a/src/bk-user/bkuser/utils/url.py b/src/bk-user/bkuser/utils/url.py new file mode 100644 index 000000000..1593d9ac7 --- /dev/null +++ b/src/bk-user/bkuser/utils/url.py @@ -0,0 +1,20 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) 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 +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" + + +def urljoin(host: str, path: str) -> str: + """ + 拼接host, path生成url,核心是处理host, path有多余/的情况 + Q: 为什么不直接使用 urllib.parse.urljoin + A: urllib.parse.urljoin 会根据path是否带"/"前缀,对host的带部分path进行移除 + urllib.parse.urljoin("https://example.com/abc", "/efg/index.html") => "https://example.com/efg/index.html" + """ + return "{}/{}".format(host.rstrip("/"), path.lstrip("/")) diff --git a/src/bk-user/tests/utils/test_url.py b/src/bk-user/tests/utils/test_url.py new file mode 100644 index 000000000..8d59f9519 --- /dev/null +++ b/src/bk-user/tests/utils/test_url.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +""" +TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-用户管理(Bk-User) 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 +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on +an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. +""" +import pytest +from bkuser.utils.url import urljoin + + +@pytest.mark.parametrize( + ("host", "path", "excepted"), + [ + ("https://example.com/abc", "/efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc", "efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc/", "/efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com/abc/", "efg/index.html", "https://example.com/abc/efg/index.html"), + ("https://example.com", "efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com", "/efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com/", "efg/index.html", "https://example.com/efg/index.html"), + ("https://example.com/", "/efg/index.html", "https://example.com/efg/index.html"), + ], +) +def test_urljoin(host, path, excepted): + assert urljoin(host, path) == excepted diff --git a/src/idp-plugins/idp_plugins/local/client.py b/src/idp-plugins/idp_plugins/local/client.py index bf8a50cf5..efdfa4d9e 100644 --- a/src/idp-plugins/idp_plugins/local/client.py +++ b/src/idp-plugins/idp_plugins/local/client.py @@ -10,13 +10,13 @@ """ import logging from typing import Any, Dict, List -from urllib.parse import urljoin from requests.auth import HTTPBasicAuth from .settings import BK_USER_API_URL, BK_USER_APP_CODE, BK_USER_APP_SECRET from ..exceptions import RequestAPIError, ValidationError from ..http import http_post +from ..utils import urljoin logger = logging.getLogger(__name__) diff --git a/src/idp-plugins/idp_plugins/utils.py b/src/idp-plugins/idp_plugins/utils.py index 02d00d162..fffe6c393 100644 --- a/src/idp-plugins/idp_plugins/utils.py +++ b/src/idp-plugins/idp_plugins/utils.py @@ -18,6 +18,16 @@ from .exceptions import ParseRequestBodyError +def urljoin(host: str, path: str) -> str: + """ + 拼接host, path生成url,核心是处理host, path有多余/的情况 + Q: 为什么不直接使用 urllib.parse.urljoin + A: urllib.parse.urljoin 会根据path是否带"/"前缀,对host的带部分path进行移除 + urllib.parse.urljoin("https://example.com/abc", "/efg/index.html") => "https://example.com/efg/index.html" + """ + return "{}/{}".format(host.rstrip("/"), path.lstrip("/")) + + def parse_request_body_json(body: bytes) -> Dict[str, Any]: """解析请求Body Json数据""" try: diff --git a/src/idp-plugins/idp_plugins/wecom/client.py b/src/idp-plugins/idp_plugins/wecom/client.py index 024640d5c..d45ac6e1b 100644 --- a/src/idp-plugins/idp_plugins/wecom/client.py +++ b/src/idp-plugins/idp_plugins/wecom/client.py @@ -10,13 +10,13 @@ """ import logging from typing import Any, Dict, Tuple -from urllib.parse import urljoin from django.utils.translation import gettext_lazy as _ from .settings import WECOM_API_BASE_URL from ..exceptions import RequestAPIError, UnexpectedDataError from ..http import http_get_20x +from ..utils import urljoin logger = logging.getLogger(__name__) diff --git a/src/idp-plugins/idp_plugins/wecom/logo.png b/src/idp-plugins/idp_plugins/wecom/logo.png index 8dab6d1f0..69ea6d756 100644 Binary files a/src/idp-plugins/idp_plugins/wecom/logo.png and b/src/idp-plugins/idp_plugins/wecom/logo.png differ