├── src ├── tests │ ├── casbinTest.svg │ ├── __init__.py │ ├── load_tests.py │ ├── test_resource.py │ ├── test_util.py │ ├── test_plan.py │ ├── test_webhook.py │ ├── test_role.py │ ├── test_group.py │ ├── test_payment.py │ ├── test_session.py │ ├── test_pricing.py │ ├── test_provider.py │ ├── test_adapter.py │ ├── test_enforcer.py │ ├── test_subscription.py │ ├── test_product.py │ ├── test_syncer.py │ ├── test_application.py │ ├── test_cert.py │ ├── test_permission.py │ ├── test_model.py │ ├── test_organization.py │ ├── test_user.py │ ├── test_oauth.py │ └── test_async_oauth.py ├── .DS_Store └── casdoor │ ├── __init__.py │ ├── plan.py │ ├── session.py │ ├── enforcer.py │ ├── adapter.py │ ├── pricing.py │ ├── model.py │ ├── cert.py │ ├── group.py │ ├── payment.py │ ├── webhook.py │ ├── subscription.py │ ├── product.py │ ├── token.py │ ├── provider.py │ ├── permission.py │ ├── syncer.py │ ├── resource.py │ ├── role.py │ ├── organization.py │ └── application.py ├── setup.py ├── .DS_Store ├── requirements.txt ├── .pre-commit-config.yaml ├── .releaserc.json ├── setup.cfg ├── .github └── workflows │ └── build.yml ├── pyproject.toml ├── .gitignore ├── README.md └── LICENSE /src/tests/casbinTest.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | setup() 4 | -------------------------------------------------------------------------------- /src/tests/__init__.py: -------------------------------------------------------------------------------- 1 | from .test_oauth import TestOAuth # noqa: F401 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/casdoor/casdoor-python-sdk/HEAD/.DS_Store -------------------------------------------------------------------------------- /src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/casdoor/casdoor-python-sdk/HEAD/src/.DS_Store -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | aiohttp~=3.10.11 2 | cryptography~=44.0.0 3 | PyJWT~=2.8.0 4 | requests~=2.32.0 5 | setuptools>=68.0.0 6 | yarl~=1.15.2 7 | -------------------------------------------------------------------------------- /src/casdoor/__init__.py: -------------------------------------------------------------------------------- 1 | from .async_main import AsyncCasdoorSDK # noqa: F401 2 | from .main import CasdoorSDK # noqa: F401 3 | from .user import User # noqa: F401 4 | -------------------------------------------------------------------------------- /src/tests/load_tests.py: -------------------------------------------------------------------------------- 1 | import os 2 | import unittest 3 | 4 | 5 | def load_tests(loader, tests, pattern): 6 | top_level_dir = os.path.dirname(__file__) 7 | pattern = "test_*.py" 8 | exclude_files = ["test_oauth", "test_async_oauth"] 9 | suite = unittest.TestSuite() 10 | 11 | # using loader.discover to find all test modules 12 | discovered_suite = loader.discover(top_level_dir, pattern=pattern) 13 | 14 | # add all tests to the suite 15 | for test in discovered_suite: 16 | if any(exclude_file in str(test) for exclude_file in exclude_files): 17 | continue 18 | suite.addTest(test) 19 | 20 | return suite 21 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_stages: [ commit ] 2 | fail_fast: true 3 | 4 | repos: 5 | - repo: local 6 | hooks: 7 | - id: black 8 | name: black 9 | entry: black 10 | language: system 11 | types: [ python ] 12 | description: "Black code formatter" 13 | 14 | - id: ruff 15 | name: ruff 16 | description: "Ruff code checker" 17 | entry: ruff check 18 | args: [ --fix, --exit-non-zero-on-fix ] 19 | language: system 20 | types: [ python ] 21 | 22 | 23 | - repo: https://github.com/commitizen-tools/commitizen 24 | rev: v3.2.2 25 | hooks: 26 | - id: commitizen 27 | stages: [ commit-msg ] 28 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": "master", 3 | "plugins": [ 4 | "@semantic-release/commit-analyzer", 5 | "@semantic-release/release-notes-generator", 6 | "semantic-release-pypi", 7 | "@semantic-release/github", 8 | [ 9 | "@semantic-release/changelog", 10 | { 11 | "changelogFile": "CHANGELOG.md", 12 | "changelogTitle": "# Semantic Versioning Changelog" 13 | } 14 | ], 15 | [ 16 | "@semantic-release/git", 17 | { 18 | "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}", 19 | "assets": ["CHANGELOG.md", "setup.py", "setup.cfg"] 20 | } 21 | ] 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = casdoor 3 | version = 1.17.0 4 | author = ffyuanda 5 | author_email = shaoxuan.yuan02@gmail.com 6 | url = https://github.com/casdoor/casdoor-python-sdk 7 | description = Python SDK built for Casdoor 8 | long_description = file: README.md 9 | long_description_content_type = text/markdown 10 | license = Apache 2.0 11 | platform = any 12 | keywords = Casdoor 13 | classifiers = 14 | Intended Audience :: Developers 15 | License :: OSI Approved :: Apache Software License 16 | Operating System :: OS Independent 17 | Programming Language :: Python 18 | Programming Language :: Python :: 3.6 19 | Programming Language :: Python :: 3.7 20 | Programming Language :: Python :: 3.8 21 | Programming Language :: Python :: 3.9 22 | Programming Language :: Python :: 3.10 23 | Programming Language :: Python :: 3.11 24 | 25 | [options] 26 | package_dir = 27 | =src 28 | packages = 29 | casdoor 30 | setup_requires = 31 | setuptools 32 | python_requires = >=3.6 33 | test_suite = tests 34 | 35 | [bdist_wheel] 36 | universal = true 37 | 38 | [sdist] 39 | formats = gztar 40 | 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | 8 | jobs: 9 | release: 10 | name: Release 11 | runs-on: ubuntu-latest 12 | #needs: [test] 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 18 | 19 | - name: Setup Node.js 20 | uses: actions/setup-node@v4 21 | with: 22 | node-version: '20' 23 | 24 | - name: Setup 25 | run: npm install -g semantic-release @semantic-release/github @semantic-release/changelog @semantic-release/commit-analyzer @semantic-release/git @semantic-release/release-notes-generator semantic-release-pypi 26 | 27 | - name: Set up python 28 | uses: actions/setup-python@v5 29 | with: 30 | python-version: '3.12' 31 | 32 | - name: Install setuptools 33 | run: python -m pip install --upgrade setuptools wheel twine 34 | 35 | - name: Install dependencies 36 | run: | 37 | python -m pip install --upgrade pip 38 | pip install black ruff pre-commit 39 | pip install -r requirements.txt 40 | 41 | - name: Run linter 42 | run: git diff --name-only HEAD~10 HEAD | xargs pre-commit run --files 43 | 44 | - name: Run tests 45 | run: python -m unittest src/tests/load_tests.py -v 46 | 47 | - name: Release 48 | env: 49 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 50 | PYPI_TOKEN: ${{ secrets.PYPI_TOKEN }} 51 | run: npx semantic-release -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "casdoor" 3 | version = "1.17.0" 4 | authors = [{name = "Casdoor", email = "admin@casdoor.org"}] 5 | description = "Python SDK built for Casdoor" 6 | readme = "README.md" 7 | license = { file = "LICENSE" } 8 | keywords = ["Casdoor"] 9 | classifiers = [ 10 | "Intended Audience :: Developers", 11 | "License :: OSI Approved :: Apache Software License", 12 | "Operating System :: OS Independent", 13 | "Programming Language :: Python", 14 | "Programming Language :: Python :: 3.6", 15 | "Programming Language :: Python :: 3.7", 16 | "Programming Language :: Python :: 3.8", 17 | "Programming Language :: Python :: 3.9", 18 | "Programming Language :: Python :: 3.10", 19 | "Programming Language :: Python :: 3.11", 20 | "Programming Language :: Python :: 3.12" 21 | ] 22 | requires-python = ">=3.6" 23 | 24 | dynamic = ["dependencies"] 25 | [tool.setuptools.dynamic] 26 | dependencies = {file = ["requirements.txt"]} 27 | 28 | [project.urls] 29 | "Home" = "https://github.com/casdoor/casdoor-python-sdk" 30 | 31 | [build-system] 32 | requires = ["setuptools", "wheel"] 33 | build-backend = "setuptools.build_meta" 34 | 35 | [tool.black] 36 | line-length = 120 37 | target-version = ["py36", "py37", "py38", "py39", "py310", "py311"] 38 | include = '\.pyi?$' 39 | 40 | [tool.ruff] 41 | line-length = 120 42 | 43 | [tool.ruff.lint] 44 | select = [ 45 | "E", # pycodestyle errors 46 | "W", # pycodestyle warnings 47 | "F", # pyflakes 48 | "I", # isort 49 | "C", # flake8-comprehensions 50 | "B", # flake8-bugbear 51 | ] 52 | 53 | # Allow autofix for all enabled rules (when `--fix`) is provided. 54 | fixable = ["I", "F"] 55 | unfixable = [] 56 | -------------------------------------------------------------------------------- /src/tests/test_resource.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.resource import Resource 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | ) 28 | 29 | 30 | class ResourceTest(unittest.TestCase): 31 | def test_resource(self): 32 | # upload_resource 33 | filename = "casbinTest.svg" 34 | script_dir = os.path.dirname(os.path.abspath(__file__)) 35 | file_path = os.path.join(script_dir, filename) 36 | with open(file_path, "rb") as file: 37 | data = file.read() 38 | name = f"/casdoor/{filename}" 39 | resource = Resource.new(owner="casbin", name=name) 40 | 41 | sdk = CasdoorSDK( 42 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 43 | ) 44 | 45 | response = sdk.upload_resource(resource.owner, name, "", filename, data) 46 | self.assertEqual("ok", response["status"]) 47 | 48 | # Delete the resource 49 | delete_resource = sdk.delete_resource(name) 50 | self.assertEqual("ok", delete_resource["status"]) 51 | # There is no get method 52 | # so there is no way to test the effect of deletion, only to assert the returned status code 53 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | .idea 132 | .pytest_cache 133 | 134 | # Vscode 135 | .vscode -------------------------------------------------------------------------------- /src/tests/test_util.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import random 16 | 17 | TestEndpoint = "https://demo.casdoor.com" 18 | TestClientId = "294b09fbc17f95daf2fe" 19 | TestClientSecret = "dd8982f7046ccba1bbd7851d5c1ece4e52bf039d" 20 | TestOrganization = "casbin" 21 | TestApplication = "app-vue-python-example" 22 | TestJwtPublicKey = """-----BEGIN CERTIFICATE----- 23 | MIIE+TCCAuGgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMDYxHTAbBgNVBAoTFENh 24 | c2Rvb3IgT3JnYW5pemF0aW9uMRUwEwYDVQQDEwxDYXNkb29yIENlcnQwHhcNMjEx 25 | MDE1MDgxMTUyWhcNNDExMDE1MDgxMTUyWjA2MR0wGwYDVQQKExRDYXNkb29yIE9y 26 | Z2FuaXphdGlvbjEVMBMGA1UEAxMMQ2FzZG9vciBDZXJ0MIICIjANBgkqhkiG9w0B 27 | AQEFAAOCAg8AMIICCgKCAgEAsInpb5E1/ym0f1RfSDSSE8IR7y+lw+RJjI74e5ej 28 | rq4b8zMYk7HeHCyZr/hmNEwEVXnhXu1P0mBeQ5ypp/QGo8vgEmjAETNmzkI1NjOQ 29 | CjCYwUrasO/f/MnI1C0j13vx6mV1kHZjSrKsMhYY1vaxTEP3+VB8Hjg3MHFWrb07 30 | uvFMCJe5W8+0rKErZCKTR8+9VB3janeBz//zQePFVh79bFZate/hLirPK0Go9P1g 31 | OvwIoC1A3sarHTP4Qm/LQRt0rHqZFybdySpyWAQvhNaDFE7mTstRSBb/wUjNCUBD 32 | PTSLVjC04WllSf6Nkfx0Z7KvmbPstSj+btvcqsvRAGtvdsB9h62Kptjs1Yn7GAuo 33 | I3qt/4zoKbiURYxkQJXIvwCQsEftUuk5ew5zuPSlDRLoLByQTLbx0JqLAFNfW3g/ 34 | pzSDjgd/60d6HTmvbZni4SmjdyFhXCDb1Kn7N+xTojnfaNkwep2REV+RMc0fx4Gu 35 | hRsnLsmkmUDeyIZ9aBL9oj11YEQfM2JZEq+RVtUx+wB4y8K/tD1bcY+IfnG5rBpw 36 | IDpS262boq4SRSvb3Z7bB0w4ZxvOfJ/1VLoRftjPbLIf0bhfr/AeZMHpIKOXvfz4 37 | yE+hqzi68wdF0VR9xYc/RbSAf7323OsjYnjjEgInUtRohnRgCpjIk/Mt2Kt84Kb0 38 | wn8CAwEAAaMQMA4wDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOCAgEAn2lf 39 | DKkLX+F1vKRO/5gJ+Plr8P5NKuQkmwH97b8CS2gS1phDyNgIc4/LSdzuf4Awe6ve 40 | C06lVdWSIis8UPUPdjmT2uMPSNjwLxG3QsrimMURNwFlLTfRem/heJe0Zgur9J1M 41 | 8haawdSdJjH2RgmFoDeE2r8NVRfhbR8KnCO1ddTJKuS1N0/irHz21W4jt4rxzCvl 42 | 2nR42Fybap3O/g2JXMhNNROwZmNjgpsF7XVENCSuFO1jTywLaqjuXCg54IL7XVLG 43 | omKNNNcc8h1FCeKj/nnbGMhodnFWKDTsJcbNmcOPNHo6ixzqMy/Hqc+mWYv7maAG 44 | Jtevs3qgMZ8F9Qzr3HpUc6R3ZYYWDY/xxPisuKftOPZgtH979XC4mdf0WPnOBLqL 45 | 2DJ1zaBmjiGJolvb7XNVKcUfDXYw85ZTZQ5b9clI4e+6bmyWqQItlwt+Ati/uFEV 46 | XzCj70B4lALX6xau1kLEpV9O1GERizYRz5P9NJNA7KoO5AVMp9w0DQTkt+LbXnZE 47 | HHnWKy8xHQKZF9sR7YBPGLs/Ac6tviv5Ua15OgJ/8dLRZ/veyFfGo2yZsI+hKVU5 48 | nCCJHBcAyFnm1hdvdwEdH33jDBjNB6ciotJZrf/3VYaIWSalADosHAgMWfXuWP+h 49 | 8XKXmzlxuHbTMQYtZPDgspS5aK+S4Q9wb8RRAYo= 50 | -----END CERTIFICATE-----""" 51 | 52 | 53 | def get_random_code(length): 54 | std_nums = "0123456789" 55 | result = "".join(random.choice(std_nums) for _ in range(length)) 56 | return result 57 | 58 | 59 | def get_random_name(prefix): 60 | return f"{prefix}_{get_random_code(6)}" 61 | -------------------------------------------------------------------------------- /src/tests/test_plan.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.plan import Plan 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class PlanTest(unittest.TestCase): 32 | def test_plan(self): 33 | name = get_random_name("Plan") 34 | 35 | # Add a new object 36 | plan = Plan.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="casbin", 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | try: 48 | sdk.add_plan(plan=plan) 49 | except Exception as e: 50 | self.fail(f"Failed to add object: {e}") 51 | 52 | # Get all objects, check if our added object is inside the list 53 | try: 54 | plans = sdk.get_plans() 55 | except Exception as e: 56 | self.fail(f"Failed to get objects: {e}") 57 | names = [item.name for item in plans] 58 | self.assertIn(name, names, "Added object not found in list") 59 | 60 | # Get the object 61 | try: 62 | plan = sdk.get_plan(name) 63 | except Exception as e: 64 | self.fail(f"Failed to get object: {e}") 65 | self.assertEqual(plan.name, name) 66 | 67 | # Update the object 68 | updated_description = "Updated Casdoor Website" 69 | plan.description = updated_description 70 | try: 71 | sdk.update_plan(plan) 72 | except Exception as e: 73 | self.fail(f"Failed to update object: {e}") 74 | 75 | # Validate the update 76 | try: 77 | updated_plan = sdk.get_plan(name) 78 | except Exception as e: 79 | self.fail(f"Failed to get updated object: {e}") 80 | self.assertEqual(updated_plan.description, updated_description) 81 | 82 | # Delete the object 83 | try: 84 | sdk.delete_plan(plan) 85 | except Exception as e: 86 | self.fail(f"Failed to delete object: {e}") 87 | 88 | # Validate the deletion 89 | try: 90 | deleted_plan = sdk.get_plan(name) 91 | except Exception as e: 92 | self.fail(f"Failed to get object: {e}") 93 | self.assertIsNone(deleted_plan, "Failed to delete object, it's still retrievable") 94 | -------------------------------------------------------------------------------- /src/tests/test_webhook.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.webhook import Webhook 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class WebhookTest(unittest.TestCase): 32 | def test_webhook(self): 33 | name = get_random_name("Webhook") 34 | 35 | # Add a new object 36 | webhook = Webhook.new( 37 | owner="casbin", name=name, created_time=datetime.datetime.now().isoformat(), organization="casbin" 38 | ) 39 | 40 | sdk = CasdoorSDK( 41 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 42 | ) 43 | try: 44 | sdk.add_webhook(webhook=webhook) 45 | except Exception as e: 46 | self.fail(f"Failed to add object: {e}") 47 | 48 | # Get all objects, check if our added object is inside the list 49 | try: 50 | webhooks = sdk.get_webhooks() 51 | except Exception as e: 52 | self.fail(f"Failed to get objects: {e}") 53 | names = [item.name for item in webhooks] 54 | self.assertIn(name, names, "Added object not found in list") 55 | 56 | # Get the object 57 | try: 58 | webhook = sdk.get_webhook(name) 59 | except Exception as e: 60 | self.fail(f"Failed to get object: {e}") 61 | self.assertEqual(webhook.name, name) 62 | 63 | # Update the object 64 | updated_organization = "Updated Casdoor Website" 65 | webhook.organization = updated_organization 66 | try: 67 | sdk.update_webhook(webhook) 68 | except Exception as e: 69 | self.fail(f"Failed to update object: {e}") 70 | 71 | # Validate the update 72 | try: 73 | updated_webhook = sdk.get_webhook(name) 74 | except Exception as e: 75 | self.fail(f"Failed to get updated object: {e}") 76 | self.assertEqual(updated_webhook.organization, updated_organization) 77 | 78 | # Delete the object 79 | try: 80 | sdk.delete_webhook(webhook) 81 | except Exception as e: 82 | self.fail(f"Failed to delete object: {e}") 83 | 84 | # Validate the deletion 85 | try: 86 | deleted_webhook = sdk.get_webhook(name) 87 | except Exception as e: 88 | self.fail(f"Failed to get object: {e}") 89 | self.assertIsNone(deleted_webhook, "Failed to delete object, it's still retrievable") 90 | -------------------------------------------------------------------------------- /src/tests/test_role.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.role import Role 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class RoleTest(unittest.TestCase): 32 | def test_role(self): 33 | name = get_random_name("Role") 34 | 35 | # Add a new object 36 | role = Role.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="Casdoor Website", 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | try: 48 | sdk.add_role(role=role) 49 | except Exception as e: 50 | self.fail(f"Failed to add object: {e}") 51 | 52 | # Get all objects, check if our added object is inside the list 53 | try: 54 | roles = sdk.get_roles() 55 | except Exception as e: 56 | self.fail(f"Failed to get objects: {e}") 57 | names = [item.name for item in roles] 58 | self.assertIn(name, names, "Added object not found in list") 59 | 60 | # Get the object 61 | try: 62 | role = sdk.get_role(name) 63 | except Exception as e: 64 | self.fail(f"Failed to get object: {e}") 65 | self.assertEqual(role.name, name) 66 | 67 | # Update the object 68 | updated_description = "Updated Casdoor Website" 69 | role.description = updated_description 70 | try: 71 | sdk.update_role(role) 72 | except Exception as e: 73 | self.fail(f"Failed to update object: {e}") 74 | 75 | # Validate the update 76 | try: 77 | updated_role = sdk.get_role(name) 78 | except Exception as e: 79 | self.fail(f"Failed to get updated object: {e}") 80 | self.assertEqual(updated_role.description, updated_description) 81 | 82 | # Delete the object 83 | try: 84 | sdk.delete_role(role) 85 | except Exception as e: 86 | self.fail(f"Failed to delete object: {e}") 87 | 88 | # Validate the deletion 89 | try: 90 | deleted_role = sdk.get_role(name) 91 | except Exception as e: 92 | self.fail(f"Failed to get object: {e}") 93 | self.assertIsNone(deleted_role, "Failed to delete object, it's still retrievable") 94 | -------------------------------------------------------------------------------- /src/tests/test_group.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.group import Group 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class GroupTest(unittest.TestCase): 32 | def test_group(self): 33 | name = get_random_name("group") 34 | 35 | # Add a new object 36 | group = Group.new(owner="admin", name=name, created_time=datetime.datetime.now().isoformat(), display_name=name) 37 | 38 | sdk = CasdoorSDK( 39 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 40 | ) 41 | 42 | try: 43 | sdk.add_group(group) 44 | except Exception as e: 45 | self.fail(f"Failed to add object: {e}") 46 | 47 | # Get all objects, check if our added object is inside the list 48 | try: 49 | groups = sdk.get_groups() 50 | except Exception as e: 51 | self.fail(f"Failed to get objects: {e}") 52 | names = [item.name for item in groups] 53 | self.assertIn(name, names, "Added object not found in list") 54 | 55 | # Get the object 56 | try: 57 | retrieved_group = sdk.get_group(name) 58 | except Exception as e: 59 | self.fail(f"Failed to get object: {e}") 60 | self.assertEqual(name, retrieved_group.name, "Retrieved object does not match added object") 61 | 62 | # Update the object 63 | updated_display_name = "updated_display_name" 64 | retrieved_group.displayName = updated_display_name 65 | try: 66 | updated_group = sdk.update_group(retrieved_group) 67 | except Exception as e: 68 | self.fail(f"Failed to update object: {e}") 69 | 70 | # Validate the update 71 | try: 72 | updated_group = sdk.get_group(name) 73 | except Exception as e: 74 | self.fail(f"Failed to get object: {e}") 75 | self.assertEqual( 76 | updated_display_name, updated_group.displayName, "Failed to update object, display_name mismatch" 77 | ) 78 | 79 | # Delete the object 80 | try: 81 | sdk.delete_group(group) 82 | except Exception as e: 83 | self.fail(f"Failed to delete object: {e}") 84 | 85 | # Validate the deletion 86 | try: 87 | deleted_group = sdk.get_group(name) 88 | except Exception as e: 89 | self.fail(f"Failed to get object: {e}") 90 | self.assertIsNone(deleted_group, "Failed to delete object, it's still retrievable") 91 | -------------------------------------------------------------------------------- /src/tests/test_payment.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.payment import Payment 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class PaymentTest(unittest.TestCase): 32 | def test_payment(self): 33 | name = get_random_name("Payment") 34 | 35 | # Add a new object 36 | payment = Payment.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | product_name="casbin", 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | try: 48 | sdk.add_payment(payment=payment) 49 | except Exception as e: 50 | self.fail(f"Failed to add object: {e}") 51 | 52 | # Get all objects, check if our added object is inside the list 53 | try: 54 | payments = sdk.get_payments() 55 | except Exception as e: 56 | self.fail(f"Failed to get objects: {e}") 57 | names = [item.name for item in payments] 58 | self.assertIn(name, names, "Added object not found in list") 59 | 60 | # Get the object 61 | try: 62 | payment = sdk.get_payment(name) 63 | except Exception as e: 64 | self.fail(f"Failed to get object: {e}") 65 | self.assertEqual(payment.name, name) 66 | 67 | # Update the object 68 | updated_product_name = "Updated Casdoor Website" 69 | payment.productName = updated_product_name 70 | try: 71 | sdk.update_payment(payment) 72 | except Exception as e: 73 | self.fail(f"Failed to update object: {e}") 74 | 75 | # Validate the update 76 | try: 77 | updated_payment = sdk.get_payment(name) 78 | except Exception as e: 79 | self.fail(f"Failed to get updated object: {e}") 80 | self.assertEqual(updated_payment.productName, updated_product_name) 81 | 82 | # Delete the object 83 | try: 84 | sdk.delete_payment(payment) 85 | except Exception as e: 86 | self.fail(f"Failed to delete object: {e}") 87 | 88 | # Validate the deletion 89 | try: 90 | deleted_payment = sdk.get_payment(name) 91 | except Exception as e: 92 | self.fail(f"Failed to get object: {e}") 93 | self.assertIsNone(deleted_payment, "Failed to delete object, it's still retrievable") 94 | -------------------------------------------------------------------------------- /src/tests/test_session.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.session import Session 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class sessionTest(unittest.TestCase): 32 | def test_session(self): 33 | name = get_random_name("Session") 34 | 35 | # Add a new object 36 | session = Session.new( 37 | owner="casbin", 38 | name=name, 39 | application="app-built-in", 40 | created_time=datetime.datetime.now().isoformat(), 41 | session_id=[], 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | try: 48 | sdk.add_session(session=session) 49 | except Exception as e: 50 | self.fail(f"Failed to add object: {e}") 51 | 52 | # Get all objects, check if our added object is inside the list 53 | try: 54 | sessions = sdk.get_sessions() 55 | except Exception as e: 56 | self.fail(f"Failed to get objects: {e}") 57 | names = [item.name for item in sessions] 58 | self.assertIn(name, names, "Added object not found in list") 59 | 60 | # Get the object 61 | try: 62 | session = sdk.get_session(name, session.application) 63 | except Exception as e: 64 | self.fail(f"Failed to get object: {e}") 65 | self.assertEqual(session.name, name) 66 | 67 | # Update the object 68 | updated_time = "Updated Casdoor Website" 69 | session.createdTime = updated_time 70 | try: 71 | sdk.update_session(session) 72 | except Exception as e: 73 | self.fail(f"Failed to update object: {e}") 74 | 75 | # Validate the update 76 | try: 77 | updated_session = sdk.get_session(name, session.application) 78 | except Exception as e: 79 | self.fail(f"Failed to get updated object: {e}") 80 | self.assertEqual(updated_session.createdTime, updated_time) 81 | 82 | # Delete the object 83 | try: 84 | sdk.delete_session(session) 85 | except Exception as e: 86 | self.fail(f"Failed to delete object: {e}") 87 | 88 | # Validate the deletion 89 | try: 90 | deleted_session = sdk.get_session(name, session.application) 91 | except Exception as e: 92 | self.fail(f"Failed to get object: {e}") 93 | self.assertIsNone(deleted_session, "Failed to delete object, it's still retrievable") 94 | -------------------------------------------------------------------------------- /src/tests/test_pricing.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.pricing import Pricing 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class pricingTest(unittest.TestCase): 32 | def test_pricing(self): 33 | name = get_random_name("Pricing") 34 | 35 | # Add a new object 36 | pricing = Pricing.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="app-admin", 42 | application="Casdoor Website", 43 | ) 44 | 45 | sdk = CasdoorSDK( 46 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 47 | ) 48 | try: 49 | sdk.add_pricing(pricing=pricing) 50 | except Exception as e: 51 | self.fail(f"Failed to add object: {e}") 52 | 53 | # Get all objects, check if our added object is inside the list 54 | try: 55 | pricings = sdk.get_pricings() 56 | except Exception as e: 57 | self.fail(f"Failed to get objects: {e}") 58 | names = [item.name for item in pricings] 59 | self.assertIn(name, names, "Added object not found in list") 60 | 61 | # Get the object 62 | try: 63 | pricing = sdk.get_pricing(name) 64 | except Exception as e: 65 | self.fail(f"Failed to get object: {e}") 66 | self.assertEqual(pricing.name, name) 67 | 68 | # Update the object 69 | updated_description = "Updated Casdoor Website" 70 | pricing.description = updated_description 71 | try: 72 | sdk.update_pricing(pricing) 73 | except Exception as e: 74 | self.fail(f"Failed to update object: {e}") 75 | 76 | # Validate the update 77 | try: 78 | updated_pricing = sdk.get_pricing(name) 79 | except Exception as e: 80 | self.fail(f"Failed to get updated object: {e}") 81 | self.assertEqual(updated_pricing.description, updated_description) 82 | 83 | # Delete the object 84 | try: 85 | sdk.delete_pricing(pricing) 86 | except Exception as e: 87 | self.fail(f"Failed to delete object: {e}") 88 | 89 | # Validate the deletion 90 | try: 91 | deleted_pricing = sdk.get_pricing(name) 92 | except Exception as e: 93 | self.fail(f"Failed to get object: {e}") 94 | self.assertIsNone(deleted_pricing, "Failed to delete object, it's still retrievable") 95 | -------------------------------------------------------------------------------- /src/tests/test_provider.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.provider import Provider 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class ProviderTest(unittest.TestCase): 32 | def test_provider(self): 33 | name = get_random_name("Provider") 34 | 35 | # Add a new object 36 | provider = Provider.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | category="Captcha", 42 | type="Default", 43 | ) 44 | 45 | sdk = CasdoorSDK( 46 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 47 | ) 48 | try: 49 | sdk.add_provider(provider=provider) 50 | except Exception as e: 51 | self.fail(f"Failed to add object: {e}") 52 | 53 | # Get all objects, check if our added object is inside the list 54 | try: 55 | providers = sdk.get_providers() 56 | except Exception as e: 57 | self.fail(f"Failed to get objects: {e}") 58 | names = [item.name for item in providers] 59 | self.assertIn(name, names, "Added object not found in list") 60 | 61 | # Get the object 62 | try: 63 | provider = sdk.get_provider(name) 64 | except Exception as e: 65 | self.fail(f"Failed to get object: {e}") 66 | self.assertEqual(provider.name, name) 67 | 68 | # Update the object 69 | updated_display_name = "Updated Casdoor Website" 70 | provider.displayName = updated_display_name 71 | try: 72 | sdk.update_provider(provider) 73 | except Exception as e: 74 | self.fail(f"Failed to update object: {e}") 75 | 76 | # Validate the update 77 | try: 78 | updated_provider = sdk.get_provider(name) 79 | except Exception as e: 80 | self.fail(f"Failed to get updated object: {e}") 81 | self.assertEqual(updated_provider.displayName, updated_display_name) 82 | 83 | # Delete the object 84 | try: 85 | sdk.delete_provider(provider) 86 | except Exception as e: 87 | self.fail(f"Failed to delete object: {e}") 88 | 89 | # Validate the deletion 90 | try: 91 | deleted_provider = sdk.get_provider(name) 92 | except Exception as e: 93 | self.fail(f"Failed to get object: {e}") 94 | self.assertIsNone(deleted_provider, "Failed to delete object, it's still retrievable") 95 | -------------------------------------------------------------------------------- /src/tests/test_adapter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.adapter import Adapter 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class AdapterTest(unittest.TestCase): 32 | def test_adapter(self): 33 | name = get_random_name("Adapter") 34 | 35 | # Add a new object 36 | adapter = Adapter.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | host=name, 41 | user="https://casdoor.org", 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | 48 | try: 49 | sdk.add_adapter(adapter=adapter) 50 | except Exception as e: 51 | self.fail("Failed to add object: " + str(e)) 52 | 53 | # Get all objects, check if our added object is inside the list 54 | try: 55 | adapters = sdk.get_adapters() 56 | except Exception as e: 57 | self.fail("Failed to get objects: " + str(e)) 58 | names = [item.name for item in adapters] 59 | self.assertIn(name, names, "Added object not found in list") 60 | 61 | # Get the object 62 | try: 63 | adapter = sdk.get_adapter(name) 64 | except Exception as e: 65 | self.fail("Failed to get object: " + str(e)) 66 | 67 | self.assertEqual(adapter.name, name, "Retrieved object does not match added object") 68 | 69 | # Update the object 70 | updated_user = "Updated Casdoor Website" 71 | adapter.user = updated_user 72 | try: 73 | sdk.update_adapter(adapter) 74 | except Exception as e: 75 | self.fail("Failed to update object: " + str(e)) 76 | 77 | # Validate the update 78 | try: 79 | updated_adapter = sdk.get_adapter(name) 80 | except Exception as e: 81 | self.fail("Failed to get updated object: " + str(e)) 82 | 83 | self.assertEqual(updated_adapter.user, updated_user, "Failed to update object, display_name mismatch") 84 | 85 | # Delete the object 86 | try: 87 | sdk.delete_adapter(adapter) 88 | except Exception as e: 89 | self.fail("Failed to delete object: " + str(e)) 90 | 91 | # Validate the deletion 92 | try: 93 | deleted_adapter = sdk.get_adapter(name) 94 | except Exception as e: 95 | self.fail("Failed to delete object: " + str(e)) 96 | 97 | self.assertIsNone(deleted_adapter, "Failed to delete object, it's still retrievable") 98 | -------------------------------------------------------------------------------- /src/tests/test_enforcer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.enforcer import Enforcer 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class EnforcerTest(unittest.TestCase): 32 | def test_enforcer(self): 33 | name = get_random_name("Enforcer") 34 | 35 | # Add a new object 36 | enforcer = Enforcer.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="built-in/user-model-built-in", 42 | model="built-in/user-adapter-built-in", 43 | adapter="Casdoor Website", 44 | ) 45 | 46 | sdk = CasdoorSDK( 47 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 48 | ) 49 | try: 50 | sdk.add_enforcer(enforcer=enforcer) 51 | except Exception as e: 52 | self.fail(f"Failed to add object: {e}") 53 | 54 | # Get all objects, check if our added object is inside the list 55 | try: 56 | enforcers = sdk.get_enforcers() 57 | except Exception as e: 58 | self.fail(f"Failed to get objects: {e}") 59 | names = [item.name for item in enforcers] 60 | self.assertIn(name, names, "Added object not found in list") 61 | 62 | # Get the object 63 | try: 64 | enforcer = sdk.get_enforcer(name) 65 | except Exception as e: 66 | self.fail(f"Failed to get object: {e}") 67 | self.assertEqual(enforcer.name, name) 68 | 69 | # Update the object 70 | updated_description = "Updated Casdoor Website" 71 | enforcer.description = updated_description 72 | try: 73 | sdk.update_enforcer(enforcer) 74 | except Exception as e: 75 | self.fail(f"Failed to update object: {e}") 76 | 77 | # Validate the update 78 | try: 79 | updated_enforcer = sdk.get_enforcer(name) 80 | except Exception as e: 81 | self.fail(f"Failed to get updated object: {e}") 82 | self.assertEqual(updated_enforcer.description, updated_description) 83 | 84 | # Delete the object 85 | try: 86 | sdk.delete_enforcer(enforcer) 87 | except Exception as e: 88 | self.fail(f"Failed to delete object: {e}") 89 | 90 | # Validate the deletion 91 | try: 92 | deleted_enforcer = sdk.get_enforcer(name) 93 | except Exception as e: 94 | self.fail(f"Failed to get object: {e}") 95 | self.assertIsNone(deleted_enforcer, "Failed to delete object, it's still retrievable") 96 | -------------------------------------------------------------------------------- /src/tests/test_subscription.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.subscription import Subscription 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class SubscriptionTest(unittest.TestCase): 32 | def test_subscription(self): 33 | name = get_random_name("Subscription") 34 | 35 | # Add a new object 36 | subscription = Subscription.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="Casdoor Website", 42 | ) 43 | 44 | sdk = CasdoorSDK( 45 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 46 | ) 47 | try: 48 | sdk.add_subscription(subscription=subscription) 49 | except Exception as e: 50 | self.fail(f"Failed to add object: {e}") 51 | 52 | # Get all objects, check if our added object is inside the list 53 | try: 54 | subscriptions = sdk.get_subscriptions() 55 | except Exception as e: 56 | self.fail(f"Failed to get objects: {e}") 57 | names = [item.name for item in subscriptions] 58 | self.assertIn(name, names, "Added object not found in list") 59 | 60 | # Get the object 61 | try: 62 | subscription = sdk.get_subscription(name) 63 | except Exception as e: 64 | self.fail(f"Failed to get object: {e}") 65 | self.assertEqual(subscription.name, name) 66 | 67 | # Update the object 68 | updated_description = "Updated Casdoor Website" 69 | subscription.description = updated_description 70 | try: 71 | sdk.update_subscription(subscription) 72 | except Exception as e: 73 | self.fail(f"Failed to update object: {e}") 74 | 75 | # Validate the update 76 | try: 77 | updated_subscription = sdk.get_subscription(name) 78 | except Exception as e: 79 | self.fail(f"Failed to get updated object: {e}") 80 | self.assertEqual(updated_subscription.description, updated_description) 81 | 82 | # Delete the object 83 | try: 84 | sdk.delete_subscription(subscription) 85 | except Exception as e: 86 | self.fail(f"Failed to delete object: {e}") 87 | 88 | # Validate the deletion 89 | try: 90 | deleted_subscription = sdk.get_subscription(name) 91 | except Exception as e: 92 | self.fail(f"Failed to get object: {e}") 93 | self.assertIsNone(deleted_subscription, "Failed to delete object, it's still retrievable") 94 | -------------------------------------------------------------------------------- /src/tests/test_product.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.product import Product 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class ProductTest(unittest.TestCase): 32 | def test_product(self): 33 | name = get_random_name("Product") 34 | 35 | # Add a new object 36 | product = Product.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | image="https://cdn.casbin.org/img/casdoor-logo_1185x256.png", 42 | description="Casdoor Website", 43 | tag="auto_created_product_for_plan", 44 | quantity=999, 45 | sold=0, 46 | state="Published", 47 | ) 48 | 49 | sdk = CasdoorSDK( 50 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 51 | ) 52 | try: 53 | sdk.add_product(product=product) 54 | except Exception as e: 55 | self.fail(f"Failed to add object: {e}") 56 | 57 | # Get all objects, check if our added object is inside the list 58 | try: 59 | products = sdk.get_products() 60 | except Exception as e: 61 | self.fail(f"Failed to get objects: {e}") 62 | names = [item.name for item in products] 63 | self.assertIn(name, names, "Added object not found in list") 64 | 65 | # Get the object 66 | try: 67 | product = sdk.get_product(name) 68 | except Exception as e: 69 | self.fail(f"Failed to get object: {e}") 70 | self.assertEqual(product.name, name) 71 | 72 | # Update the object 73 | updated_description = "Updated Casdoor Website" 74 | product.description = updated_description 75 | try: 76 | sdk.update_product(product) 77 | except Exception as e: 78 | self.fail(f"Failed to update object: {e}") 79 | 80 | # Validate the update 81 | try: 82 | updated_product = sdk.get_product(name) 83 | except Exception as e: 84 | self.fail(f"Failed to get updated object: {e}") 85 | self.assertEqual(updated_product.description, updated_description) 86 | 87 | # Delete the object 88 | try: 89 | sdk.delete_product(product) 90 | except Exception as e: 91 | self.fail(f"Failed to delete object: {e}") 92 | 93 | # Validate the deletion 94 | try: 95 | deleted_product = sdk.get_product(name) 96 | except Exception as e: 97 | self.fail(f"Failed to get object: {e}") 98 | self.assertIsNone(deleted_product, "Failed to delete object, it's still retrievable") 99 | -------------------------------------------------------------------------------- /src/tests/test_syncer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.syncer import Syncer 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class SyncerTest(unittest.TestCase): 32 | def test_syncer(self): 33 | name = get_random_name("Syncer") 34 | 35 | # Add a new object 36 | syncer = Syncer.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | organization="casbin", 41 | host="localhost", 42 | port=3306, 43 | user="root", 44 | password="123", 45 | database_type="mysql", 46 | database="syncer_db", 47 | table="user-table", 48 | sync_interval=1, 49 | ) 50 | 51 | sdk = CasdoorSDK( 52 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 53 | ) 54 | try: 55 | sdk.add_syncer(syncer=syncer) 56 | except Exception as e: 57 | self.fail(f"Failed to add object: {e}") 58 | 59 | # Get all objects, check if our added object is inside the list 60 | try: 61 | syncers = sdk.get_syncers() 62 | except Exception as e: 63 | self.fail(f"Failed to get objects: {e}") 64 | names = [item.name for item in syncers] 65 | self.assertIn(name, names, "Added object not found in list") 66 | 67 | # Get the object 68 | try: 69 | syncer = sdk.get_syncer(name) 70 | except Exception as e: 71 | self.fail(f"Failed to get object: {e}") 72 | self.assertEqual(syncer.name, name) 73 | 74 | # Update the object 75 | updated_host = "Updated Host" 76 | syncer.host = updated_host 77 | try: 78 | sdk.update_syncer(syncer) 79 | except Exception as e: 80 | self.fail(f"Failed to update object: {e}") 81 | 82 | # Validate the update 83 | try: 84 | updated_syncer = sdk.get_syncer(name) 85 | except Exception as e: 86 | self.fail(f"Failed to get updated object: {e}") 87 | self.assertEqual(updated_syncer.host, updated_host) 88 | 89 | # Delete the object 90 | try: 91 | sdk.delete_syncer(syncer) 92 | except Exception as e: 93 | self.fail(f"Failed to delete object: {e}") 94 | 95 | # Validate the deletion 96 | try: 97 | deleted_syncer = sdk.get_syncer(name) 98 | except Exception as e: 99 | self.fail(f"Failed to get object: {e}") 100 | self.assertIsNone(deleted_syncer, "Failed to delete object, it's still retrievable") 101 | -------------------------------------------------------------------------------- /src/tests/test_application.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.application import Application 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class ApplicationTest(unittest.TestCase): 32 | def test_application(self): 33 | name = get_random_name("application") 34 | 35 | # Add a new object 36 | application = Application.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | logo="https://cdn.casbin.org/img/casdoor-logo_1185x256.png", 42 | homepage_url="https://casdoor.org", 43 | description="Casdoor Website", 44 | organization="casbin", 45 | ) 46 | 47 | sdk = CasdoorSDK( 48 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 49 | ) 50 | try: 51 | sdk.add_application(application=application) 52 | except Exception as e: 53 | self.fail(f"Failed to add object: {e}") 54 | 55 | # Get all objects, check if our added object is inside the list 56 | try: 57 | applications = sdk.get_applications() 58 | except Exception as e: 59 | self.fail(f"Failed to get objects: {e}") 60 | names = [item.name for item in applications] 61 | self.assertIn(name, names, "Added object not found in list") 62 | 63 | # Get the object 64 | try: 65 | application = sdk.get_application(name) 66 | except Exception as e: 67 | self.fail(f"Failed to get object: {e}") 68 | self.assertEqual(application.name, name) 69 | 70 | # Update the object 71 | updated_description = "Updated Casdoor Website" 72 | application.description = updated_description 73 | try: 74 | sdk.update_application(application) 75 | except Exception as e: 76 | self.fail(f"Failed to update object: {e}") 77 | 78 | # Validate the update 79 | try: 80 | updated_application = sdk.get_application(name) 81 | except Exception as e: 82 | self.fail(f"Failed to get updated object: {e}") 83 | self.assertEqual(updated_application.description, updated_description) 84 | 85 | # Delete the object 86 | try: 87 | sdk.delete_application(application) 88 | except Exception as e: 89 | self.fail(f"Failed to delete object: {e}") 90 | 91 | # Validate the deletion 92 | try: 93 | deleted_application = sdk.get_application(name) 94 | except Exception as e: 95 | self.fail(f"Failed to get object: {e}") 96 | self.assertIsNone(deleted_application, "Failed to delete object, it's still retrievable") 97 | -------------------------------------------------------------------------------- /src/tests/test_cert.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.cert import Cert 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class CertTest(unittest.TestCase): 32 | def test_cert(self): 33 | name = get_random_name("Cert") 34 | 35 | # Add a new object 36 | cert = Cert.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | scope="JWT", 42 | type="x509", 43 | crypto_algorithm="RS256", 44 | bit_size=4096, 45 | expire_in_years=20, 46 | ) 47 | 48 | sdk = CasdoorSDK( 49 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 50 | ) 51 | 52 | try: 53 | sdk.add_cert(cert=cert) 54 | except Exception as e: 55 | self.fail("Failed to add object: " + str(e)) 56 | 57 | # Get all objects, check if our added object is inside the list 58 | try: 59 | certs = sdk.get_certs() 60 | except Exception as e: 61 | self.fail("Failed to get objects: " + str(e)) 62 | names = [item.name for item in certs] 63 | self.assertIn(name, names, "Added object not found in list") 64 | 65 | # Get the object 66 | try: 67 | cert = sdk.get_cert(name) 68 | except Exception as e: 69 | self.fail("Failed to get object: " + str(e)) 70 | 71 | self.assertEqual(cert.name, name, "Retrieved object does not match added object") 72 | 73 | # Update the object 74 | updated_display_name = "Updated Casdoor Website" 75 | cert.displayName = updated_display_name 76 | try: 77 | sdk.update_cert(cert) 78 | except Exception as e: 79 | self.fail("Failed to update object: " + str(e)) 80 | 81 | # Validate the update 82 | try: 83 | updated_cert = sdk.get_cert(name) 84 | except Exception as e: 85 | self.fail("Failed to get updated object: " + str(e)) 86 | 87 | self.assertEqual( 88 | updated_cert.displayName, updated_display_name, "Failed to update object, display_name mismatch" 89 | ) 90 | 91 | # Delete the object 92 | try: 93 | sdk.delete_cert(cert) 94 | except Exception as e: 95 | self.fail("Failed to delete object: " + str(e)) 96 | 97 | # Validate the deletion 98 | try: 99 | deleted_cert = sdk.get_cert(name) 100 | except Exception as e: 101 | self.fail("Failed to delete object: " + str(e)) 102 | 103 | self.assertIsNone(deleted_cert, "Failed to delete object, it's still retrievable") 104 | -------------------------------------------------------------------------------- /src/tests/test_permission.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.permission import Permission 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class permissionTest(unittest.TestCase): 32 | def test_permission(self): 33 | name = get_random_name("Permission") 34 | 35 | # Add a new object 36 | permission = Permission.new( 37 | owner="casbin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | description="Casdoor Website", 42 | users=["casbin/*"], 43 | roles=[], 44 | domains=[], 45 | model="user-model-built-in", 46 | resource_type="Application", 47 | resources=["app-casbin"], 48 | actions=["Read", "Write"], 49 | effect="Allow", 50 | is_enabled=True, 51 | ) 52 | 53 | sdk = CasdoorSDK( 54 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 55 | ) 56 | try: 57 | sdk.add_permission(permission=permission) 58 | except Exception as e: 59 | self.fail(f"Failed to add object: {e}") 60 | 61 | # Get all objects, check if our added object is inside the list 62 | try: 63 | permissions = sdk.get_permissions() 64 | except Exception as e: 65 | self.fail(f"Failed to get objects: {e}") 66 | names = [item.name for item in permissions] 67 | self.assertIn(name, names, "Added object not found in list") 68 | 69 | # Get the object 70 | try: 71 | permission = sdk.get_permission(name) 72 | except Exception as e: 73 | self.fail(f"Failed to get object: {e}") 74 | self.assertEqual(permission.name, name) 75 | 76 | # Update the object 77 | updated_description = "Updated Casdoor Website" 78 | permission.description = updated_description 79 | try: 80 | sdk.update_permission(permission) 81 | except Exception as e: 82 | self.fail(f"Failed to update object: {e}") 83 | 84 | # Validate the update 85 | try: 86 | updated_permission = sdk.get_permission(name) 87 | except Exception as e: 88 | self.fail(f"Failed to get updated object: {e}") 89 | self.assertEqual(updated_permission.description, updated_description) 90 | 91 | # Delete the object 92 | try: 93 | sdk.delete_permission(permission) 94 | except Exception as e: 95 | self.fail(f"Failed to delete object: {e}") 96 | 97 | # Validate the deletion 98 | try: 99 | deleted_permission = sdk.get_permission(name) 100 | except Exception as e: 101 | self.fail(f"Failed to get object: {e}") 102 | self.assertIsNone(deleted_permission, "Failed to delete object, it's still retrievable") 103 | -------------------------------------------------------------------------------- /src/tests/test_model.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.model import Model 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class ModelTest(unittest.TestCase): 32 | def test_model(self): 33 | name = get_random_name("model") 34 | 35 | # Add a new object 36 | model = Model.new( 37 | owner="casbin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | model_text="[request_definition]\n" 42 | + "r = sub, obj, act\n" 43 | + "\n" 44 | + "[policy_definition]\n" 45 | + "p = sub, obj, act\n" 46 | + "\n" 47 | + "[role_definition]\n" 48 | + "g = _, _\n" 49 | + "\n" 50 | + "[policy_effect]\n" 51 | + "e = some(where (p.eft == allow))\n" 52 | + "\n" 53 | + "[matchers]\n" 54 | + "m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act", 55 | ) 56 | 57 | sdk = CasdoorSDK( 58 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 59 | ) 60 | try: 61 | sdk.add_model(model=model) 62 | except Exception as e: 63 | self.fail(f"Failed to add object: {e}") 64 | 65 | # Get all objects, check if our added object is inside the list 66 | try: 67 | models = sdk.get_models() 68 | except Exception as e: 69 | self.fail(f"Failed to get objects: {e}") 70 | names = [item.name for item in models] 71 | self.assertIn(name, names, "Added object not found in list") 72 | 73 | # Get the object 74 | try: 75 | model = sdk.get_model(name) 76 | except Exception as e: 77 | self.fail(f"Failed to get object: {e}") 78 | self.assertEqual(model.name, name) 79 | 80 | # Update the object 81 | updated_display_name = "Updated Casdoor Website" 82 | model.displayName = updated_display_name 83 | try: 84 | sdk.update_model(model) 85 | except Exception as e: 86 | self.fail(f"Failed to update object: {e}") 87 | 88 | # Validate the update 89 | try: 90 | updated_model = sdk.get_model(name) 91 | except Exception as e: 92 | self.fail(f"Failed to get updated object: {e}") 93 | self.assertEqual(updated_model.displayName, updated_display_name) 94 | 95 | # Delete the object 96 | try: 97 | sdk.delete_model(model) 98 | except Exception as e: 99 | self.fail(f"Failed to delete object: {e}") 100 | 101 | # Validate the deletion 102 | try: 103 | deleted_model = sdk.get_model(name) 104 | except Exception as e: 105 | self.fail(f"Failed to get object: {e}") 106 | self.assertIsNone(deleted_model, "Failed to delete object, it's still retrievable") 107 | -------------------------------------------------------------------------------- /src/tests/test_organization.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | from src.casdoor import CasdoorSDK 19 | from src.casdoor.organization import Organization 20 | from src.tests.test_util import ( 21 | TestApplication, 22 | TestClientId, 23 | TestClientSecret, 24 | TestEndpoint, 25 | TestJwtPublicKey, 26 | TestOrganization, 27 | get_random_name, 28 | ) 29 | 30 | 31 | class OrganizationTest(unittest.TestCase): 32 | def test_organization(self): 33 | name = get_random_name("Organization") 34 | 35 | # Add a new object 36 | organization = Organization.new( 37 | owner="admin", 38 | name=name, 39 | created_time=datetime.datetime.now().isoformat(), 40 | display_name=name, 41 | website_url="https://example.com", 42 | password_type="plain", 43 | password_options=["AtLeast6"], 44 | country_codes=["US", "ES", "FR", "DE", "GB", "CN", "JP", "KR", "VN", "ID", "SG", "IN"], 45 | tags=[], 46 | languages=["en", "zh", "es", "fr", "de", "id", "ja", "ko", "ru", "vi", "pt"], 47 | init_score=2000, 48 | enable_soft_deletion=False, 49 | is_profile_public=False, 50 | ) 51 | 52 | sdk = CasdoorSDK( 53 | TestEndpoint, TestClientId, TestClientSecret, TestJwtPublicKey, TestOrganization, TestApplication 54 | ) 55 | 56 | try: 57 | sdk.add_organization(organization) 58 | except Exception as e: 59 | self.fail(f"Failed to add object: {e}") 60 | 61 | # Get all objects, check if our added object is inside the list 62 | # try: 63 | # organizations = sdk.get_organizations() 64 | # except Exception as e: 65 | # self.fail(f"Failed to get objects: {e}") 66 | # names = [item.name for item in organizations] 67 | # self.assertIn(name, names, "Added object not found in list") 68 | 69 | # Get the object 70 | try: 71 | organization = sdk.get_organization(name) 72 | except Exception as e: 73 | self.fail(f"Failed to get object: {e}") 74 | self.assertEqual(organization.name, name) 75 | 76 | # Update the object 77 | updated_display_name = "Updated Casdoor Website" 78 | organization.displayName = updated_display_name 79 | try: 80 | sdk.update_organization(organization) 81 | except Exception as e: 82 | self.fail(f"Failed to update object: {e}") 83 | 84 | # Validate the update 85 | try: 86 | updated_organization = sdk.get_organization(name) 87 | except Exception as e: 88 | self.fail(f"Failed to get object: {e}") 89 | self.assertEqual(updated_organization.displayName, updated_display_name) 90 | 91 | # Delete the object 92 | sdk.delete_organization(organization) 93 | 94 | # Validate the deletion 95 | try: 96 | deleted_organization = sdk.get_organization(name) 97 | except Exception as e: 98 | self.fail(f"Failed to get object: {e}") 99 | self.assertIsNone(deleted_organization, "Failed to delete object, it's still retrievable") 100 | -------------------------------------------------------------------------------- /src/casdoor/plan.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Plan: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.description = "" 28 | self.pricePerMonth = 0.0 29 | self.pricePerYear = 0.0 30 | self.currency = "" 31 | self.isEnabled = False 32 | self.role = "" 33 | self.options = [""] 34 | 35 | @classmethod 36 | def new(cls, owner, name, created_time, display_name, description): 37 | self = cls() 38 | self.owner = owner 39 | self.name = name 40 | self.createdTime = created_time 41 | self.displayName = display_name 42 | self.description = description 43 | return self 44 | 45 | @classmethod 46 | def from_dict(cls, data: dict): 47 | if data is None: 48 | return None 49 | 50 | plan = cls() 51 | for key, value in data.items(): 52 | if hasattr(plan, key): 53 | setattr(plan, key, value) 54 | return plan 55 | 56 | def __str__(self): 57 | return str(self.__dict__) 58 | 59 | def to_dict(self) -> dict: 60 | return self.__dict__ 61 | 62 | 63 | class _PlanSDK: 64 | def get_plans(self) -> List[Dict]: 65 | """ 66 | Get the plans from Casdoor. 67 | 68 | :return: a list of dicts containing plan info 69 | """ 70 | url = self.endpoint + "/api/get-plans" 71 | params = { 72 | "owner": self.org_name, 73 | "clientId": self.client_id, 74 | "clientSecret": self.client_secret, 75 | } 76 | r = requests.get(url, params) 77 | response = r.json() 78 | if response["status"] != "ok": 79 | raise Exception(response["msg"]) 80 | plans = [] 81 | for plan in response["data"]: 82 | plans.append(Plan.from_dict(plan)) 83 | return plans 84 | 85 | def get_plan(self, plan_id: str) -> Dict: 86 | """ 87 | Get the plan from Casdoor providing the plan_id. 88 | 89 | :param plan_id: the id of the plan 90 | :return: a dict that contains plan's info 91 | """ 92 | url = self.endpoint + "/api/get-plan" 93 | params = { 94 | "id": f"{self.org_name}/{plan_id}", 95 | "clientId": self.client_id, 96 | "clientSecret": self.client_secret, 97 | } 98 | r = requests.get(url, params) 99 | response = r.json() 100 | if response["status"] != "ok": 101 | raise Exception(response["msg"]) 102 | 103 | return Plan.from_dict(response["data"]) 104 | 105 | def modify_plan(self, method: str, plan: Plan) -> Dict: 106 | url = self.endpoint + f"/api/{method}" 107 | plan.owner = self.org_name 108 | params = { 109 | "id": f"{plan.owner}/{plan.name}", 110 | "clientId": self.client_id, 111 | "clientSecret": self.client_secret, 112 | } 113 | plan_info = json.dumps(plan.to_dict()) 114 | r = requests.post(url, params=params, data=plan_info) 115 | response = r.json() 116 | if response["status"] != "ok": 117 | raise Exception(response["msg"]) 118 | return response 119 | 120 | def add_plan(self, plan: Plan) -> Dict: 121 | response = self.modify_plan("add-plan", plan) 122 | return response 123 | 124 | def update_plan(self, plan: Plan) -> Dict: 125 | response = self.modify_plan("update-plan", plan) 126 | return response 127 | 128 | def delete_plan(self, plan: Plan) -> Dict: 129 | response = self.modify_plan("delete-plan", plan) 130 | return response 131 | -------------------------------------------------------------------------------- /src/casdoor/session.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Session: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.application = "" 26 | self.createdTime = "" 27 | self.sessionId = [""] 28 | 29 | @classmethod 30 | def new(cls, owner, name, application, created_time, session_id): 31 | self = cls() 32 | self.owner = owner 33 | self.name = name 34 | self.application = application 35 | self.createdTime = created_time 36 | self.sessionId = session_id 37 | return self 38 | 39 | @classmethod 40 | def from_dict(cls, data: dict): 41 | if data is None: 42 | return None 43 | session = cls() 44 | for key, value in data.items(): 45 | if hasattr(session, key): 46 | setattr(session, key, value) 47 | return session 48 | 49 | def __str__(self): 50 | return str(self.__dict__) 51 | 52 | def to_dict(self) -> dict: 53 | return self.__dict__ 54 | 55 | 56 | class _SessionSDK: 57 | def get_sessions(self) -> List[Dict]: 58 | """ 59 | Get the sessions from Casdoor. 60 | 61 | :return: a list of dicts containing session info 62 | """ 63 | url = self.endpoint + "/api/get-sessions" 64 | params = { 65 | "owner": self.org_name, 66 | "clientId": self.client_id, 67 | "clientSecret": self.client_secret, 68 | } 69 | r = requests.get(url, params) 70 | response = r.json() 71 | if response["status"] != "ok": 72 | raise Exception(response["msg"]) 73 | sessions = [] 74 | for session in response["data"]: 75 | sessions.append(Session.from_dict(session)) 76 | return sessions 77 | 78 | def get_session(self, session_id: str, application: str) -> Dict: 79 | """ 80 | Get the session from Casdoor providing the session_id. 81 | 82 | :param session_id: the id of the session 83 | :return: a dict that contains session's info 84 | """ 85 | url = self.endpoint + "/api/get-session" 86 | params = { 87 | "id": f"{self.org_name}/{session_id}", 88 | "clientId": self.client_id, 89 | "clientSecret": self.client_secret, 90 | "sessionPkId": f"{self.org_name}/{session_id}/{application}", 91 | } 92 | r = requests.get(url, params) 93 | response = r.json() 94 | if response["status"] != "ok": 95 | raise Exception(response["msg"]) 96 | return Session.from_dict(response["data"]) 97 | 98 | def modify_session(self, method: str, session: Session) -> Dict: 99 | url = self.endpoint + f"/api/{method}" 100 | session.owner = self.org_name 101 | params = { 102 | "id": f"{session.owner}/{session.name}", 103 | "clientId": self.client_id, 104 | "clientSecret": self.client_secret, 105 | } 106 | session_info = json.dumps(session.to_dict()) 107 | r = requests.post(url, params=params, data=session_info) 108 | response = r.json() 109 | if response["status"] != "ok": 110 | raise Exception(response["msg"]) 111 | return response 112 | 113 | def add_session(self, session: Session) -> Dict: 114 | response = self.modify_session("add-session", session) 115 | return response 116 | 117 | def update_session(self, session: Session) -> Dict: 118 | response = self.modify_session("update-session", session) 119 | return response 120 | 121 | def delete_session(self, session: Session) -> Dict: 122 | response = self.modify_session("delete-session", session) 123 | return response 124 | -------------------------------------------------------------------------------- /src/casdoor/enforcer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Enforcer: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.updatedTime = "" 27 | self.displayName = "" 28 | self.description = "" 29 | self.model = "" 30 | self.adapter = "" 31 | self.isEnabled = False 32 | 33 | @classmethod 34 | def new(cls, owner, name, created_time, display_name, description, model, adapter): 35 | self = cls() 36 | self.owner = owner 37 | self.name = name 38 | self.createdTime = created_time 39 | self.displayName = display_name 40 | self.description = description 41 | self.model = model 42 | self.adapter = adapter 43 | return self 44 | 45 | @classmethod 46 | def from_dict(cls, data: dict): 47 | if data is None: 48 | return None 49 | 50 | enforcer = cls() 51 | for key, value in data.items(): 52 | if hasattr(enforcer, key): 53 | setattr(enforcer, key, value) 54 | return enforcer 55 | 56 | def __str__(self): 57 | return str(self.__dict__) 58 | 59 | def to_dict(self) -> dict: 60 | return self.__dict__ 61 | 62 | 63 | class _EnforcerSDK: 64 | def get_enforcers(self) -> List[Dict]: 65 | """ 66 | Get the enforcers from Casdoor. 67 | 68 | :return: a list of dicts containing enforcer info 69 | """ 70 | url = self.endpoint + "/api/get-enforcers" 71 | params = { 72 | "owner": self.org_name, 73 | "clientId": self.client_id, 74 | "clientSecret": self.client_secret, 75 | } 76 | r = requests.get(url, params) 77 | response = r.json() 78 | if response["status"] != "ok": 79 | raise Exception(response["msg"]) 80 | enforcers = [] 81 | for enforcer in response["data"]: 82 | enforcers.append(Enforcer.from_dict(enforcer)) 83 | return enforcers 84 | 85 | def get_enforcer(self, enforcer_id: str) -> Dict: 86 | """ 87 | Get the enforcer from Casdoor providing the enforcer_id. 88 | 89 | :param enforcer_id: the id of the enforcer 90 | :return: a dict that contains enforcer's info 91 | """ 92 | url = self.endpoint + "/api/get-enforcer" 93 | params = { 94 | "id": f"{self.org_name}/{enforcer_id}", 95 | "clientId": self.client_id, 96 | "clientSecret": self.client_secret, 97 | } 98 | r = requests.get(url, params) 99 | response = r.json() 100 | if response["status"] != "ok": 101 | raise Exception(response["msg"]) 102 | 103 | return Enforcer.from_dict(response["data"]) 104 | 105 | def modify_enforcer(self, method: str, enforcer: Enforcer) -> Dict: 106 | url = self.endpoint + f"/api/{method}" 107 | enforcer.owner = self.org_name 108 | params = { 109 | "id": f"{enforcer.owner}/{enforcer.name}", 110 | "clientId": self.client_id, 111 | "clientSecret": self.client_secret, 112 | } 113 | enforcer_info = json.dumps(enforcer.to_dict()) 114 | r = requests.post(url, params=params, data=enforcer_info) 115 | response = r.json() 116 | return response 117 | 118 | def add_enforcer(self, enforcer: Enforcer) -> Dict: 119 | response = self.modify_enforcer("add-enforcer", enforcer) 120 | return response 121 | 122 | def update_enforcer(self, enforcer: Enforcer) -> Dict: 123 | response = self.modify_enforcer("update-enforcer", enforcer) 124 | return response 125 | 126 | def delete_enforcer(self, enforcer: Enforcer) -> Dict: 127 | response = self.modify_enforcer("delete-enforcer", enforcer) 128 | return response 129 | -------------------------------------------------------------------------------- /src/casdoor/adapter.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Adapter: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.type = "" 27 | self.databaseType = "" 28 | self.host = "" 29 | self.port = 0 30 | self.user = "" 31 | self.password = "" 32 | self.database = "" 33 | self.table = "" 34 | self.tableNamePrefix = "" 35 | self.isEnabled = False 36 | 37 | @classmethod 38 | def new(cls, owner, name, created_time, host, user): 39 | self = cls() 40 | self.owner = owner 41 | self.name = name 42 | self.createdTime = created_time 43 | self.host = host 44 | self.user = user 45 | return self 46 | 47 | @classmethod 48 | def from_dict(cls, data: dict): 49 | if data is None: 50 | return None 51 | 52 | adapter = cls() 53 | for key, value in data.items(): 54 | if hasattr(adapter, key): 55 | setattr(adapter, key, value) 56 | return adapter 57 | 58 | def __str__(self): 59 | return str(self.__dict__) 60 | 61 | def to_dict(self) -> dict: 62 | return self.__dict__ 63 | 64 | 65 | class _AdapterSDK: 66 | def get_adapters(self) -> List[Adapter]: 67 | """ 68 | Get the adapters from Casdoor. 69 | 70 | :return: a list of dicts containing adapter info 71 | """ 72 | url = self.endpoint + "/api/get-adapters" 73 | params = { 74 | "owner": self.org_name, 75 | "clientId": self.client_id, 76 | "clientSecret": self.client_secret, 77 | } 78 | r = requests.get(url, params) 79 | response = r.json() 80 | if response["status"] != "ok": 81 | raise Exception(response["msg"]) 82 | adapters = [] 83 | for adapter in response["data"]: 84 | adapters.append(Adapter.from_dict(adapter)) 85 | return adapters 86 | 87 | def get_adapter(self, adapter_id: str) -> Adapter: 88 | """ 89 | Get the adapter from Casdoor providing the adapter_id. 90 | 91 | :param adapter_id: the id of the adapter 92 | :return: a dict that contains adapter's info 93 | """ 94 | url = self.endpoint + "/api/get-adapter" 95 | params = { 96 | "id": f"{self.org_name}/{adapter_id}", 97 | "clientId": self.client_id, 98 | "clientSecret": self.client_secret, 99 | } 100 | r = requests.get(url, params) 101 | response = r.json() 102 | if response["status"] != "ok": 103 | raise Exception(response["msg"]) 104 | return Adapter.from_dict(response["data"]) 105 | 106 | def modify_adapter(self, method: str, adapter: Adapter) -> str: 107 | url = self.endpoint + f"/api/{method}" 108 | adapter.owner = self.org_name 109 | params = { 110 | "id": f"{adapter.owner}/{adapter.name}", 111 | "clientId": self.client_id, 112 | "clientSecret": self.client_secret, 113 | } 114 | adapter_info = json.dumps(adapter.to_dict()) 115 | r = requests.post(url, params=params, data=adapter_info) 116 | response = r.json() 117 | if response["status"] != "ok": 118 | raise Exception(response["msg"]) 119 | return str(response["data"]) 120 | 121 | def add_adapter(self, adapter: Adapter) -> Dict: 122 | response = self.modify_adapter("add-adapter", adapter) 123 | return response 124 | 125 | def update_adapter(self, adapter: Adapter) -> Dict: 126 | response = self.modify_adapter("update-adapter", adapter) 127 | return response 128 | 129 | def delete_adapter(self, adapter: Adapter) -> Dict: 130 | response = self.modify_adapter("delete-adapter", adapter) 131 | return response 132 | -------------------------------------------------------------------------------- /src/casdoor/pricing.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Pricing: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.description = "" 28 | self.plans = [""] 29 | self.isEnabled = False 30 | self.trialDuration = 0 31 | self.application = "" 32 | self.submitter = "" 33 | self.approver = "" 34 | self.approveTime = "" 35 | self.state = "" 36 | 37 | @classmethod 38 | def new(cls, owner, name, created_time, display_name, description, application): 39 | self = cls() 40 | self.owner = owner 41 | self.name = name 42 | self.createdTime = created_time 43 | self.displayName = display_name 44 | self.description = description 45 | self.application = application 46 | return self 47 | 48 | @classmethod 49 | def from_dict(cls, data: dict): 50 | if data is None: 51 | return None 52 | 53 | pricing = cls() 54 | for key, value in data.items(): 55 | if hasattr(pricing, key): 56 | setattr(pricing, key, value) 57 | return pricing 58 | 59 | def __str__(self): 60 | return str(self.__dict__) 61 | 62 | def to_dict(self) -> dict: 63 | return self.__dict__ 64 | 65 | 66 | class _PricingSDK: 67 | def get_pricings(self) -> List[Dict]: 68 | """ 69 | Get the pricings from Casdoor. 70 | 71 | :return: a list of dicts containing pricing info 72 | """ 73 | url = self.endpoint + "/api/get-pricings" 74 | params = { 75 | "owner": self.org_name, 76 | "clientId": self.client_id, 77 | "clientSecret": self.client_secret, 78 | } 79 | r = requests.get(url, params) 80 | response = r.json() 81 | if response["status"] != "ok": 82 | raise Exception(response["msg"]) 83 | pricings = [] 84 | for pricing in response["data"]: 85 | pricings.append(Pricing.from_dict(pricing)) 86 | return pricings 87 | 88 | def get_pricing(self, pricing_id: str) -> Dict: 89 | """ 90 | Get the pricing from Casdoor providing the pricing_id. 91 | 92 | :param pricing_id: the id of the pricing 93 | :return: a dict that contains pricing's info 94 | """ 95 | url = self.endpoint + "/api/get-pricing" 96 | params = { 97 | "id": f"{self.org_name}/{pricing_id}", 98 | "clientId": self.client_id, 99 | "clientSecret": self.client_secret, 100 | } 101 | r = requests.get(url, params) 102 | response = r.json() 103 | if response["status"] != "ok": 104 | raise Exception(response["msg"]) 105 | 106 | return Pricing.from_dict(response["data"]) 107 | 108 | def modify_pricing(self, method: str, pricing: Pricing) -> Dict: 109 | url = self.endpoint + f"/api/{method}" 110 | pricing.owner = self.org_name 111 | params = { 112 | "id": f"{pricing.owner}/{pricing.name}", 113 | "clientId": self.client_id, 114 | "clientSecret": self.client_secret, 115 | } 116 | pricing_info = json.dumps(pricing.to_dict()) 117 | r = requests.post(url, params=params, data=pricing_info) 118 | response = r.json() 119 | if response["status"] != "ok": 120 | raise Exception(response["msg"]) 121 | return response 122 | 123 | def add_pricing(self, pricing: Pricing) -> Dict: 124 | response = self.modify_pricing("add-pricing", pricing) 125 | return response 126 | 127 | def update_pricing(self, pricing: Pricing) -> Dict: 128 | response = self.modify_pricing("update-pricing", pricing) 129 | return response 130 | 131 | def delete_pricing(self, pricing: Pricing) -> Dict: 132 | response = self.modify_pricing("delete-pricing", pricing) 133 | return response 134 | -------------------------------------------------------------------------------- /src/casdoor/model.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | from .user import User 21 | 22 | 23 | class Model: 24 | def __init__(self): 25 | self.owner = "" 26 | self.name = "" 27 | self.createdTime = "" 28 | self.updatedTime = "" 29 | self.displayName = "" 30 | self.manager = "" 31 | self.contactEmail = "" 32 | self.type = "" 33 | self.parentId = "" 34 | self.isTopModel = False 35 | self.users = [User] 36 | self.title = "" 37 | self.key = "" 38 | self.children = [Model] 39 | self.modelText = "" 40 | self.isEnabled = False 41 | 42 | @classmethod 43 | def new(cls, owner, name, created_time, display_name, model_text): 44 | self = cls() 45 | self.owner = owner 46 | self.name = name 47 | self.createdTime = created_time 48 | self.displayName = display_name 49 | self.modelText = model_text 50 | return self 51 | 52 | @classmethod 53 | def from_dict(cls, data: dict): 54 | if not data: 55 | return None 56 | model = cls() 57 | for key, value in data.items(): 58 | if hasattr(model, key): 59 | setattr(model, key, value) 60 | return model 61 | 62 | def __str__(self): 63 | return str(self.__dict__) 64 | 65 | def to_dict(self) -> dict: 66 | return self.__dict__ 67 | 68 | 69 | class _ModelSDK: 70 | def get_models(self) -> List[Dict]: 71 | """ 72 | Get the models from Casdoor. 73 | 74 | :return: a list of dicts containing model info 75 | """ 76 | url = self.endpoint + "/api/get-models" 77 | params = { 78 | "owner": self.org_name, 79 | "clientId": self.client_id, 80 | "clientSecret": self.client_secret, 81 | } 82 | r = requests.get(url, params) 83 | response = r.json() 84 | if response["status"] != "ok": 85 | raise Exception(response["msg"]) 86 | models = [] 87 | for model in response["data"]: 88 | models.append(Model.from_dict(model)) 89 | return models 90 | 91 | def get_model(self, model_id: str) -> Dict: 92 | """ 93 | Get the model from Casdoor providing the model_id. 94 | 95 | :param model_id: the id of the model 96 | :return: a dict that contains model's info 97 | """ 98 | url = self.endpoint + "/api/get-model" 99 | params = { 100 | "id": f"{self.org_name}/{model_id}", 101 | "clientId": self.client_id, 102 | "clientSecret": self.client_secret, 103 | } 104 | r = requests.get(url, params) 105 | response = r.json() 106 | if response["status"] != "ok": 107 | raise Exception(response["msg"]) 108 | return Model.from_dict(response["data"]) 109 | 110 | def modify_model(self, method: str, model: Model) -> Dict: 111 | url = self.endpoint + f"/api/{method}" 112 | model.owner = self.org_name 113 | params = { 114 | "id": f"{model.owner}/{model.name}", 115 | "clientId": self.client_id, 116 | "clientSecret": self.client_secret, 117 | } 118 | model_info = json.dumps(model.to_dict(), default=self.custom_encoder) 119 | r = requests.post(url, params=params, data=model_info) 120 | response = r.json() 121 | return response 122 | 123 | def add_model(self, model: Model) -> Dict: 124 | response = self.modify_model("add-model", model) 125 | return response 126 | 127 | def update_model(self, model: Model) -> Dict: 128 | response = self.modify_model("update-model", model) 129 | return response 130 | 131 | def delete_model(self, model: Model) -> Dict: 132 | response = self.modify_model("delete-model", model) 133 | return response 134 | 135 | def custom_encoder(self, o): 136 | if isinstance(o, (Model, User)): 137 | return o.__dict__ 138 | -------------------------------------------------------------------------------- /src/casdoor/cert.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import List 17 | 18 | import requests 19 | 20 | 21 | class Cert: 22 | def __init__(self): 23 | self.name = "" 24 | self.owner = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.type = "" 28 | self.scope = "" 29 | self.cryptoAlgorithm = "" 30 | self.bitSize = 0 31 | self.expireInYears = 0 32 | self.certificate = "" 33 | self.privateKey = "" 34 | self.authorityPublicKey = "" 35 | self.authorityRootPublicKey = "" 36 | 37 | @classmethod 38 | def new(cls, owner, name, created_time, display_name, scope, type, crypto_algorithm, bit_size, expire_in_years): 39 | self = cls() 40 | self.owner = owner 41 | self.name = name 42 | self.createdTime = created_time 43 | self.displayName = display_name 44 | self.scope = scope 45 | self.type = type 46 | self.cryptoAlgorithm = crypto_algorithm 47 | self.bitSize = bit_size 48 | self.expireInYears = expire_in_years 49 | return self 50 | 51 | @classmethod 52 | def from_dict(cls, data: dict): 53 | if data is None: 54 | return None 55 | 56 | cert = cls() 57 | for key, value in data.items(): 58 | if hasattr(cert, key): 59 | setattr(cert, key, value) 60 | return cert 61 | 62 | def __str__(self): 63 | return str(self.__dict__) 64 | 65 | def to_dict(self) -> dict: 66 | return self.__dict__ 67 | 68 | 69 | class _CertSDK: 70 | def get_certs(self) -> List[Cert]: 71 | """ 72 | Get the certs from Casdoor. 73 | 74 | :return: a list of dicts containing cert info 75 | """ 76 | url = self.endpoint + "/api/get-certs" 77 | params = { 78 | "owner": self.org_name, 79 | "clientId": self.client_id, 80 | "clientSecret": self.client_secret, 81 | } 82 | r = requests.get(url, params) 83 | response = r.json() 84 | if response["status"] != "ok": 85 | raise ValueError(response["msg"]) 86 | 87 | res = [] 88 | for element in response["data"]: 89 | res.append(Cert.from_dict(element)) 90 | return res 91 | 92 | def get_cert(self, cert_id: str) -> Cert: 93 | """ 94 | Get the cert from Casdoor providing the cert_id. 95 | 96 | :param cert_id: the id of the cert 97 | :return: a dict that contains cert's info 98 | """ 99 | url = self.endpoint + "/api/get-cert" 100 | params = { 101 | "id": f"{self.org_name}/{cert_id}", 102 | "clientId": self.client_id, 103 | "clientSecret": self.client_secret, 104 | } 105 | r = requests.get(url, params) 106 | response = r.json() 107 | if response["status"] != "ok": 108 | raise ValueError(response["msg"]) 109 | 110 | return Cert.from_dict(response["data"]) 111 | 112 | def modify_cert(self, method: str, cert: Cert) -> str: 113 | url = self.endpoint + f"/api/{method}" 114 | cert.owner = self.org_name 115 | params = { 116 | "id": f"{cert.owner}/{cert.name}", 117 | "clientId": self.client_id, 118 | "clientSecret": self.client_secret, 119 | } 120 | cert_info = json.dumps(cert.to_dict()) 121 | r = requests.post(url, params=params, data=cert_info) 122 | response = r.json() 123 | if response["status"] != "ok": 124 | raise ValueError(response["msg"]) 125 | return str(response["data"]) 126 | 127 | def add_cert(self, cert: Cert) -> str: 128 | response = self.modify_cert("add-cert", cert) 129 | return response 130 | 131 | def update_cert(self, cert: Cert) -> str: 132 | response = self.modify_cert("update-cert", cert) 133 | return response 134 | 135 | def delete_cert(self, cert: Cert) -> str: 136 | response = self.modify_cert("delete-cert", cert) 137 | return response 138 | -------------------------------------------------------------------------------- /src/casdoor/group.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | from .user import User 21 | 22 | 23 | class Group: 24 | def __init__(self): 25 | self.owner = "" 26 | self.name = "" 27 | self.createdTime = "" 28 | self.updatedTime = "" 29 | self.displayName = "" 30 | self.manager = "" 31 | self.contactEmail = "" 32 | self.type = "" 33 | self.parentId = "" 34 | self.isTopGroup = False 35 | self.users: List[User] = [] 36 | self.title = "" 37 | self.key = "" 38 | self.children: List[Group] = [] 39 | self.isEnabled = False 40 | 41 | @classmethod 42 | def new(cls, owner, name, created_time, display_name): 43 | self = cls() 44 | self.owner = owner 45 | self.name = name 46 | self.createdTime = created_time 47 | self.displayName = display_name 48 | return self 49 | 50 | @classmethod 51 | def from_dict(cls, data: dict): 52 | if not data: 53 | return None 54 | group = cls() 55 | for key, value in data.items(): 56 | if hasattr(group, key): 57 | setattr(group, key, value) 58 | return group 59 | 60 | def __str__(self): 61 | return str(self.__dict__) 62 | 63 | def to_dict(self) -> dict: 64 | return self.__dict__ 65 | 66 | 67 | class _GroupSDK: 68 | def get_groups(self) -> List[Dict]: 69 | """ 70 | Get the groups from Casdoor. 71 | 72 | :return: a list of dicts containing group info 73 | """ 74 | url = self.endpoint + "/api/get-groups" 75 | params = { 76 | "owner": self.org_name, 77 | "clientId": self.client_id, 78 | "clientSecret": self.client_secret, 79 | } 80 | r = requests.get(url, params) 81 | response = r.json() 82 | if response["status"] != "ok": 83 | raise ValueError(response["msg"]) 84 | 85 | res = [] 86 | for element in response["data"]: 87 | res.append(Group.from_dict(element)) 88 | 89 | return res 90 | 91 | def get_group(self, group_id: str) -> Dict: 92 | """ 93 | Get the group from Casdoor providing the group_id. 94 | 95 | :param group_id: the id of the group 96 | :return: a dict that contains group's info 97 | """ 98 | url = self.endpoint + "/api/get-group" 99 | params = { 100 | "id": f"{self.org_name}/{group_id}", 101 | "clientId": self.client_id, 102 | "clientSecret": self.client_secret, 103 | } 104 | r = requests.get(url, params) 105 | response = r.json() 106 | if response["status"] != "ok": 107 | raise ValueError(response["msg"]) 108 | return Group.from_dict(response["data"]) 109 | 110 | def modify_group(self, method: str, group: Group) -> Dict: 111 | url = self.endpoint + f"/api/{method}" 112 | # if group.owner == "": 113 | # group.owner = self.org_name 114 | group.owner = self.org_name 115 | params = { 116 | "id": f"{group.owner}/{group.name}", 117 | "clientId": self.client_id, 118 | "clientSecret": self.client_secret, 119 | } 120 | 121 | # group_info = json.dumps(group.to_dict()) 122 | group_info = json.dumps(group.to_dict(), default=self.custom_encoder) 123 | r = requests.post(url, params=params, data=group_info) 124 | response = r.json() 125 | if response["status"] != "ok": 126 | raise ValueError(response["msg"]) 127 | 128 | return str(response["data"]) 129 | 130 | def add_group(self, group: Group) -> Dict: 131 | response = self.modify_group("add-group", group) 132 | return response 133 | 134 | def update_group(self, group: Group) -> Dict: 135 | response = self.modify_group("update-group", group) 136 | return response 137 | 138 | def delete_group(self, group: Group) -> Dict: 139 | response = self.modify_group("delete-group", group) 140 | return response 141 | 142 | def custom_encoder(self, o): 143 | if isinstance(o, (Group, User)): 144 | return o.__dict__ 145 | -------------------------------------------------------------------------------- /src/tests/test_user.py: -------------------------------------------------------------------------------- 1 | # Copyright 2023 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import datetime 16 | import unittest 17 | 18 | import src.tests.test_util as test_util 19 | from src.casdoor import CasdoorSDK 20 | from src.casdoor.user import User 21 | 22 | 23 | class UserTest(unittest.TestCase): 24 | @staticmethod 25 | def get_sdk(): 26 | sdk = CasdoorSDK( 27 | endpoint=test_util.TestEndpoint, 28 | client_id=test_util.TestClientId, 29 | client_secret=test_util.TestClientSecret, 30 | certificate=test_util.TestJwtPublicKey, 31 | org_name=test_util.TestOrganization, 32 | application_name=test_util.TestApplication, 33 | ) 34 | return sdk 35 | 36 | def test_user(self): 37 | name = test_util.get_random_name("User") 38 | email = f"{name}@gmail.com" 39 | phone = test_util.get_random_code(11) 40 | 41 | # Add a new object 42 | user = User.new( 43 | owner="admin", 44 | name=name, 45 | created_time=datetime.datetime.now().isoformat(), 46 | display_name=name, 47 | email=email, 48 | phone=phone, 49 | ) 50 | 51 | sdk = UserTest.get_sdk() 52 | try: 53 | sdk.add_user(user=user) 54 | except Exception as e: 55 | self.fail(f"Failed to add object: {e}") 56 | 57 | # Get all objects, check if our added object is inside the list 58 | try: 59 | users = sdk.get_users() 60 | except Exception as e: 61 | self.fail(f"Failed to get objects: {e}") 62 | names = [item.name for item in users] 63 | self.assertIn(name, names, "Added object not found in list") 64 | 65 | # Get the object 66 | try: 67 | user = sdk.get_user(name) 68 | user_id = user.id 69 | user_by_email = sdk.get_user_by_email(email) 70 | user_by_phone = sdk.get_user_by_phone(phone) 71 | user_by_user_id = sdk.get_user_by_user_id(user_id) 72 | except Exception as e: 73 | self.fail(f"Failed to get object: {e}") 74 | self.assertEqual(user.name, name) 75 | self.assertEqual(user_by_email.name, name) 76 | self.assertEqual(user_by_phone.name, name) 77 | self.assertEqual(user_by_user_id.name, name) 78 | 79 | # Update the object 80 | updated_display_name = "Updated Casdoor Website" 81 | user.displayName = updated_display_name 82 | try: 83 | sdk.update_user(user) 84 | except Exception as e: 85 | self.fail(f"Failed to update object: {e}") 86 | 87 | # Validate the update 88 | try: 89 | updated_user = sdk.get_user(name) 90 | except Exception as e: 91 | self.fail(f"Failed to get updated object: {e}") 92 | self.assertEqual(updated_user.displayName, updated_display_name) 93 | 94 | # Delete the object 95 | try: 96 | sdk.delete_user(user) 97 | except Exception as e: 98 | self.fail(f"Failed to delete object: {e}") 99 | 100 | # Validate the deletion 101 | try: 102 | deleted_user = sdk.get_user(name) 103 | except Exception as e: 104 | self.fail(f"Failed to get object: {e}") 105 | self.assertIsNone(deleted_user, "Failed to delete object, it's still retrievable") 106 | 107 | def test_get_global_users(self): 108 | sdk = UserTest.get_sdk() 109 | try: 110 | users = sdk.get_global_users() 111 | except Exception as e: 112 | self.fail(f"Fail to get object:{e}") 113 | 114 | self.assertIsInstance(users, list, "The returned result is not a list") 115 | for user in users: 116 | self.assertIsInstance(user, User, "There are non User type objects in the list") 117 | 118 | def test_get_sort_users(self): 119 | sdk = UserTest.get_sdk() 120 | try: 121 | users = sdk.get_sorted_users("created_time", 25) 122 | except Exception as e: 123 | self.fail(f"Fail to get object:{e}") 124 | self.assertIsInstance(users, list, "The returned result is not a list") 125 | for user in users: 126 | self.assertIsInstance(user, User, "There are non User type objects in the list") 127 | -------------------------------------------------------------------------------- /src/casdoor/payment.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Payment: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.provider = "" 28 | self.type = "" 29 | self.productName = "" 30 | self.productDisplayName = "" 31 | self.detail = "" 32 | self.tag = "" 33 | self.currency = "" 34 | self.price = 0.0 35 | self.returnUrl = "" 36 | self.user = "" 37 | self.personName = "" 38 | self.personIdCard = "" 39 | self.personEmail = "" 40 | self.personPhone = "" 41 | self.invoiceType = "" 42 | self.invoiceTitle = "" 43 | self.invoiceTaxId = "" 44 | self.invoiceRemark = "" 45 | self.invoiceUrl = "" 46 | self.outOrderId = "" 47 | self.payUrl = "" 48 | self.state = "" 49 | self.message = "" 50 | 51 | @classmethod 52 | def new(cls, owner, name, created_time, display_name, product_name): 53 | self = cls() 54 | self.owner = owner 55 | self.name = name 56 | self.createdTime = created_time 57 | self.displayName = display_name 58 | self.productName = product_name 59 | return self 60 | 61 | @classmethod 62 | def from_dict(cls, data: dict): 63 | if not data: 64 | return None 65 | payment = cls() 66 | for key, value in data.items(): 67 | if hasattr(payment, key): 68 | setattr(payment, key, value) 69 | return payment 70 | 71 | def __str__(self): 72 | return str(self.__dict__) 73 | 74 | def to_dict(self) -> dict: 75 | return self.__dict__ 76 | 77 | 78 | class _PaymentSDK: 79 | def get_payments(self) -> List[Dict]: 80 | """ 81 | Get the payments from Casdoor. 82 | 83 | :return: a list of dicts containing payment info 84 | """ 85 | url = self.endpoint + "/api/get-payments" 86 | params = { 87 | "owner": self.org_name, 88 | "clientId": self.client_id, 89 | "clientSecret": self.client_secret, 90 | } 91 | r = requests.get(url, params) 92 | response = r.json() 93 | if response["status"] != "ok": 94 | raise Exception(response["msg"]) 95 | payments = [] 96 | for payment in response["data"]: 97 | payments.append(Payment.from_dict(payment)) 98 | return payments 99 | 100 | def get_payment(self, payment_id: str) -> Dict: 101 | """ 102 | Get the payment from Casdoor providing the payment_id. 103 | 104 | :param payment_id: the id of the payment 105 | :return: a dict that contains payment's info 106 | """ 107 | url = self.endpoint + "/api/get-payment" 108 | params = { 109 | "id": f"{self.org_name}/{payment_id}", 110 | "clientId": self.client_id, 111 | "clientSecret": self.client_secret, 112 | } 113 | r = requests.get(url, params) 114 | response = r.json() 115 | if response["status"] != "ok": 116 | raise Exception(response["msg"]) 117 | return Payment.from_dict(response["data"]) 118 | 119 | def modify_payment(self, method: str, payment: Payment) -> Dict: 120 | url = self.endpoint + f"/api/{method}" 121 | payment.owner = self.org_name 122 | params = { 123 | "id": f"{payment.owner}/{payment.name}", 124 | "clientId": self.client_id, 125 | "clientSecret": self.client_secret, 126 | } 127 | payment_info = json.dumps(payment.to_dict()) 128 | r = requests.post(url, params=params, data=payment_info) 129 | response = r.json() 130 | return response 131 | 132 | def add_payment(self, payment: Payment) -> Dict: 133 | response = self.modify_payment("add-payment", payment) 134 | return response 135 | 136 | def update_payment(self, payment: Payment) -> Dict: 137 | response = self.modify_payment("update-payment", payment) 138 | return response 139 | 140 | def delete_payment(self, payment: Payment) -> Dict: 141 | response = self.modify_payment("delete-payment", payment) 142 | return response 143 | -------------------------------------------------------------------------------- /src/casdoor/webhook.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | from .syncer import TableColumn 21 | 22 | 23 | class Webhook: 24 | def __init__(self): 25 | self.owner = "" 26 | self.name = "" 27 | self.createdTime = "" 28 | self.organization = "" 29 | self.type = "" 30 | self.host = "" 31 | self.port = 0 32 | self.user = "" 33 | self.password = "" 34 | self.databaseType = "" 35 | self.database = "" 36 | self.table = "" 37 | self.tablePrimaryKey = "" 38 | self.tableColumns = [TableColumn] 39 | self.affiliationTable = "" 40 | self.avatarBaseUrl = "" 41 | self.errorText = "" 42 | self.syncInterval = 0 43 | self.isReadOnly = False 44 | self.isEnabled = False 45 | 46 | @classmethod 47 | def new(cls, owner, name, created_time, organization): 48 | self = cls() 49 | self.owner = owner 50 | self.name = name 51 | self.createdTime = created_time 52 | self.organization = organization 53 | return self 54 | 55 | @classmethod 56 | def from_dict(cls, d: dict): 57 | if d is None: 58 | return None 59 | webhook = cls() 60 | for key, value in d.items(): 61 | if hasattr(webhook, key): 62 | setattr(webhook, key, value) 63 | return webhook 64 | 65 | def __str__(self): 66 | return str(self.__dict__) 67 | 68 | def to_dict(self) -> dict: 69 | return self.__dict__ 70 | 71 | 72 | class _WebhookSDK: 73 | def get_webhooks(self) -> List[Dict]: 74 | """ 75 | Get the webhooks from Casdoor. 76 | 77 | :return: a list of dicts containing webhook info 78 | """ 79 | url = self.endpoint + "/api/get-webhooks" 80 | params = { 81 | "owner": self.org_name, 82 | "clientId": self.client_id, 83 | "clientSecret": self.client_secret, 84 | } 85 | r = requests.get(url, params) 86 | response = r.json() 87 | if response["status"] != "ok": 88 | raise Exception(response["msg"]) 89 | webhooks = [] 90 | for webhook in response["data"]: 91 | webhooks.append(Webhook.from_dict(webhook)) 92 | return webhooks 93 | 94 | def get_webhook(self, webhook_id: str) -> Dict: 95 | """ 96 | Get the webhook from Casdoor providing the webhook_id. 97 | 98 | :param webhook_id: the id of the webhook 99 | :return: a dict that contains webhook's info 100 | """ 101 | url = self.endpoint + "/api/get-webhook" 102 | params = { 103 | "id": f"{self.org_name}/{webhook_id}", 104 | "clientId": self.client_id, 105 | "clientSecret": self.client_secret, 106 | } 107 | r = requests.get(url, params) 108 | response = r.json() 109 | if response["status"] != "ok": 110 | raise Exception(response["msg"]) 111 | return Webhook.from_dict(response["data"]) 112 | 113 | def modify_webhook(self, method: str, webhook: Webhook) -> Dict: 114 | url = self.endpoint + f"/api/{method}" 115 | webhook.owner = self.org_name 116 | params = { 117 | "id": f"{webhook.owner}/{webhook.name}", 118 | "clientId": self.client_id, 119 | "clientSecret": self.client_secret, 120 | } 121 | webhook_info = json.dumps(webhook.to_dict(), default=self.custom_encoder) 122 | r = requests.post(url, params=params, data=webhook_info) 123 | response = r.json() 124 | if response["status"] != "ok": 125 | raise Exception(response["msg"]) 126 | return response 127 | 128 | def add_webhook(self, webhook: Webhook) -> Dict: 129 | response = self.modify_webhook("add-webhook", webhook) 130 | return response 131 | 132 | def update_webhook(self, webhook: Webhook) -> Dict: 133 | response = self.modify_webhook("update-webhook", webhook) 134 | return response 135 | 136 | def delete_webhook(self, webhook: Webhook) -> Dict: 137 | response = self.modify_webhook("delete-webhook", webhook) 138 | return response 139 | 140 | def custom_encoder(self, o): 141 | if isinstance(o, (TableColumn)): 142 | return o.__dict__ 143 | -------------------------------------------------------------------------------- /src/casdoor/subscription.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from datetime import datetime 17 | from typing import Dict, List 18 | 19 | import requests 20 | 21 | 22 | class Subscription: 23 | def __init__(self): 24 | self.owner = "" 25 | self.name = "" 26 | self.createdTime = "" 27 | self.displayName = "" 28 | self.startTime = datetime.now().isoformat() 29 | self.endTime = datetime.now().isoformat() 30 | self.duration = 0 31 | self.description = "" 32 | self.user = "" 33 | self.plan = "" 34 | self.isEnabled = False 35 | self.submitter = "" 36 | self.approver = "" 37 | self.approveTime = "" 38 | self.state = "" 39 | 40 | @classmethod 41 | def new(cls, owner, name, created_time, display_name, description): 42 | self = cls() 43 | self.owner = owner 44 | self.name = name 45 | self.createdTime = created_time 46 | self.displayName = display_name 47 | self.description = description 48 | return self 49 | 50 | @classmethod 51 | def from_dict(cls, data: dict): 52 | if data is None: 53 | return None 54 | 55 | subscription = cls() 56 | for key, value in data.items(): 57 | if hasattr(subscription, key): 58 | setattr(subscription, key, value) 59 | return subscription 60 | 61 | def __str__(self): 62 | return str(self.__dict__) 63 | 64 | def to_dict(self) -> dict: 65 | return self.__dict__ 66 | 67 | 68 | class _SubscriptionSDK: 69 | def get_subscriptions(self) -> List[Dict]: 70 | """ 71 | Get the subscriptions from Casdoor. 72 | 73 | :return: a list of dicts containing subscription info 74 | """ 75 | url = self.endpoint + "/api/get-subscriptions" 76 | params = { 77 | "owner": self.org_name, 78 | "clientId": self.client_id, 79 | "clientSecret": self.client_secret, 80 | } 81 | r = requests.get(url, params) 82 | response = r.json() 83 | if response["status"] != "ok": 84 | raise Exception(response["msg"]) 85 | subscriptions = [] 86 | for subscription in response["data"]: 87 | subscriptions.append(Subscription.from_dict(subscription)) 88 | return subscriptions 89 | 90 | def get_subscription(self, subscription_id: str) -> Dict: 91 | """ 92 | Get the subscription from Casdoor providing the subscription_id. 93 | 94 | :param subscription_id: the id of the subscription 95 | :return: a dict that contains subscription's info 96 | """ 97 | url = self.endpoint + "/api/get-subscription" 98 | params = { 99 | "id": f"{self.org_name}/{subscription_id}", 100 | "clientId": self.client_id, 101 | "clientSecret": self.client_secret, 102 | } 103 | r = requests.get(url, params) 104 | response = r.json() 105 | if response["status"] != "ok": 106 | raise Exception(response["msg"]) 107 | return Subscription.from_dict(response["data"]) 108 | 109 | def modify_subscription(self, method: str, subscription: Subscription) -> Dict: 110 | url = self.endpoint + f"/api/{method}" 111 | subscription.owner = self.org_name 112 | params = { 113 | "id": f"{subscription.owner}/{subscription.name}", 114 | "clientId": self.client_id, 115 | "clientSecret": self.client_secret, 116 | } 117 | subscription_info = json.dumps(subscription.to_dict()) 118 | r = requests.post(url, params=params, data=subscription_info) 119 | response = r.json() 120 | if response["status"] != "ok": 121 | raise Exception(response["msg"]) 122 | return response 123 | 124 | def add_subscription(self, subscription: Subscription) -> Dict: 125 | response = self.modify_subscription("add-subscription", subscription) 126 | return response 127 | 128 | def update_subscription(self, subscription: Subscription) -> Dict: 129 | response = self.modify_subscription("update-subscription", subscription) 130 | return response 131 | 132 | def delete_subscription(self, subscription: Subscription) -> Dict: 133 | response = self.modify_subscription("delete-subscription", subscription) 134 | return response 135 | -------------------------------------------------------------------------------- /src/casdoor/product.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | from .provider import Provider 21 | 22 | 23 | class Product: 24 | def __init__(self): 25 | self.owner = "" 26 | self.name = "" 27 | self.createdTime = "" 28 | self.displayName = "" 29 | self.image = "" 30 | self.detail = "" 31 | self.description = "" 32 | self.tag = "" 33 | self.currency = "" 34 | self.price = 0.0 35 | self.quantity = 0 36 | self.sold = 0 37 | self.providers = [""] 38 | self.returnUrl = "" 39 | self.state = "" 40 | self.providerObjs = [Provider] 41 | 42 | @classmethod 43 | def new(cls, owner, name, created_time, display_name, image, description, tag, quantity, sold, state): 44 | self = cls() 45 | self.owner = owner 46 | self.name = name 47 | self.createdTime = created_time 48 | self.displayName = display_name 49 | self.image = image 50 | self.description = description 51 | self.tag = tag 52 | self.quantity = quantity 53 | self.sold = sold 54 | self.state = state 55 | return self 56 | 57 | @classmethod 58 | def from_dict(cls, data: dict): 59 | if data is None: 60 | return None 61 | 62 | product = cls() 63 | for key, value in data.items(): 64 | if hasattr(product, key): 65 | setattr(product, key, value) 66 | return product 67 | 68 | def __str__(self): 69 | return str(self.__dict__) 70 | 71 | def to_dict(self) -> dict: 72 | return self.__dict__ 73 | 74 | 75 | class _ProductSDK: 76 | def get_products(self) -> List[Dict]: 77 | """ 78 | Get the products from Casdoor. 79 | 80 | :return: a list of dicts containing product info 81 | """ 82 | url = self.endpoint + "/api/get-products" 83 | params = { 84 | "owner": self.org_name, 85 | "clientId": self.client_id, 86 | "clientSecret": self.client_secret, 87 | } 88 | r = requests.get(url, params) 89 | response = r.json() 90 | if response["status"] != "ok": 91 | raise Exception(response["msg"]) 92 | products = [] 93 | for product in response["data"]: 94 | products.append(Product.from_dict(product)) 95 | return products 96 | 97 | def get_product(self, product_id: str) -> Dict: 98 | """ 99 | Get the product from Casdoor providing the product_id. 100 | 101 | :param product_id: the id of the product 102 | :return: a dict that contains product's info 103 | """ 104 | url = self.endpoint + "/api/get-product" 105 | params = { 106 | "id": f"{self.org_name}/{product_id}", 107 | "clientId": self.client_id, 108 | "clientSecret": self.client_secret, 109 | } 110 | r = requests.get(url, params) 111 | response = r.json() 112 | if response["status"] != "ok": 113 | raise Exception(response["msg"]) 114 | 115 | return Product.from_dict(response["data"]) 116 | 117 | def modify_product(self, method: str, product: Product) -> Dict: 118 | url = self.endpoint + f"/api/{method}" 119 | product.owner = self.org_name 120 | params = { 121 | "id": f"{product.owner}/{product.name}", 122 | "clientId": self.client_id, 123 | "clientSecret": self.client_secret, 124 | } 125 | product_info = json.dumps(product.to_dict(), default=self.custom_encoder) 126 | r = requests.post(url, params=params, data=product_info) 127 | response = r.json() 128 | if response["status"] != "ok": 129 | raise Exception(response["msg"]) 130 | return response 131 | 132 | def add_product(self, product: Product) -> Dict: 133 | response = self.modify_product("add-product", product) 134 | return response 135 | 136 | def update_product(self, product: Product) -> Dict: 137 | response = self.modify_product("update-product", product) 138 | return response 139 | 140 | def delete_product(self, product: Product) -> Dict: 141 | response = self.modify_product("delete-product", product) 142 | return response 143 | 144 | def custom_encoder(self, o): 145 | if isinstance(o, (Provider)): 146 | return o.__dict__ 147 | -------------------------------------------------------------------------------- /src/casdoor/token.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Token: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.application = "" 27 | self.organization = "" 28 | self.user = "" 29 | self.code = "" 30 | self.accessToken = "" 31 | self.refreshToken = "" 32 | self.expiresIn = 0 33 | self.scope = "" 34 | self.tokenType = "" 35 | self.codeChallenge = "" 36 | self.codeIsUsed = False 37 | self.codeExpireIn = 0 38 | 39 | @classmethod 40 | def new( 41 | cls, 42 | owner, 43 | name, 44 | created_time, 45 | application, 46 | organization, 47 | user, 48 | code, 49 | access_token, 50 | refresh_token, 51 | expires_in, 52 | scope, 53 | token_type, 54 | code_challenge, 55 | code_is_used, 56 | code_expire_in, 57 | ): 58 | self = cls() 59 | self.owner = owner 60 | self.name = name 61 | self.createdTime = created_time 62 | self.application = application 63 | self.organization = organization 64 | self.user = user 65 | self.code = code 66 | self.accessToken = access_token 67 | self.refreshToken = refresh_token 68 | self.expiresIn = expires_in 69 | self.scope = scope 70 | self.tokenType = token_type 71 | self.codeChallenge = code_challenge 72 | self.codeIsUsed = code_is_used 73 | self.codeExpireIn = code_expire_in 74 | return self 75 | 76 | @classmethod 77 | def from_dict(cls, data: dict): 78 | if data is None: 79 | return None 80 | 81 | token = cls() 82 | for key, value in data.items(): 83 | if hasattr(token, key): 84 | setattr(token, key, value) 85 | return token 86 | 87 | def __str__(self): 88 | return str(self.__dict__) 89 | 90 | def to_dict(self) -> dict: 91 | return self.__dict__ 92 | 93 | 94 | class _TokenSDK: 95 | def get_tokens(self, p, page_size) -> List[Dict]: 96 | """ 97 | Get the tokens from Casdoor. 98 | 99 | :return: a list of dicts containing token info 100 | """ 101 | url = self.endpoint + "/api/get-tokens" 102 | params = { 103 | "owner": self.org_name, 104 | "p": str(p), 105 | "pageSize": str(page_size), 106 | "clientId": self.client_id, 107 | "clientSecret": self.client_secret, 108 | } 109 | r = requests.get(url, params) 110 | response = r.json() 111 | if response["status"] != "ok": 112 | raise Exception(response["msg"]) 113 | tokens = [] 114 | for token in response["data"]: 115 | tokens.append(Token.from_dict(token)) 116 | return tokens 117 | 118 | def get_token(self, token_id: str) -> Dict: 119 | """ 120 | Get the token from Casdoor providing the token_id. 121 | 122 | :param token_id: the id of the token 123 | :return: a dict that contains token's info 124 | """ 125 | url = self.endpoint + "/api/get-token" 126 | params = { 127 | "id": f"{self.org_name}/{token_id}", 128 | "clientId": self.client_id, 129 | "clientSecret": self.client_secret, 130 | } 131 | r = requests.get(url, params) 132 | response = r.json() 133 | if response["status"] != "ok": 134 | raise Exception(response["msg"]) 135 | return Token.from_dict(response["data"]) 136 | 137 | def modify_token(self, method: str, token: Token) -> Dict: 138 | url = self.endpoint + f"/api/{method}" 139 | if token.owner == "": 140 | token.owner = self.org_name 141 | params = { 142 | "id": f"{token.owner}/{token.name}", 143 | "clientId": self.client_id, 144 | "clientSecret": self.client_secret, 145 | } 146 | token_info = json.dumps(token.to_dict()) 147 | r = requests.post(url, params=params, data=token_info) 148 | response = r.json() 149 | if response["status"] != "ok": 150 | raise Exception(response["msg"]) 151 | return response 152 | 153 | def add_token(self, token: Token) -> Dict: 154 | response = self.modify_token("add-token", token) 155 | return response 156 | 157 | def update_token(self, token: Token) -> Dict: 158 | response = self.modify_token("update-token", token) 159 | return response 160 | 161 | def delete_token(self, token: Token) -> Dict: 162 | response = self.modify_token("delete-token", token) 163 | return response 164 | -------------------------------------------------------------------------------- /src/casdoor/provider.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Provider: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.category = "" 28 | self.type = "" 29 | self.subType = "" 30 | self.method = "" 31 | self.clientId = "" 32 | self.clientSecret = "" 33 | self.clientId2 = "" 34 | self.clientSecret2 = "" 35 | self.cert = "" 36 | self.customAuthUrl = "" 37 | self.customTokenUrl = "" 38 | self.customUserInfoUrl = "" 39 | self.customLogo = "" 40 | self.scopes = "" 41 | self.userMapping = {"": ""} 42 | self.host = "" 43 | self.port = 0 44 | self.disableSsl = False 45 | self.title = "" 46 | self.content = "" 47 | self.receiver = "" 48 | self.regionId = "" 49 | self.signName = "" 50 | self.templateCode = "" 51 | self.appId = "" 52 | self.endpoint = "" 53 | self.intranetEndpoint = "" 54 | self.domain = "" 55 | self.bucket = "" 56 | self.pathPrefix = "" 57 | self.metadata = "" 58 | self.idP = "" 59 | self.issuerUrl = "" 60 | self.enableSignAuthnRequest = False 61 | self.providerUrl = "" 62 | 63 | @classmethod 64 | def new(cls, owner, name, created_time, display_name, category, type): 65 | self = cls() 66 | self.owner = owner 67 | self.name = name 68 | self.createdTime = created_time 69 | self.displayName = display_name 70 | self.category = category 71 | self.type = type 72 | return self 73 | 74 | @classmethod 75 | def from_dict(cls, d: dict): 76 | if not d: 77 | return None 78 | provider = cls() 79 | for key, value in d.items(): 80 | if hasattr(provider, key): 81 | setattr(provider, key, value) 82 | return provider 83 | 84 | def __str__(self): 85 | return str(self.__dict__) 86 | 87 | def to_dict(self) -> dict: 88 | return self.__dict__ 89 | 90 | 91 | class _ProviderSDK: 92 | def get_providers(self) -> List[Provider]: 93 | """ 94 | Get the providers from Casdoor. 95 | 96 | :return: a list of dicts containing provider info 97 | """ 98 | url = self.endpoint + "/api/get-providers" 99 | params = { 100 | "owner": self.org_name, 101 | "clientId": self.client_id, 102 | "clientSecret": self.client_secret, 103 | } 104 | r = requests.get(url, params) 105 | response = r.json() 106 | if response["status"] != "ok": 107 | raise Exception(response["msg"]) 108 | providers = [] 109 | for provider in response["data"]: 110 | providers.append(Provider.from_dict(provider)) 111 | return providers 112 | 113 | def get_provider(self, provider_id: str) -> Provider: 114 | """ 115 | Get the provider from Casdoor providing the provider_id. 116 | 117 | :param provider_id: the id of the provider 118 | :return: a dict that contains provider's info 119 | """ 120 | url = self.endpoint + "/api/get-provider" 121 | params = { 122 | "id": f"{self.org_name}/{provider_id}", 123 | "clientId": self.client_id, 124 | "clientSecret": self.client_secret, 125 | } 126 | r = requests.get(url, params) 127 | response = r.json() 128 | if response["status"] != "ok": 129 | raise Exception(response["msg"]) 130 | 131 | return Provider.from_dict(response["data"]) 132 | 133 | def modify_provider(self, method: str, provider: Provider) -> Dict: 134 | url = self.endpoint + f"/api/{method}" 135 | provider.owner = self.org_name 136 | params = { 137 | "id": f"{provider.owner}/{provider.name}", 138 | "clientId": self.client_id, 139 | "clientSecret": self.client_secret, 140 | } 141 | provider_info = json.dumps(provider.to_dict()) 142 | r = requests.post(url, params=params, data=provider_info) 143 | response = r.json() 144 | if response["status"] != "ok": 145 | raise Exception(response["msg"]) 146 | return response 147 | 148 | def add_provider(self, provider: Provider) -> Dict: 149 | response = self.modify_provider("add-provider", provider) 150 | return response 151 | 152 | def update_provider(self, provider: Provider) -> Dict: 153 | response = self.modify_provider("update-provider", provider) 154 | return response 155 | 156 | def delete_provider(self, provider: Provider) -> Dict: 157 | response = self.modify_provider("delete-provider", provider) 158 | return response 159 | -------------------------------------------------------------------------------- /src/casdoor/permission.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Permission: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.description = "" 28 | self.users = [""] 29 | self.roles = [""] 30 | self.domains = [""] 31 | self.model = "" 32 | self.adapter = "" 33 | self.resourceType = "" 34 | self.resources = [""] 35 | self.actions = [""] 36 | self.effect = "" 37 | self.isEnabled = False 38 | self.submitter = "" 39 | self.approver = "" 40 | self.approveTime = "" 41 | self.state = "" 42 | 43 | @classmethod 44 | def new( 45 | cls, 46 | owner, 47 | name, 48 | created_time, 49 | display_name, 50 | description, 51 | users, 52 | roles, 53 | domains, 54 | model, 55 | resource_type, 56 | resources, 57 | actions, 58 | effect, 59 | is_enabled, 60 | ): 61 | self = cls() 62 | self.owner = owner 63 | self.name = name 64 | self.createdTime = created_time 65 | self.displayName = display_name 66 | self.description = description 67 | self.users = users 68 | self.roles = roles 69 | self.domains = domains 70 | self.model = model 71 | self.resourceType = resource_type 72 | self.resources = resources 73 | self.actions = actions 74 | self.effect = effect 75 | self.isEnabled = is_enabled 76 | return self 77 | 78 | @classmethod 79 | def from_dict(cls, data: dict): 80 | if not data: 81 | return None 82 | permission = cls() 83 | for key, value in data.items(): 84 | if hasattr(permission, key): 85 | setattr(permission, key, value) 86 | return permission 87 | 88 | def __str__(self): 89 | return str(self.__dict__) 90 | 91 | def to_dict(self) -> dict: 92 | return self.__dict__ 93 | 94 | 95 | class _PermissionSDK: 96 | def get_permissions(self) -> List[Dict]: 97 | """ 98 | Get the permissions from Casdoor. 99 | 100 | :return: a list of dicts containing permission info 101 | """ 102 | url = self.endpoint + "/api/get-permissions" 103 | params = { 104 | "owner": self.org_name, 105 | "clientId": self.client_id, 106 | "clientSecret": self.client_secret, 107 | } 108 | r = requests.get(url, params) 109 | response = r.json() 110 | if response["status"] != "ok": 111 | raise Exception(response["msg"]) 112 | permissions = [] 113 | for permission in response["data"]: 114 | permissions.append(Permission.from_dict(permission)) 115 | return permissions 116 | 117 | def get_permission(self, permission_id: str) -> Dict: 118 | """ 119 | Get the permission from Casdoor providing the permission_id. 120 | 121 | :param permission_id: the id of the permission 122 | :return: a dict that contains permission's info 123 | """ 124 | url = self.endpoint + "/api/get-permission" 125 | params = { 126 | "id": f"{self.org_name}/{permission_id}", 127 | "clientId": self.client_id, 128 | "clientSecret": self.client_secret, 129 | } 130 | r = requests.get(url, params) 131 | response = r.json() 132 | if response["status"] != "ok": 133 | raise Exception(response["msg"]) 134 | return Permission.from_dict(response["data"]) 135 | 136 | def modify_permission(self, method: str, permission: Permission) -> Dict: 137 | url = self.endpoint + f"/api/{method}" 138 | permission.owner = self.org_name 139 | params = { 140 | "id": f"{permission.owner}/{permission.name}", 141 | "clientId": self.client_id, 142 | "clientSecret": self.client_secret, 143 | } 144 | permission_info = json.dumps(permission.to_dict()) 145 | r = requests.post(url, params=params, data=permission_info) 146 | response = r.json() 147 | if response["status"] != "ok": 148 | raise Exception(response["msg"]) 149 | return str(response["data"]) 150 | 151 | def add_permission(self, permission: Permission) -> Dict: 152 | response = self.modify_permission("add-permission", permission) 153 | return response 154 | 155 | def update_permission(self, permission: Permission) -> Dict: 156 | response = self.modify_permission("update-permission", permission) 157 | return response 158 | 159 | def delete_permission(self, permission: Permission) -> Dict: 160 | response = self.modify_permission("delete-permission", permission) 161 | return response 162 | -------------------------------------------------------------------------------- /src/casdoor/syncer.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class TableColumn: 22 | def __init__(self): 23 | self.name = "" 24 | self.type = "" 25 | self.casdoorName = "" 26 | self.isKey = False 27 | self.isHashed = False 28 | self.values = [""] 29 | 30 | def __str__(self): 31 | return str(self.__dict__) 32 | 33 | def to_dict(self) -> dict: 34 | return self.__dict__ 35 | 36 | 37 | class Syncer: 38 | def __init__(self): 39 | self.owner = "" 40 | self.name = "" 41 | self.createdTime = "" 42 | self.organization = "" 43 | self.type = "" 44 | self.host = "" 45 | self.port = 0 46 | self.user = "" 47 | self.password = "" 48 | self.databaseType = "" 49 | self.database = "" 50 | self.table = "" 51 | self.tablePrimaryKey = "" 52 | self.tableColumns = [TableColumn] 53 | self.affiliationTable = "" 54 | self.avatarBaseUrl = "" 55 | self.errorText = "" 56 | self.syncInterval = 0 57 | self.isReadOnly = False 58 | self.isEnabled = False 59 | 60 | @classmethod 61 | def new( 62 | cls, 63 | owner, 64 | name, 65 | created_time, 66 | organization, 67 | host, 68 | port, 69 | user, 70 | password, 71 | database_type, 72 | database, 73 | table, 74 | sync_interval, 75 | ): 76 | self = cls() 77 | self.owner = owner 78 | self.name = name 79 | self.createdTime = created_time 80 | self.organization = organization 81 | self.host = host 82 | self.port = port 83 | self.user = user 84 | self.password = password 85 | self.databaseType = database_type 86 | self.database = database 87 | self.table = table 88 | self.syncInterval = sync_interval 89 | return self 90 | 91 | @classmethod 92 | def from_dict(cls, d: dict): 93 | if not d: 94 | return None 95 | 96 | syncer = cls() 97 | for key, value in d.items(): 98 | if hasattr(syncer, key): 99 | setattr(syncer, key, value) 100 | return syncer 101 | 102 | def __str__(self): 103 | return str(self.__dict__) 104 | 105 | def to_dict(self) -> dict: 106 | return self.__dict__ 107 | 108 | 109 | class _SyncerSDK: 110 | def get_syncers(self) -> List[Dict]: 111 | """ 112 | Get the syncers from Casdoor. 113 | 114 | :return: a list of dicts containing syncer info 115 | """ 116 | url = self.endpoint + "/api/get-syncers" 117 | params = { 118 | "owner": self.org_name, 119 | "clientId": self.client_id, 120 | "clientSecret": self.client_secret, 121 | } 122 | r = requests.get(url, params) 123 | response = r.json() 124 | if response["status"] != "ok": 125 | raise Exception(response["msg"]) 126 | syncers = [] 127 | for syncer in response["data"]: 128 | syncers.append(Syncer.from_dict(syncer)) 129 | return syncers 130 | 131 | def get_syncer(self, syncer_id: str) -> Dict: 132 | """ 133 | Get the syncer from Casdoor providing the syncer_id. 134 | 135 | :param syncer_id: the id of the syncer 136 | :return: a dict that contains syncer's info 137 | """ 138 | url = self.endpoint + "/api/get-syncer" 139 | params = { 140 | "id": f"{self.org_name}/{syncer_id}", 141 | "clientId": self.client_id, 142 | "clientSecret": self.client_secret, 143 | } 144 | r = requests.get(url, params) 145 | response = r.json() 146 | if response["status"] != "ok": 147 | raise Exception(response["msg"]) 148 | return Syncer.from_dict(response["data"]) 149 | 150 | def modify_syncer(self, method: str, syncer: Syncer) -> Dict: 151 | url = self.endpoint + f"/api/{method}" 152 | syncer.owner = self.org_name 153 | params = { 154 | "id": f"{syncer.owner}/{syncer.name}", 155 | "clientId": self.client_id, 156 | "clientSecret": self.client_secret, 157 | } 158 | syncer_info = json.dumps(syncer.to_dict(), default=self.custom_encoder) 159 | r = requests.post(url, params=params, data=syncer_info) 160 | response = r.json() 161 | if response["status"] != "ok": 162 | raise Exception(response["msg"]) 163 | return response 164 | 165 | def add_syncer(self, syncer: Syncer) -> Dict: 166 | response = self.modify_syncer("add-syncer", syncer) 167 | return response 168 | 169 | def update_syncer(self, syncer: Syncer) -> Dict: 170 | response = self.modify_syncer("update-syncer", syncer) 171 | return response 172 | 173 | def delete_syncer(self, syncer: Syncer) -> Dict: 174 | response = self.modify_syncer("delete-syncer", syncer) 175 | return response 176 | 177 | def custom_encoder(self, o): 178 | if isinstance(o, (TableColumn)): 179 | return o.__dict__ 180 | -------------------------------------------------------------------------------- /src/casdoor/resource.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Resource: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.user = "" 27 | self.provider = "" 28 | self.application = "" 29 | self.tag = "" 30 | self.parent = "" 31 | self.fileName = "" 32 | self.fileType = "" 33 | self.fileFormat = "" 34 | self.fileSize = 0 35 | self.url = "" 36 | self.description = "" 37 | 38 | @classmethod 39 | def new(cls, owner, name): 40 | self = cls() 41 | self.owner = owner 42 | self.name = name 43 | return self 44 | 45 | @classmethod 46 | def from_dict(cls, data: dict): 47 | if data is None: 48 | return None 49 | resource = cls() 50 | for key, value in data.items(): 51 | setattr(resource, key, value) 52 | return resource 53 | 54 | def __str__(self): 55 | return str(self.__dict__) 56 | 57 | def to_dict(self) -> dict: 58 | return self.__dict__ 59 | 60 | 61 | class _ResourceSDK: 62 | def get_resources(self, owner, user, field, value, sort_field, sort_order) -> List[Dict]: 63 | """ 64 | Get the resources from Casdoor. 65 | 66 | :return: a list of dicts containing resource info 67 | """ 68 | url = self.endpoint + "/api/get-resources" 69 | params = { 70 | "owner": owner, 71 | "user": user, 72 | "field": field, 73 | "value": value, 74 | "sortField": sort_field, 75 | "sortOrder": sort_order, 76 | "clientId": self.client_id, 77 | "clientSecret": self.client_secret, 78 | } 79 | r = requests.get(url, params) 80 | response = r.json() 81 | if response["status"] != "ok": 82 | raise Exception(response["msg"]) 83 | resources = [] 84 | for resource in response["data"]: 85 | resources.append(Resource.from_dict(resource)) 86 | return resources 87 | 88 | def get_resource(self, resource_id: str) -> Dict: 89 | """ 90 | Get the resource from Casdoor providing the resource_id. 91 | 92 | :param resource_id: the id of the resource 93 | :return: a dict that contains resource's info 94 | """ 95 | url = self.endpoint + "/api/get-resource" 96 | params = { 97 | "id": f"{self.org_name}/{resource_id}", 98 | "clientId": self.client_id, 99 | "clientSecret": self.client_secret, 100 | } 101 | r = requests.get(url, params) 102 | response = r.json() 103 | if response["status"] != "ok": 104 | raise Exception(response["msg"]) 105 | 106 | return Resource.from_dict(response["data"]) 107 | 108 | def modify_resource(self, method: str, resource: Resource) -> Dict: 109 | url = self.endpoint + f"/api/{method}" 110 | resource.owner = self.org_name 111 | params = { 112 | "id": f"{resource.owner}/{resource.name}", 113 | "clientId": self.client_id, 114 | "clientSecret": self.client_secret, 115 | } 116 | resource_info = json.dumps(resource.to_dict()) 117 | r = requests.post(url, params=params, data=resource_info) 118 | response = r.json() 119 | if response["status"] != "ok": 120 | raise Exception(response["msg"]) 121 | return response 122 | 123 | def add_resource(self, resource: Resource) -> Dict: 124 | response = self.modify_resource("add-resource", resource) 125 | return response 126 | 127 | def update_resource(self, resource: Resource) -> Dict: 128 | response = self.modify_resource("update-resource", resource) 129 | return response 130 | 131 | def upload_resource(self, user, tag, parent, full_File_path, file) -> Dict: 132 | url = self.endpoint + "/api/upload-resource" 133 | params = { 134 | "owner": self.org_name, 135 | "user": user, 136 | "application": self.application_name, 137 | "tag": tag, 138 | "parent": parent, 139 | "fullFilePath": full_File_path, 140 | "clientId": self.client_id, 141 | "clientSecret": self.client_secret, 142 | } 143 | 144 | files = {"file": file} 145 | r = requests.post(url, params=params, files=files) 146 | response = r.json() 147 | if response["status"] != "ok": 148 | raise Exception(response["msg"]) 149 | return response 150 | 151 | def delete_resource(self, name) -> Dict: 152 | resource = Resource.new(self.org_name, name) 153 | user_str = json.dumps(resource.to_dict()) 154 | url = self.endpoint + "/api/delete-resource" 155 | params = { 156 | "owner": self.org_name, 157 | "name": name, 158 | "clientId": self.client_id, 159 | "clientSecret": self.client_secret, 160 | } 161 | r = requests.post(url, params=params, data=user_str) 162 | response = r.json() 163 | if response["status"] != "ok": 164 | raise Exception(response["msg"]) 165 | return response 166 | -------------------------------------------------------------------------------- /src/casdoor/role.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class Role: 22 | def __init__(self): 23 | self.owner = "" 24 | self.name = "" 25 | self.createdTime = "" 26 | self.displayName = "" 27 | self.description = "" 28 | self.users = [""] 29 | self.roles = [""] 30 | self.domains = [""] 31 | self.isEnabled = False 32 | 33 | @classmethod 34 | def new(cls, owner, name, created_time, display_name, description): 35 | self = cls() 36 | self.owner = owner 37 | self.name = name 38 | self.createdTime = created_time 39 | self.displayName = display_name 40 | self.description = description 41 | return self 42 | 43 | @classmethod 44 | def from_dict(cls, data: dict): 45 | if data is None: 46 | return None 47 | 48 | role = cls() 49 | for key, value in data.items(): 50 | if hasattr(role, key): 51 | setattr(role, key, value) 52 | return role 53 | 54 | def __str__(self): 55 | return str(self.__dict__) 56 | 57 | def to_dict(self) -> dict: 58 | return self.__dict__ 59 | 60 | 61 | class _RoleSDK: 62 | def get_roles(self) -> List[Dict]: 63 | """ 64 | Get the roles from Casdoor. 65 | 66 | :return: a list of dicts containing role info 67 | """ 68 | url = self.endpoint + "/api/get-roles" 69 | params = { 70 | "owner": self.org_name, 71 | "clientId": self.client_id, 72 | "clientSecret": self.client_secret, 73 | } 74 | r = requests.get(url, params) 75 | response = r.json() 76 | if response["status"] != "ok": 77 | raise Exception(response["msg"]) 78 | roles = [] 79 | for role in response["data"]: 80 | roles.append(Role.from_dict(role)) 81 | return roles 82 | 83 | def get_role(self, role_id: str) -> Dict: 84 | """ 85 | Get the role from Casdoor providing the role_id. 86 | 87 | :param role_id: the id of the role 88 | :return: a dict that contains role's info 89 | """ 90 | url = self.endpoint + "/api/get-role" 91 | params = { 92 | "id": f"{self.org_name}/{role_id}", 93 | "clientId": self.client_id, 94 | "clientSecret": self.client_secret, 95 | } 96 | r = requests.get(url, params) 97 | response = r.json() 98 | if response["status"] != "ok": 99 | raise Exception(response["msg"]) 100 | return Role.from_dict(response["data"]) 101 | 102 | def modify_role(self, method: str, role: Role) -> Dict: 103 | url = self.endpoint + f"/api/{method}" 104 | role.owner = self.org_name 105 | params = { 106 | "id": f"{role.owner}/{role.name}", 107 | "clientId": self.client_id, 108 | "clientSecret": self.client_secret, 109 | } 110 | role_info = json.dumps(role.to_dict()) 111 | r = requests.post(url, params=params, data=role_info) 112 | response = r.json() 113 | if response["status"] != "ok": 114 | raise Exception(response["msg"]) 115 | return response 116 | 117 | def add_role(self, role: Role) -> Dict: 118 | response = self.modify_role("add-role", role) 119 | return response 120 | 121 | def update_role(self, role: Role) -> Dict: 122 | response = self.modify_role("update-role", role) 123 | return response 124 | 125 | def delete_role(self, role: Role) -> Dict: 126 | response = self.modify_role("delete-role", role) 127 | return response 128 | 129 | def assign_role_to_user(self, username: str, role_name: str) -> Dict: 130 | """ 131 | Assign a role to a user by adding the user to the role's users list. 132 | 133 | :param username: the username to assign the role to 134 | :param role_name: the name of the role to assign 135 | :return: response dict with status 136 | """ 137 | user_id = f"{self.org_name}/{username}" 138 | 139 | role = self.get_role(role_name) 140 | if role is None: 141 | raise Exception(f"Role {role_name} not found") 142 | 143 | if not hasattr(role, "users") or role.users is None: 144 | role.users = [] 145 | 146 | if user_id not in role.users: 147 | role.users.append(user_id) 148 | return self.update_role(role) 149 | 150 | return {"status": "ok", "msg": "User already has this role"} 151 | 152 | def remove_role_from_user(self, username: str, role_name: str) -> Dict: 153 | """ 154 | Remove a role from a user by removing the user from the role's users list. 155 | 156 | :param username: the username to remove the role from 157 | :param role_name: the name of the role to remove 158 | :return: response dict with status 159 | """ 160 | user_id = f"{self.org_name}/{username}" 161 | 162 | role = self.get_role(role_name) 163 | if role is None: 164 | raise Exception(f"Role {role_name} not found") 165 | 166 | if hasattr(role, "users") and role.users and user_id in role.users: 167 | role.users.remove(user_id) 168 | return self.update_role(role) 169 | 170 | return {"status": "ok", "msg": "User does not have this role"} 171 | 172 | def get_user_roles(self, username: str) -> List[Role]: 173 | """ 174 | Get all roles assigned to a user. 175 | 176 | :param username: the username to get roles for 177 | :return: list of Role objects assigned to the user 178 | """ 179 | user_id = f"{self.org_name}/{username}" 180 | all_roles = self.get_roles() 181 | 182 | user_roles = [] 183 | for role in all_roles: 184 | if hasattr(role, "users") and role.users and user_id in role.users: 185 | user_roles.append(role) 186 | 187 | return user_roles 188 | -------------------------------------------------------------------------------- /src/casdoor/organization.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import Dict, List 17 | 18 | import requests 19 | 20 | 21 | class AccountItem: 22 | def __init__(self): 23 | self.name = "" 24 | self.visible = False 25 | self.viewRule = "" 26 | self.modifyRule = "" 27 | 28 | def __str__(self): 29 | return str(self.__dict__) 30 | 31 | def to_dict(self) -> dict: 32 | return self.__dict__ 33 | 34 | 35 | class ThemeData: 36 | def __init__(self): 37 | self.themeType = "" 38 | self.colorPrimary = "" 39 | self.borderRadius = 0 40 | self.isCompact = False 41 | self.isEnabled = False 42 | 43 | def __str__(self): 44 | return str(self.__dict__) 45 | 46 | def to_dict(self) -> dict: 47 | return self.__dict__ 48 | 49 | 50 | class MfaItem: 51 | def __init__(self): 52 | self.name = "" 53 | self.rule = "" 54 | 55 | def __str__(self): 56 | return str(self.__dict__) 57 | 58 | def to_dict(self) -> dict: 59 | return self.__dict__ 60 | 61 | 62 | class Organization: 63 | def __init__(self): 64 | self.owner = "" 65 | self.name = "" 66 | self.createdTime = "" 67 | self.displayName = "" 68 | self.websiteUrl = "" 69 | self.favicon = "" 70 | self.passwordType = "" 71 | self.passwordSalt = "" 72 | self.passwordOptions = [""] 73 | self.countryCodes = [""] 74 | self.defaultAvatar = "" 75 | self.defaultApplication = "" 76 | self.tags = [""] 77 | self.languages = [""] 78 | # self.themeData = ThemeData 79 | self.masterPassword = "" 80 | self.initScore = 0 81 | self.enableSoftDeletion = False 82 | self.isProfilePublic = False 83 | # self.mfaItems = [MfaItem] 84 | # self.accountItems = [AccountItem] 85 | 86 | @classmethod 87 | def new( 88 | cls, 89 | owner, 90 | name, 91 | created_time, 92 | display_name, 93 | website_url, 94 | password_type, 95 | password_options, 96 | country_codes, 97 | tags, 98 | languages, 99 | init_score, 100 | enable_soft_deletion, 101 | is_profile_public, 102 | ): 103 | self = cls() 104 | self.owner = owner 105 | self.name = name 106 | self.createdTime = created_time 107 | self.displayName = display_name 108 | self.websiteUrl = website_url 109 | self.passwordType = password_type 110 | self.passwordOptions = password_options 111 | self.countryCodes = country_codes 112 | self.tags = tags 113 | self.languages = languages 114 | self.initScore = init_score 115 | self.enableSoftDeletion = enable_soft_deletion 116 | self.isProfilePublic = is_profile_public 117 | 118 | return self 119 | 120 | @classmethod 121 | def from_dict(cls, data: dict): 122 | if data is None: 123 | return None 124 | 125 | org = cls() 126 | for key, value in data.items(): 127 | if hasattr(org, key): 128 | setattr(org, key, value) 129 | return org 130 | 131 | def __str__(self): 132 | return str(self.__dict__) 133 | 134 | def to_dict(self) -> dict: 135 | return self.__dict__ 136 | 137 | 138 | class _OrganizationSDK: 139 | def get_organizations(self) -> List[Dict]: 140 | """ 141 | Get the organizations from Casdoor. 142 | 143 | :return: a list of dicts containing organization info 144 | """ 145 | url = self.endpoint + "/api/get-organizations" 146 | params = { 147 | "owner": self.org_name, 148 | "clientId": self.client_id, 149 | "clientSecret": self.client_secret, 150 | } 151 | r = requests.get(url, params) 152 | response = r.json() 153 | if response["status"] != "ok": 154 | raise ValueError(response.msg) 155 | 156 | res = [] 157 | for element in response["data"]: 158 | res.append(Organization.from_dict(element)) 159 | return res 160 | 161 | def get_organization(self, organization_id: str) -> Dict: 162 | """ 163 | Get the organization from Casdoor providing the organization_id. 164 | 165 | :param organization_id: the id of the organization 166 | :return: a dict that contains organization's info 167 | """ 168 | url = self.endpoint + "/api/get-organization" 169 | params = { 170 | "id": f"admin/{organization_id}", 171 | "clientId": self.client_id, 172 | "clientSecret": self.client_secret, 173 | } 174 | r = requests.get(url, params) 175 | response = r.json() 176 | if response["status"] != "ok": 177 | raise ValueError(response.msg) 178 | return Organization.from_dict(response["data"]) 179 | 180 | def modify_organization(self, method: str, organization: Organization) -> Dict: 181 | url = self.endpoint + f"/api/{method}" 182 | 183 | params = { 184 | "id": f"{organization.owner}/{organization.name}", 185 | "clientId": self.client_id, 186 | "clientSecret": self.client_secret, 187 | } 188 | organization_info = json.dumps(organization.to_dict()) 189 | r = requests.post(url, params=params, data=organization_info) 190 | response = r.json() 191 | if response["status"] != "ok": 192 | raise ValueError(response) 193 | return str(response["data"]) 194 | 195 | def add_organization(self, organization: Organization) -> Dict: 196 | organization.owner = "admin" 197 | response = self.modify_organization("add-organization", organization) 198 | return response 199 | 200 | def update_organization(self, organization: Organization) -> Dict: 201 | organization.owner = "admin" 202 | response = self.modify_organization("update-organization", organization) 203 | return response 204 | 205 | def delete_organization(self, organization: Organization) -> Dict: 206 | organization.owner = "admin" 207 | response = self.modify_organization("delete-organization", organization) 208 | return response 209 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # casdoor-python-sdk 2 | 3 | [![GitHub Action](https://github.com/casdoor/casdoor-python-sdk/workflows/build/badge.svg?branch=master)](https://github.com/casdoor/casdoor-python-sdk/actions) 4 | [![Version](https://img.shields.io/pypi/v/casdoor.svg)](https://pypi.org/project/casdoor) 5 | [![PyPI - Wheel](https://img.shields.io/pypi/wheel/casdoor.svg)](https://pypi.org/project/casdoor) 6 | [![Pyversions](https://img.shields.io/pypi/pyversions/casdoor.svg)](https://pypi.org/project/casdoor) 7 | [![Discord](https://img.shields.io/discord/1022748306096537660?logo=discord&label=discord&color=5865F2)](https://discord.gg/5rPsrAzK7S) 8 | 9 | Casdoor's SDK for Python will allow you to easily connect your application to the Casdoor authentication system without having to implement it from scratch. 10 | 11 | Casdoor-python-sdk is available on PyPI: 12 | 13 | ```console 14 | $ pip install casdoor 15 | ``` 16 | 17 | Casdoor SDK is simple to use. We will show you the steps below. 18 | 19 | ## Step1. Init Config 20 | Initialization requires 5 parameters, which are all str type: 21 | | Name (in order) | Must | Description | 22 | | ---------------- | ---- | --------------------------------------------------- | 23 | | endpoint | Yes | Casdoor Server Url, such as `http://localhost:8000` | 24 | | client_id | Yes | Application.client_id | 25 | | client_secret | Yes | Application.client_secret | 26 | | certificate | Yes | Same as Casdoor certificate | 27 | | org_name | Yes | Organization name | 28 | | application_name | Yes | Application name | 29 | 30 | ```python 31 | from casdoor import CasdoorSDK 32 | 33 | certificate = b'''-----BEGIN CERTIFICATE----- 34 | MIIE+TCCAuGgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMDYxHTAbBgNVBAoTFENh 35 | ... 36 | -----END CERTIFICATE-----''' 37 | 38 | sdk = CasdoorSDK( 39 | endpoint, 40 | client_id, 41 | client_secret, 42 | certificate, 43 | org_name, 44 | application_name, 45 | ) 46 | ``` 47 | 48 | OR use async version 49 | 50 | ```python 51 | from casdoor import AsyncCasdoorSDK 52 | 53 | certificate = b'''-----BEGIN CERTIFICATE----- 54 | MIIE+TCCAuGgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMDYxHTAbBgNVBAoTFENh 55 | ... 56 | -----END CERTIFICATE-----''' 57 | 58 | sdk = AsyncCasdoorSDK( 59 | endpoint, 60 | client_id, 61 | client_secret, 62 | certificate, 63 | org_name, 64 | application_name, 65 | ) 66 | ``` 67 | 68 | 69 | ## Step2. Authorize with the Casdoor server 70 | At this point, we should use some ways to verify with the Casdoor server. 71 | 72 | To start, we want you understand clearly the verification process of Casdoor. 73 | The following paragraphs will mention your app that wants to use Casdoor as a means 74 | of verification as `APP`, and Casdoor as `Casdoor`. 75 | 76 | 1. `APP` will send a request to `Casdoor`. 77 | Since `Casdoor` is a UI-based OAuth 78 | provider, you cannot use request management service like Postman to send a URL 79 | with parameters and get back a JSON file. 80 | 81 | 82 | 2. The simplest way to try it out is to type the URL in your browser (in which JavaScript can be executed to run the UI). 83 | 84 | 3. Type in the URL in your browser in this format: 85 | `endpoint/login/oauth/authorize?client_id=xxx&response_type=code&redirect_uri=xxx&scope=read&state=xxx` 86 | In this URL the `endpoint` is your Casdoor's location, as mentioned in Step1; then the `xxx` need to be filled out by yourself. 87 | 88 | Hints: 89 | 1. `redirect_uri` is the URL that your `APP` is configured to 90 | listen to the response from `Casdoor`. For example, if your `redirect_uri` is `https://forum.casbin.com/callback`, then Casdoor will send a request to this URL along with two parameters `code` and `state`, which will be used in later steps for authentication. 91 | 92 | 2. `state` is usually your Application's name, you can find it under the `Applications` tab in `Casdoor`, and the leftmost `Name` column gives each application's name. 93 | 94 | 3. Of course you want your `APP` to be able to send the URL. For example you should have something like a button, and it carries this URL. So when you click the button, you should be redirected to `Casdoor` for verification. For now you are typing it in the browser simply for testing. 95 | 96 | ## Step3. Get token and parse 97 | 98 | After Casdoor verification passed, it will be redirected to your application with code and state as said in Step2, like `https://forum.casbin.com/callback?code=xxx&state=yyyy`. 99 | 100 | Your web application can get the `code` and call `get_oauth_token(code=code)`, then parse out jwt token. 101 | 102 | The general process is as follows: 103 | 104 | ```python 105 | token = sdk.get_oauth_token(code=code) 106 | access_token = token.get("access_token") 107 | decoded_msg = sdk.parse_jwt_token(access_token) # or sdk.parse_jwt_token(access_token, kwargs) 108 | ``` 109 | 110 | `decoded_msg` is the JSON data decoded from the `access_token`, which contains user info and other useful stuff. 111 | 112 | ## Step4. Interact with the users 113 | 114 | casdoor-python-sdk support basic user operations, like: 115 | 116 | - `get_user(user_id: str)`, get one user by user name. 117 | - `get_users()`, get all users. 118 | - `modify_user(method: str, user: User)/add_user(user: User)/update_user(user: User)/delete_user(user: User)`, write user to database. 119 | - `refresh_token_request(refresh_token: str, scope: str)`, refresh access token 120 | - `enforce(self, permission_model_name: str, sub: str, obj: str, act: str, v3: Optional[str], v4: Optional[str], v5: Optional[str])`, check permission from model 121 | - `batch_enforce(self, permission_model_name: str, permission_rules: list[list[str]])`, batch check permission from model 122 | - `get_user_count(is_online: bool = None)`, get user count. 123 | 124 | ## Resource Owner Password Credentials Grant 125 | 126 | If your application doesn't have a frontend that redirects users to Casdoor and you have Password Credentials Grant enabled, then you may get access token like this: 127 | 128 | ```python 129 | token = sdk.get_oauth_token(username=username, password=password) 130 | access_token = token.get("access_token") 131 | decoded_msg = sdk.parse_jwt_token(access_token) # or sdk.parse_jwt_token(access_token, kwargs) 132 | ``` 133 | 134 | `decoded_msg` is the JSON data decoded from the `access_token`, which contains user info and other useful stuff. 135 | 136 | ## Client Credentials Grant 137 | 138 | You can also use Client Credentials Grant when your application does not have a frontend. 139 | It is important to note that the AccessToken obtained in this way differs from other in that it corresponds to the application rather than to the user. 140 | 141 | ```python 142 | token = sdk.get_oauth_token() 143 | access_token = token.get("access_token") 144 | decoded_msg = sdk.parse_jwt_token(access_token) # or sdk.parse_jwt_token(access_token, kwargs) 145 | ``` 146 | 147 | `decoded_msg` is the JSON data decoded from the `access_token`. 148 | -------------------------------------------------------------------------------- /src/casdoor/application.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import json 16 | from typing import List 17 | 18 | import requests 19 | 20 | # from .organization import Organization, ThemeData 21 | from .provider import Provider 22 | 23 | 24 | class ProviderItem: 25 | def __init__(self): 26 | self.owner = "" 27 | self.name = "" 28 | self.canSignUp = False 29 | self.canSignIn = False 30 | self.canUnlink = False 31 | self.prompted = False 32 | self.alertType = "" 33 | self.rule = "" 34 | self.provider = Provider 35 | 36 | def __str__(self): 37 | return str(self.__dict__) 38 | 39 | def to_dict(self) -> dict: 40 | return self.__dict__ 41 | 42 | 43 | class SignupItem: 44 | def __init__(self): 45 | self.name = "" 46 | self.visible = False 47 | self.required = False 48 | self.prompted = False 49 | self.rule = "" 50 | 51 | def __str__(self): 52 | return str(self.__dict__) 53 | 54 | def to_dict(self) -> dict: 55 | return self.__dict__ 56 | 57 | 58 | class Application: 59 | def __init__(self): 60 | self.owner = "" 61 | self.name = "" 62 | self.createdTime = "" 63 | self.displayName = "" 64 | self.logo = "" 65 | self.homepageUrl = "" 66 | self.description = "" 67 | self.organization = "" 68 | self.cert = "" 69 | self.enablePassword = False 70 | self.enableSignUp = False 71 | self.enableSigninSession = False 72 | self.enableAutoSignin = False 73 | self.enableCodeSignin = False 74 | self.enableSamlCompress = False 75 | self.enableWebAuthn = False 76 | self.enableLinkWithEmail = False 77 | self.orgChoiceMode = "" 78 | self.samlReplyUrl = "" 79 | # self.providers = [ProviderItem] 80 | # self.signupItems = [SignupItem] 81 | self.grantTypes = [""] 82 | # self.organizationObj = Organization 83 | self.tags = [""] 84 | self.clientId = "" 85 | self.clientSecret = "" 86 | self.redirectUris = [""] 87 | self.tokenFormat = "" 88 | self.expireInHours = 0 89 | self.refreshExpireInHours = 0 90 | self.signupUrl = "" 91 | self.signinUrl = "" 92 | self.forgetUrl = "" 93 | self.affiliationUrl = "" 94 | self.termsOfUse = "" 95 | self.signupHtml = "" 96 | self.signinHtml = "" 97 | # self.themeData = ThemeData 98 | 99 | @classmethod 100 | def new(cls, owner, name, created_time, display_name, logo, homepage_url, description, organization): 101 | self = cls() 102 | self.owner = owner 103 | self.name = name 104 | self.createdTime = created_time 105 | self.displayName = display_name 106 | self.logo = logo 107 | self.homepageUrl = homepage_url 108 | self.description = description 109 | self.organization = organization 110 | return self 111 | 112 | @classmethod 113 | def from_dict(cls, data: dict): 114 | if data is None: 115 | return None 116 | 117 | app = cls() 118 | for key, value in data.items(): 119 | if hasattr(app, key): 120 | setattr(app, key, value) 121 | return app 122 | 123 | def __str__(self): 124 | return str(self.__dict__) 125 | 126 | def to_dict(self) -> dict: 127 | return self.__dict__ 128 | 129 | 130 | class _ApplicationSDK: 131 | def get_applications(self) -> List[Application]: 132 | """ 133 | Get the applications from Casdoor. 134 | 135 | :return: a list of dicts containing application info 136 | """ 137 | url = self.endpoint + "/api/get-applications" 138 | params = { 139 | "owner": "admin", 140 | "clientId": self.client_id, 141 | "clientSecret": self.client_secret, 142 | } 143 | r = requests.get(url, params) 144 | response = r.json() 145 | if response["status"] != "ok": 146 | raise ValueError(response["msg"]) 147 | 148 | res = [] 149 | for element in response["data"]: 150 | res.append(Application.from_dict(element)) 151 | return res 152 | 153 | def get_application(self, application_id: str) -> Application: 154 | """ 155 | Get the application from Casdoor providing the application_id. 156 | 157 | :param application_id: the id of the application 158 | :return: a dict that contains application's info 159 | """ 160 | url = self.endpoint + "/api/get-application" 161 | params = { 162 | "id": f"admin/{application_id}", 163 | "clientId": self.client_id, 164 | "clientSecret": self.client_secret, 165 | } 166 | r = requests.get(url, params) 167 | response = r.json() 168 | if response["status"] != "ok": 169 | raise ValueError(response["msg"]) 170 | return Application.from_dict(response["data"]) 171 | 172 | def modify_application(self, method: str, application: Application) -> str: 173 | url = self.endpoint + f"/api/{method}" 174 | if application.owner == "": 175 | application.owner = self.org_name 176 | params = { 177 | "id": f"{application.owner}/{application.name}", 178 | "clientId": self.client_id, 179 | "clientSecret": self.client_secret, 180 | } 181 | application_info = json.dumps(application.to_dict()) 182 | r = requests.post(url, params=params, data=application_info) 183 | response = r.json() 184 | if response["status"] != "ok": 185 | raise ValueError(response["msg"]) 186 | return str(response["data"]) 187 | 188 | def add_application(self, application: Application) -> str: 189 | application.owner = "admin" 190 | response = self.modify_application("add-application", application) 191 | return response 192 | 193 | def update_application(self, application: Application) -> str: 194 | application.owner = "admin" 195 | response = self.modify_application("update-application", application) 196 | return response 197 | 198 | def delete_application(self, application: Application) -> str: 199 | application.owner = "admin" 200 | response = self.modify_application("delete-application", application) 201 | return response 202 | -------------------------------------------------------------------------------- /src/tests/test_oauth.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import TestCase 16 | 17 | from requests import Response 18 | 19 | import src.tests.test_util as test_util 20 | from src.casdoor.main import CasdoorSDK 21 | from src.casdoor.user import User 22 | 23 | 24 | class TestOAuth(TestCase): 25 | """ 26 | You should replace the code content below and 27 | the get_sdk() method's content with your own Casdoor 28 | instance and such if you need to. And running these tests successfully 29 | proves that your connection to Casdoor is good-and-working! 30 | """ 31 | 32 | # server returned authorization code 33 | code = "6d038ac60d4e1f17e742" 34 | 35 | # Casdoor user and password for auth with 36 | # Resource Owner Password Credentials Grant. 37 | # Grant type "Password" must be enabled in Casdoor Application. 38 | username = "" 39 | password = "" 40 | 41 | @staticmethod 42 | def get_sdk(): 43 | sdk = CasdoorSDK( 44 | endpoint=test_util.TestEndpoint, 45 | client_id=test_util.TestClientId, 46 | client_secret=test_util.TestClientSecret, 47 | certificate=test_util.TestJwtPublicKey, 48 | org_name=test_util.TestOrganization, 49 | application_name=test_util.TestApplication, 50 | ) 51 | return sdk 52 | 53 | def test__oauth_token_request(self): 54 | sdk = self.get_sdk() 55 | data = { 56 | "grant_type": sdk.grant_type, 57 | "client_id": sdk.client_id, 58 | "client_secret": sdk.client_secret, 59 | "code": self.code, 60 | } 61 | response = sdk._oauth_token_request(payload=data) 62 | self.assertIsInstance(response, Response) 63 | 64 | def test__get_payload_for_authorization_code(self): 65 | sdk = self.get_sdk() 66 | result = sdk._CasdoorSDK__get_payload_for_authorization_code(code=self.code) 67 | self.assertEqual("authorization_code", result.get("grant_type")) 68 | 69 | def test__get_payload_for_client_credentials(self): 70 | sdk = self.get_sdk() 71 | result = sdk._CasdoorSDK__get_payload_for_client_credentials() 72 | self.assertEqual("client_credentials", result.get("grant_type")) 73 | 74 | def test__get_payload_for_password_credentials(self): 75 | sdk = self.get_sdk() 76 | result = sdk._CasdoorSDK__get_payload_for_password_credentials(username="test", password="test") 77 | self.assertEqual("password", result.get("grant_type")) 78 | 79 | def test__get_payload_for_access_token_request_with_code(self): 80 | sdk = self.get_sdk() 81 | result = sdk._get_payload_for_access_token_request(code="test") 82 | self.assertEqual("authorization_code", result.get("grant_type")) 83 | 84 | def test__get_payload_for_access_token_request_with_client_cred(self): 85 | sdk = self.get_sdk() 86 | result = sdk._get_payload_for_access_token_request() 87 | self.assertEqual("client_credentials", result.get("grant_type")) 88 | 89 | def test__get_payload_for_access_token_request_with_cred(self): 90 | sdk = self.get_sdk() 91 | result = sdk._get_payload_for_access_token_request(username="test", password="test") 92 | self.assertEqual("password", result.get("grant_type")) 93 | 94 | def test_get_oauth_token_with_client_cred(self): 95 | sdk = self.get_sdk() 96 | token = sdk.get_oauth_token() 97 | access_token = token.get("access_token") 98 | self.assertIsInstance(access_token, str) 99 | 100 | def test_get_oauth_token_with_code(self): 101 | sdk = self.get_sdk() 102 | token = sdk.get_oauth_token(code=self.code) 103 | access_token = token.get("access_token") 104 | self.assertIsInstance(access_token, str) 105 | 106 | def test_get_oauth_token_with_password(self): 107 | sdk = self.get_sdk() 108 | token = sdk.get_oauth_token(username=self.username, password=self.password) 109 | access_token = token.get("access_token") 110 | self.assertIsInstance(access_token, str) 111 | 112 | def test_oauth_token_request(self): 113 | sdk = self.get_sdk() 114 | response = sdk.oauth_token_request(self.code) 115 | self.assertIsInstance(response, Response) 116 | 117 | def test_refresh_token_request(self): 118 | sdk = self.get_sdk() 119 | response = sdk.oauth_token_request(self.code) 120 | refresh_token = response.json().get("refresh_token") 121 | response = sdk.refresh_token_request(refresh_token) 122 | self.assertIsInstance(response, Response) 123 | 124 | def test_get_oauth_refreshed_token(self): 125 | sdk = self.get_sdk() 126 | response = sdk.oauth_token_request(self.code) 127 | refresh_token = response.json().get("refresh_token") 128 | response = sdk.refresh_oauth_token(refresh_token) 129 | self.assertIsInstance(response, str) 130 | 131 | def test_parse_jwt_token(self): 132 | sdk = self.get_sdk() 133 | token = sdk.get_oauth_token(self.code) 134 | access_token = token.get("access_token") 135 | decoded_msg = sdk.parse_jwt_token(access_token) 136 | self.assertIsInstance(decoded_msg, dict) 137 | 138 | def test_enforce(self): 139 | sdk = self.get_sdk() 140 | status = sdk.enforce( 141 | permission_id="built-in/permission-built-in", 142 | model_id="", 143 | resource_id="", 144 | enforce_id="", 145 | owner="", 146 | casbin_request=["alice", "data1", "read"], 147 | ) 148 | self.assertIsInstance(status, bool) 149 | 150 | def test_enforce_parmas(self): 151 | sdk = self.get_sdk() 152 | status = sdk.enforce( 153 | permission_id="built-in/permission-built-in", 154 | model_id="", 155 | resource_id="", 156 | enforce_id="", 157 | owner="", 158 | casbin_request=["alice", "data1", "read"], 159 | ) 160 | self.assertIsInstance(status, bool) 161 | 162 | def test_batch_enforce(self): 163 | sdk = self.get_sdk() 164 | status = sdk.batch_enforce( 165 | permission_id="built-in/permission-built-in", 166 | model_id="", 167 | enforce_id="", 168 | owner="", 169 | casbin_request=[["alice", "data1", "read"], ["bob", "data2", "write"]], 170 | ) 171 | self.assertEqual(len(status), 2) 172 | self.assertIsInstance(status[0], bool) 173 | self.assertIsInstance(status[1], bool) 174 | 175 | def test_batch_enforce_raise(self): 176 | sdk = self.get_sdk() 177 | with self.assertRaises(ValueError): 178 | sdk.batch_enforce( 179 | permission_id="built-in/permission-built-in", 180 | model_id="", 181 | enforce_id="", 182 | owner="", 183 | casbin_request=[], 184 | ) 185 | 186 | def test_get_users(self): 187 | sdk = self.get_sdk() 188 | users = sdk.get_users() 189 | self.assertIsInstance(users, list) 190 | 191 | def test_get_user_count(self): 192 | sdk = self.get_sdk() 193 | online_count = sdk.get_user_count(is_online=True) 194 | offline_count = sdk.get_user_count(is_online=False) 195 | all_count = sdk.get_user_count() 196 | self.assertIsInstance(online_count, int) 197 | self.assertIsInstance(offline_count, int) 198 | self.assertIsInstance(all_count, int) 199 | self.assertEqual(online_count + offline_count, all_count) 200 | 201 | def test_get_user(self): 202 | sdk = self.get_sdk() 203 | user = sdk.get_user("admin") 204 | self.assertIsInstance(user, User) 205 | 206 | def test_modify_user(self): 207 | sdk = self.get_sdk() 208 | user = User() 209 | user.name = "test_ffyuanda" 210 | sdk.delete_user(user) 211 | 212 | response = sdk.add_user(user) 213 | self.assertEqual(response["data"], "Affected") 214 | 215 | response = sdk.delete_user(user) 216 | self.assertEqual(response["data"], "Affected") 217 | 218 | response = sdk.add_user(user) 219 | self.assertEqual(response["data"], "Affected") 220 | 221 | user.phone = "phone" 222 | response = sdk.update_user(user) 223 | self.assertEqual(response["data"], "Affected") 224 | 225 | self.assertIn("status", response) 226 | self.assertIsInstance(response, dict) 227 | -------------------------------------------------------------------------------- /src/tests/test_async_oauth.py: -------------------------------------------------------------------------------- 1 | # Copyright 2021 The Casdoor Authors. All Rights Reserved. 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from unittest import IsolatedAsyncioTestCase 16 | 17 | import src.tests.test_util as test_util 18 | from src.casdoor.async_main import AsyncCasdoorSDK 19 | from src.casdoor.user import User 20 | 21 | 22 | class TestOAuth(IsolatedAsyncioTestCase): 23 | """ 24 | You should replace the code content below and 25 | the get_sdk() method's content with your own Casdoor 26 | instance and such if you need to. And running these tests successfully 27 | proves that your connection to Casdoor is good-and-working! 28 | """ 29 | 30 | # server returned authorization code 31 | code = "21dc0ac806c27e6d7962" 32 | 33 | # Casdoor user and password for auth with 34 | # Resource Owner Password Credentials Grant. 35 | # Grant type "Password" must be enabled in Casdoor Application. 36 | username = "" 37 | password = "" 38 | 39 | @staticmethod 40 | def get_sdk(): 41 | sdk = AsyncCasdoorSDK( 42 | endpoint=test_util.TestEndpoint, 43 | client_id=test_util.TestClientId, 44 | client_secret=test_util.TestClientSecret, 45 | certificate=test_util.TestJwtPublicKey, 46 | org_name=test_util.TestOrganization, 47 | application_name=test_util.TestApplication, 48 | ) 49 | return sdk 50 | 51 | async def test__oauth_token_request(self): 52 | sdk = self.get_sdk() 53 | data = { 54 | "grant_type": sdk.grant_type, 55 | "client_id": sdk.client_id, 56 | "client_secret": sdk.client_secret, 57 | "code": self.code, 58 | } 59 | auth_token = await sdk._oauth_token_request(payload=data) 60 | self.assertIn("access_token", auth_token) 61 | 62 | async def test__get_payload_for_authorization_code(self): 63 | sdk = self.get_sdk() 64 | result = sdk._AsyncCasdoorSDK__get_payload_for_authorization_code(code=self.code) 65 | self.assertEqual("authorization_code", result.get("grant_type")) 66 | 67 | async def test__get_payload_for_password_credentials(self): 68 | sdk = self.get_sdk() 69 | result = sdk._AsyncCasdoorSDK__get_payload_for_password_credentials(username="test", password="test") 70 | self.assertEqual("password", result.get("grant_type")) 71 | 72 | async def test__get_payload_for_client_credentials(self): 73 | sdk = self.get_sdk() 74 | result = sdk._AsyncCasdoorSDK__get_payload_for_client_credentials() 75 | self.assertEqual("client_credentials", result.get("grant_type")) 76 | 77 | async def test__get_payload_for_access_token_request_with_code(self): 78 | sdk = self.get_sdk() 79 | result = sdk._get_payload_for_access_token_request(code="test") 80 | self.assertEqual("authorization_code", result.get("grant_type")) 81 | 82 | async def test__get_payload_for_access_token_request_with_cred(self): 83 | sdk = self.get_sdk() 84 | result = sdk._get_payload_for_access_token_request(username="test", password="test") 85 | self.assertEqual("password", result.get("grant_type")) 86 | 87 | async def test_get_payload_for_access_token_request_with_client_cred(self): 88 | sdk = self.get_sdk() 89 | result = sdk._get_payload_for_access_token_request() 90 | self.assertEqual("client_credentials", result.get("grant_type")) 91 | 92 | async def test_get_oauth_token_with_password(self): 93 | sdk = self.get_sdk() 94 | token = await sdk.get_oauth_token(username=self.username, password=self.password) 95 | access_token = token.get("access_token") 96 | self.assertIsInstance(access_token, str) 97 | 98 | async def test_get_oauth_token_with_client_cred(self): 99 | sdk = self.get_sdk() 100 | token = await sdk.get_oauth_token() 101 | access_token = token.get("access_token") 102 | self.assertIsInstance(access_token, str) 103 | 104 | async def test_get_oauth_token(self): 105 | sdk = self.get_sdk() 106 | token = await sdk.get_oauth_token(code=self.code) 107 | access_token = token.get("access_token") 108 | self.assertIsInstance(access_token, str) 109 | 110 | async def test_oauth_token_request(self): 111 | sdk = self.get_sdk() 112 | response = await sdk.oauth_token_request(self.code) 113 | self.assertIsInstance(response, dict) 114 | 115 | async def test_refresh_token_request(self): 116 | sdk = self.get_sdk() 117 | response = await sdk.oauth_token_request(self.code) 118 | refresh_token = response.get("refresh_token") 119 | self.assertIsInstance(refresh_token, str) 120 | response = await sdk.refresh_token_request(refresh_token) 121 | self.assertIsInstance(response, dict) 122 | 123 | async def test_get_oauth_refreshed_token(self): 124 | sdk = self.get_sdk() 125 | response = await sdk.oauth_token_request(self.code) 126 | refresh_token = response.get("refresh_token") 127 | response = await sdk.refresh_oauth_token(refresh_token) 128 | self.assertIsInstance(response, str) 129 | 130 | async def test_parse_jwt_token(self): 131 | sdk = self.get_sdk() 132 | token = await sdk.get_oauth_token(code=self.code) 133 | access_token = token.get("access_token") 134 | decoded_msg = sdk.parse_jwt_token(access_token) 135 | self.assertIsInstance(decoded_msg, dict) 136 | 137 | async def test_enforce(self): 138 | sdk = self.get_sdk() 139 | status = await sdk.enforce( 140 | permission_id="built-in/permission-built-in", 141 | model_id="", 142 | resource_id="", 143 | enforce_id="", 144 | owner="", 145 | casbin_request=["alice", "data1", "read"], 146 | ) 147 | self.assertIsInstance(status, bool) 148 | 149 | async def test_batch_enforce(self): 150 | sdk = self.get_sdk() 151 | status = await sdk.batch_enforce( 152 | permission_id="built-in/permission-built-in", 153 | model_id="", 154 | enforce_id="", 155 | owner="", 156 | casbin_request=[["alice", "data1", "read"], ["bob", "data2", "write"]], 157 | ) 158 | self.assertEqual(len(status), 2) 159 | self.assertIsInstance(status[0], bool) 160 | self.assertIsInstance(status[1], bool) 161 | 162 | async def test_get_users(self): 163 | sdk = self.get_sdk() 164 | users = await sdk.get_users() 165 | self.assertIsInstance(users, list) 166 | 167 | async def test_get_user(self): 168 | sdk = self.get_sdk() 169 | user = await sdk.get_user("admin") 170 | self.assertIsInstance(user, dict) 171 | self.assertEqual(user["name"], "admin") 172 | 173 | async def test_get_user_count(self): 174 | sdk = self.get_sdk() 175 | online_count = await sdk.get_user_count(is_online=True) 176 | offline_count = await sdk.get_user_count(is_online=False) 177 | all_count = await sdk.get_user_count() 178 | self.assertIsInstance(online_count, int) 179 | self.assertIsInstance(offline_count, int) 180 | self.assertIsInstance(all_count, int) 181 | self.assertEqual(online_count + offline_count, all_count) 182 | 183 | async def test_modify_user(self): 184 | sdk = self.get_sdk() 185 | user = User() 186 | user.name = "test_ffyuanda" 187 | user.owner = sdk.org_name 188 | await sdk.delete_user(user) 189 | 190 | response = await sdk.add_user(user) 191 | self.assertEqual(response["data"], "Affected") 192 | 193 | response = await sdk.delete_user(user) 194 | self.assertEqual(response["data"], "Affected") 195 | 196 | response = await sdk.add_user(user) 197 | self.assertEqual(response["data"], "Affected") 198 | 199 | user.phone = "phone" 200 | response = await sdk.update_user(user) 201 | self.assertEqual(response["data"], "Affected") 202 | 203 | self.assertIn("status", response) 204 | self.assertIsInstance(response, dict) 205 | 206 | def check_enforce_request(*args, **kwargs): 207 | return True 208 | 209 | async def test_auth_link(self): 210 | sdk = self.get_sdk() 211 | redirect_uri = "http://localhost:9000/callback" 212 | response = await sdk.get_auth_link(redirect_uri=redirect_uri) 213 | self.assertEqual( 214 | response, 215 | f"{sdk.front_endpoint}/login/oauth/authorize?client_id={sdk.client_id}&response_type=code&redirect_uri={redirect_uri}&scope=read&state={sdk.application_name}", 216 | ) 217 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------