diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index db891158..8ed0073c 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -25,10 +25,10 @@ jobs: LAB_OBO_PUBLIC_CLIENT_ID: ${{ secrets.LAB_OBO_PUBLIC_CLIENT_ID }} # Derived from https://docs.github.com/en/actions/guides/building-and-testing-python#starting-with-the-python-workflow-template - runs-on: ubuntu-latest # It switched to 22.04 shortly after 2022-Nov-8 + runs-on: ubuntu-22.04 strategy: matrix: - python-version: [3.7, 3.8, 3.9, "3.10", "3.11", "3.12"] + python-version: ['3.7', '3.8', '3.9', '3.10', '3.11', '3.12', '3.13'] steps: - uses: actions/checkout@v4 diff --git a/msal/cloudshell.py b/msal/cloudshell.py index f4feaf44..1a25dea4 100644 --- a/msal/cloudshell.py +++ b/msal/cloudshell.py @@ -32,8 +32,12 @@ def _scope_to_resource(scope): # This is an experimental reasonable-effort appr if scope.startswith(a): return a u = urlparse(scope) + if not u.scheme and not u.netloc: # Typically the "GUID/scope" case + return u.path.split("/")[0] if u.scheme: - return "{}://{}".format(u.scheme, u.netloc) + trailer = ( # https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc#trailing-slash-and-default + "/" if u.path.startswith("//") else "") + return "{}://{}{}".format(u.scheme, u.netloc, trailer) return scope # There is no much else we can do here diff --git a/setup.cfg b/setup.cfg index 33ec3f06..6dfcfc7b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -52,7 +52,7 @@ install_requires = # And we will use the cryptography (X+3).0.0 as the upper bound, # based on their latest deprecation policy # https://cryptography.io/en/latest/api-stability/#deprecation - cryptography>=2.5,<46 + cryptography>=2.5,<47 [options.extras_require] diff --git a/tests/test_cloudshell.py b/tests/test_cloudshell.py new file mode 100644 index 00000000..9a0e5709 --- /dev/null +++ b/tests/test_cloudshell.py @@ -0,0 +1,23 @@ +import unittest +from msal.cloudshell import _scope_to_resource + +class TestScopeToResource(unittest.TestCase): + + def test_expected_behaviors(self): + for scope, expected_resource in { + "https://analysis.windows.net/powerbi/api/foo": + "https://analysis.windows.net/powerbi/api", # A special case + "https://pas.windows.net/CheckMyAccess/Linux/.default": + "https://pas.windows.net/CheckMyAccess/Linux/.default", # Special case + "https://double-slash.com//scope": "https://double-slash.com/", + "https://single-slash.com/scope": "https://single-slash.com", + "guid/some/scope": "guid", + "6dae42f8-4368-4678-94ff-3960e28e3630/.default": + # The real guid of AKS resource + # https://learn.microsoft.com/en-us/azure/aks/kubelogin-authentication#how-to-use-kubelogin-with-aks + "6dae42f8-4368-4678-94ff-3960e28e3630", + }.items(): + self.assertEqual(_scope_to_resource(scope), expected_resource) + +if __name__ == '__main__': + unittest.main()