diff --git a/docs/source/conf.py b/docs/source/conf.py index 9a5d438..c6bcb60 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -86,6 +86,7 @@ language = "en" # directories to ignore when looking for source files. # This patterns also effect to html_static_path and html_extra_path exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] +suppress_warnings = ["ref.python"] add_function_parentheses = False add_module_names = True diff --git a/poetry.lock b/poetry.lock index c636fa2..9fb3952 100644 --- a/poetry.lock +++ b/poetry.lock @@ -140,6 +140,18 @@ python-versions = ">=3.7" colorama = {version = "*", markers = "platform_system == \"Windows\""} importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} +[[package]] +name = "codespell" +version = "2.1.0" +description = "Codespell" +category = "dev" +optional = false +python-versions = ">=3.5" + +[package.extras] +dev = ["check-manifest", "flake8", "pytest", "pytest-cov", "pytest-dependency"] +hard-encoding-detection = ["chardet"] + [[package]] name = "colorama" version = "0.4.5" @@ -212,6 +224,14 @@ sdist = ["setuptools_rust (>=0.11.4)"] ssh = ["bcrypt (>=3.1.5)"] test = ["pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-subtests", "pytest-xdist", "pretend", "iso8601", "pytz", "hypothesis (>=1.11.4,!=3.79.2)"] +[[package]] +name = "darglint" +version = "1.8.1" +description = "A utility for ensuring Google-style docstrings stay up to date with the source code." +category = "dev" +optional = false +python-versions = ">=3.6,<4.0" + [[package]] name = "decli" version = "0.5.2" @@ -291,7 +311,7 @@ pydocstyle = ">=2.1" [[package]] name = "identify" -version = "2.5.1" +version = "2.5.2" description = "File identification library for Python" category = "dev" optional = false @@ -731,7 +751,7 @@ requests = ">=2.0.1,<3.0.0" [[package]] name = "rsa" -version = "4.8" +version = "4.9" description = "Pure-Python RSA implementation" category = "main" optional = false @@ -1039,7 +1059,7 @@ docs = ["mock", "alabaster", "commonmark", "recommonmark", "Sphinx", "sphinx-rtd [metadata] lock-version = "1.1" python-versions = "^3.7" -content-hash = "b6851001fb6b3e331a39e6bab1fa2ed99fdc555e9683137c20c9c593c0e1c040" +content-hash = "5d740e81a3604cb20ca85945c2fc134f6373f599315992afb50284f1f993c1d0" [metadata.files] alabaster = [ @@ -1075,6 +1095,7 @@ click = [ {file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"}, {file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"}, ] +codespell = [] colorama = [ {file = "colorama-0.4.5-py2.py3-none-any.whl", hash = "sha256:854bf444933e37f5824ae7bfc1e98d5bce2ebe4160d46b5edf346a89358e99da"}, {file = "colorama-0.4.5.tar.gz", hash = "sha256:e6c6b4334fc50988a639d9b98aa429a0b57da6e17b9a44f0451f930b6967b7a4"}, @@ -1086,6 +1107,7 @@ commonmark = [ ] coverage = [] cryptography = [] +darglint = [] decli = [ {file = "decli-0.5.2-py3-none-any.whl", hash = "sha256:d3207bc02d0169bf6ed74ccca09ce62edca0eb25b0ebf8bf4ae3fb8333e15ca0"}, {file = "decli-0.5.2.tar.gz", hash = "sha256:f2cde55034a75c819c630c7655a844c612f2598c42c21299160465df6ad463ad"}, @@ -1105,10 +1127,7 @@ flake8 = [ {file = "flake8-3.9.2.tar.gz", hash = "sha256:07528381786f2a6237b061f6e96610a4167b226cb926e2aa2b6b1d78057c576b"}, ] flake8-docstrings = [] -identify = [ - {file = "identify-2.5.1-py2.py3-none-any.whl", hash = "sha256:0dca2ea3e4381c435ef9c33ba100a78a9b40c0bab11189c7cf121f75815efeaa"}, - {file = "identify-2.5.1.tar.gz", hash = "sha256:3d11b16f3fe19f52039fb7e39c9c884b21cb1b586988114fbe42671f03de3e82"}, -] +identify = [] idna = [ {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, @@ -1355,10 +1374,7 @@ recommonmark = [ ] requests = [] requests-toolbelt = [] -rsa = [ - {file = "rsa-4.8-py3-none-any.whl", hash = "sha256:95c5d300c4e879ee69708c428ba566c59478fd653cc3a22243eeb8ed846950bb"}, - {file = "rsa-4.8.tar.gz", hash = "sha256:5c6bd9dc7a543b7fe4304a631f8a8a3b674e2bbfc49c2ae96200cdbe55df6b17"}, -] +rsa = [] six = [ {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, diff --git a/pyproject.toml b/pyproject.toml index 8adfa58..7874ca4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -56,6 +56,8 @@ flake8 = "^3.5.0" flake8-docstrings = "^1.6.0" commitizen = "^2.28.0" cryptography = "^37.0.4" +codespell = "^2.1.0" +darglint = "^1.8.1" [tool.poetry.extras] docs = [ @@ -80,3 +82,6 @@ line-length = 99 [tool.isort] line_length = 99 profile = "black" + +[tool.darglint] +enable = "DAR104" \ No newline at end of file diff --git a/src/keycloak/authorization/__init__.py b/src/keycloak/authorization/__init__.py index fddd551..feebe0b 100644 --- a/src/keycloak/authorization/__init__.py +++ b/src/keycloak/authorization/__init__.py @@ -44,7 +44,11 @@ class Authorization: @property def policies(self): - """Get policies.""" + """Get policies. + + :returns: Policies + :rtype: dict + """ return self._policies @policies.setter @@ -55,7 +59,7 @@ class Authorization: """Load policies, roles and permissions (scope/resources). :param data: keycloak authorization data (dict) - :returns: None + :type data: dict """ for pol in data["policies"]: if pol["type"] == "role": diff --git a/src/keycloak/authorization/permission.py b/src/keycloak/authorization/permission.py index 667f8c3..d1b606f 100644 --- a/src/keycloak/authorization/permission.py +++ b/src/keycloak/authorization/permission.py @@ -45,10 +45,29 @@ class Permission: https://keycloak.gitbooks.io/documentation/authorization_services/topics/permission/overview.html + :param name: Name + :type name: str + :param type: Type + :type type: str + :param logic: Logic + :type logic: str + :param decision_strategy: Decision strategy + :type decision_strategy: str + """ def __init__(self, name, type, logic, decision_strategy): - """Init method.""" + """Init method. + + :param name: Name + :type name: str + :param type: Type + :type type: str + :param logic: Logic + :type logic: str + :param decision_strategy: Decision strategy + :type decision_strategy: str + """ self.name = name self.type = type self.logic = logic @@ -57,16 +76,28 @@ class Permission: self.scopes = [] def __repr__(self): - """Repr method.""" + """Repr method. + + :returns: Class representation + :rtype: str + """ return "" % (self.name, self.type) def __str__(self): - """Str method.""" + """Str method. + + :returns: Class string representation + :rtype: str + """ return "Permission: %s (%s)" % (self.name, self.type) @property def name(self): - """Get name.""" + """Get name. + + :returns: name + :rtype: str + """ return self._name @name.setter @@ -75,7 +106,11 @@ class Permission: @property def type(self): - """Get type.""" + """Get type. + + :returns: type + :rtype: str + """ return self._type @type.setter @@ -84,7 +119,11 @@ class Permission: @property def logic(self): - """Get logic.""" + """Get logic. + + :returns: Logic + :rtype: str + """ return self._logic @logic.setter @@ -93,7 +132,11 @@ class Permission: @property def decision_strategy(self): - """Get decision strategy.""" + """Get decision strategy. + + :returns: Decision strategy + :rtype: str + """ return self._decision_strategy @decision_strategy.setter @@ -102,7 +145,11 @@ class Permission: @property def resources(self): - """Get resources.""" + """Get resources. + + :returns: Resources + :rtype: list + """ return self._resources @resources.setter @@ -111,7 +158,11 @@ class Permission: @property def scopes(self): - """Get scopes.""" + """Get scopes. + + :returns: Scopes + :rtype: list + """ return self._scopes @scopes.setter diff --git a/src/keycloak/authorization/policy.py b/src/keycloak/authorization/policy.py index 7e03db0..fdf482d 100644 --- a/src/keycloak/authorization/policy.py +++ b/src/keycloak/authorization/policy.py @@ -39,10 +39,29 @@ class Policy: https://keycloak.gitbooks.io/documentation/authorization_services/topics/policy/overview.html + :param name: Name + :type name: str + :param type: Type + :type type: str + :param logic: Logic + :type logic: str + :param decision_strategy: Decision strategy + :type decision_strategy: str + """ def __init__(self, name, type, logic, decision_strategy): - """Init method.""" + """Init method. + + :param name: Name + :type name: str + :param type: Type + :type type: str + :param logic: Logic + :type logic: str + :param decision_strategy: Decision strategy + :type decision_strategy: str + """ self.name = name self.type = type self.logic = logic @@ -51,16 +70,28 @@ class Policy: self.permissions = [] def __repr__(self): - """Repr method.""" + """Repr method. + + :returns: Class representation + :rtype: str + """ return "" % (self.name, self.type) def __str__(self): - """Str method.""" + """Str method. + + :returns: Class string representation + :rtype: str + """ return "Policy: %s (%s)" % (self.name, self.type) @property def name(self): - """Get name.""" + """Get name. + + :returns: Name + :rtype: str + """ return self._name @name.setter @@ -69,7 +100,11 @@ class Policy: @property def type(self): - """Get type.""" + """Get type. + + :returns: Type + :rtype: str + """ return self._type @type.setter @@ -78,7 +113,11 @@ class Policy: @property def logic(self): - """Get logic.""" + """Get logic. + + :returns: Logic + :rtype: str + """ return self._logic @logic.setter @@ -87,7 +126,11 @@ class Policy: @property def decision_strategy(self): - """Get decision strategy.""" + """Get decision strategy. + + :returns: Decision strategy + :rtype: str + """ return self._decision_strategy @decision_strategy.setter @@ -96,7 +139,11 @@ class Policy: @property def roles(self): - """Get roles.""" + """Get roles. + + :returns: Roles + :rtype: list + """ return self._roles @roles.setter @@ -105,7 +152,11 @@ class Policy: @property def permissions(self): - """Get permissions.""" + """Get permissions. + + :returns: Permissions + :rtype: list + """ return self._permissions @permissions.setter @@ -115,8 +166,9 @@ class Policy: def add_role(self, role): """Add keycloak role in policy. - :param role: keycloak role. - :return: + :param role: Keycloak role + :type role: keycloak.authorization.Role + :raises KeycloakAuthorizationConfigError: In case of misconfigured policy type """ if self.type != "role": raise KeycloakAuthorizationConfigError( @@ -127,7 +179,7 @@ class Policy: def add_permission(self, permission): """Add keycloak permission in policy. - :param permission: keycloak permission. - :return: + :param permission: Keycloak permission + :type permission: keycloak.authorization.Permission """ self._permissions.append(permission) diff --git a/src/keycloak/authorization/role.py b/src/keycloak/authorization/role.py index 4ee6ec9..3d4c000 100644 --- a/src/keycloak/authorization/role.py +++ b/src/keycloak/authorization/role.py @@ -31,19 +31,40 @@ class Role: manager, and employee are all typical roles that may exist in an organization. https://keycloak.gitbooks.io/documentation/server_admin/topics/roles.html + + :param name: Name + :type name: str + :param required: Required role indicator + :type required: bool """ def __init__(self, name, required=False): - """Init method.""" + """Init method. + + :param name: Name + :type name: str + :param required: Required role indicator + :type required: bool + """ self.name = name self.required = required def get_name(self): - """Get name.""" + """Get name. + + :returns: Name + :rtype: str + """ return self.name def __eq__(self, other): - """Eq method.""" + """Eq method. + + :param other: The other object + :type other: str + :returns: Equality bool + :rtype: bool | NotImplemented + """ if isinstance(other, str): return self.name == other return NotImplemented diff --git a/src/keycloak/connection.py b/src/keycloak/connection.py index 44978e5..fcdffb4 100644 --- a/src/keycloak/connection.py +++ b/src/keycloak/connection.py @@ -37,15 +37,32 @@ from .exceptions import KeycloakConnectionError class ConnectionManager(object): """Represents a simple server connection. - :param base_url: (str) The server URL. - :param headers: (dict) The header parameters of the requests to the server. - :param timeout: (int) Timeout to use for requests to the server. - :param verify: (bool) Verify server SSL. - :param proxies: (dict) The proxies servers requests is sent by. + :param base_url: The server URL. + :type base_url: str + :param headers: The header parameters of the requests to the server. + :type headers: dict + :param timeout: Timeout to use for requests to the server. + :type timeout: int + :param verify: Verify server SSL. + :type verify: bool + :param proxies: The proxies servers requests is sent by. + :type proxies: dict """ def __init__(self, base_url, headers={}, timeout=60, verify=True, proxies=None): - """Init method.""" + """Init method. + + :param base_url: The server URL. + :type base_url: str + :param headers: The header parameters of the requests to the server. + :type headers: dict + :param timeout: Timeout to use for requests to the server. + :type timeout: int + :param verify: Verify server SSL. + :type verify: bool + :param proxies: The proxies servers requests is sent by. + :type proxies: dict + """ self.base_url = base_url self.headers = headers self.timeout = timeout @@ -73,7 +90,11 @@ class ConnectionManager(object): @property def base_url(self): - """Return base url in use for requests to the server.""" + """Return base url in use for requests to the server. + + :returns: Base URL + :rtype: str + """ return self._base_url @base_url.setter @@ -82,7 +103,11 @@ class ConnectionManager(object): @property def timeout(self): - """Return timeout in use for request to the server.""" + """Return timeout in use for request to the server. + + :returns: Timeout + :rtype: int + """ return self._timeout @timeout.setter @@ -91,7 +116,11 @@ class ConnectionManager(object): @property def verify(self): - """Return verify in use for request to the server.""" + """Return verify in use for request to the server. + + :returns: Verify indicator + :rtype: bool + """ return self._verify @verify.setter @@ -100,7 +129,11 @@ class ConnectionManager(object): @property def headers(self): - """Return header request to the server.""" + """Return header request to the server. + + :returns: Request headers + :rtype: dict + """ return self._headers @headers.setter @@ -110,8 +143,10 @@ class ConnectionManager(object): def param_headers(self, key): """Return a specific header parameter. - :param key: (str) Header parameters key. + :param key: Header parameters key. + :type key: str :returns: If the header parameters exist, return its value. + :rtype: str """ return self.headers.get(key) @@ -122,32 +157,41 @@ class ConnectionManager(object): def exist_param_headers(self, key): """Check if the parameter exists in the header. - :param key: (str) Header parameters key. + :param key: Header parameters key. + :type key: str :returns: If the header parameters exist, return True. + :rtype: bool """ return self.param_headers(key) is not None def add_param_headers(self, key, value): """Add a single parameter inside the header. - :param key: (str) Header parameters key. - :param value: (str) Value to be added. + :param key: Header parameters key. + :type key: str + :param value: Value to be added. + :type value: str """ self.headers[key] = value def del_param_headers(self, key): """Remove a specific parameter. - :param key: (str) Key of the header parameters. + :param key: Key of the header parameters. + :type key: str """ self.headers.pop(key, None) def raw_get(self, path, **kwargs): """Submit get request to the path. - :param path: (str) Path for request. + :param path: Path for request. + :type path: str + :param kwargs: Additional arguments + :type kwargs: dict :returns: Response the request. - :raises: HttpError Can't connect to server. + :rtype: Response + :raises KeycloakConnectionError: HttpError Can't connect to server. """ try: return self._s.get( @@ -163,10 +207,15 @@ class ConnectionManager(object): def raw_post(self, path, data, **kwargs): """Submit post request to the path. - :param path: (str) Path for request. - :param data: (dict) Payload for request. + :param path: Path for request. + :type path: str + :param data: Payload for request. + :type data: dict + :param kwargs: Additional arguments + :type kwargs: dict :returns: Response the request. - :raises: HttpError Can't connect to server. + :rtype: Response + :raises KeycloakConnectionError: HttpError Can't connect to server. """ try: return self._s.post( @@ -183,10 +232,15 @@ class ConnectionManager(object): def raw_put(self, path, data, **kwargs): """Submit put request to the path. - :param path: (str) Path for request. - :param data: (dict) Payload for request. + :param path: Path for request. + :type path: str + :param data: Payload for request. + :type data: dict + :param kwargs: Additional arguments + :type kwargs: dict :returns: Response the request. - :raises: HttpError Can't connect to server. + :rtype: Response + :raises KeycloakConnectionError: HttpError Can't connect to server. """ try: return self._s.put( @@ -200,19 +254,24 @@ class ConnectionManager(object): except Exception as e: raise KeycloakConnectionError("Can't connect to server (%s)" % e) - def raw_delete(self, path, data={}, **kwargs): + def raw_delete(self, path, data=None, **kwargs): """Submit delete request to the path. - :param path: (str) Path for request. - :param data: (dict) Payload for request. + :param path: Path for request. + :type path: str + :param data: Payload for request. + :type data: dict | None + :param kwargs: Additional arguments + :type kwargs: dict :returns: Response the request. - :raises: HttpError Can't connect to server. + :rtype: Response + :raises KeycloakConnectionError: HttpError Can't connect to server. """ try: return self._s.delete( urljoin(self.base_url, path), params=kwargs, - data=data, + data=data or dict(), headers=self.headers, timeout=self.timeout, verify=self.verify, diff --git a/src/keycloak/exceptions.py b/src/keycloak/exceptions.py index 8eb69bf..9d947e3 100644 --- a/src/keycloak/exceptions.py +++ b/src/keycloak/exceptions.py @@ -21,7 +21,7 @@ # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -"""Keycloak custom exeptions module.""" +"""Keycloak custom exceptions module.""" import requests diff --git a/src/keycloak/keycloak_admin.py b/src/keycloak/keycloak_admin.py index 7d16ad5..4d3209b 100644 --- a/src/keycloak/keycloak_admin.py +++ b/src/keycloak/keycloak_admin.py @@ -49,19 +49,31 @@ class KeycloakAdmin: """Keycloak Admin client. :param server_url: Keycloak server url + :type server_url: str :param username: admin username + :type username: str :param password: admin password + :type password: str :param totp: Time based OTP + :type totp: str :param realm_name: realm name + :type realm_name: str :param client_id: client id + :type client_id: str :param verify: True if want check connection SSL + :type verify: bool :param client_secret_key: client secret key (optional, required only for access type confidential) + :type client_secret_key: str :param custom_headers: dict of custom header to pass to each HTML request + :type custom_headers: dict :param user_realm_name: The realm name of the user, if different from realm_name + :type user_realm_name: str :param auto_refresh_token: list of methods that allows automatic token refresh. Ex: ['get', 'put', 'post', 'delete'] + :type auto_refresh_token: list :param timeout: connection timeout in seconds + :type timeout: int """ PAGE_SIZE = 100 @@ -95,7 +107,35 @@ class KeycloakAdmin: auto_refresh_token=None, timeout=60, ): - """Init method.""" + """Init method. + + :param server_url: Keycloak server url + :type server_url: str + :param username: admin username + :type username: str + :param password: admin password + :type password: str + :param totp: Time based OTP + :type totp: str + :param realm_name: realm name + :type realm_name: str + :param client_id: client id + :type client_id: str + :param verify: True if want check connection SSL + :type verify: bool + :param client_secret_key: client secret key + (optional, required only for access type confidential) + :type client_secret_key: str + :param custom_headers: dict of custom header to pass to each HTML request + :type custom_headers: dict + :param user_realm_name: The realm name of the user, if different from realm_name + :type user_realm_name: str + :param auto_refresh_token: list of methods that allows automatic token refresh. + Ex: ['get', 'put', 'post', 'delete'] + :type auto_refresh_token: list + :param timeout: connection timeout in seconds + :type timeout: int + """ self.server_url = server_url self.username = username self.password = password @@ -114,7 +154,11 @@ class KeycloakAdmin: @property def server_url(self): - """Get server url.""" + """Get server url. + + :returns: Keycloak server url + :rtype: str + """ return self._server_url @server_url.setter @@ -123,7 +167,11 @@ class KeycloakAdmin: @property def realm_name(self): - """Get realm name.""" + """Get realm name. + + :returns: Realm name + :rtype: str + """ return self._realm_name @realm_name.setter @@ -132,7 +180,11 @@ class KeycloakAdmin: @property def connection(self): - """Get connection.""" + """Get connection. + + :returns: Connection manager + :rtype: ConnectionManager + """ return self._connection @connection.setter @@ -141,7 +193,11 @@ class KeycloakAdmin: @property def client_id(self): - """Get client id.""" + """Get client id. + + :returns: Client id + :rtype: str + """ return self._client_id @client_id.setter @@ -150,7 +206,11 @@ class KeycloakAdmin: @property def client_secret_key(self): - """Get client secret key.""" + """Get client secret key. + + :returns: Client secret key + :rtype: str + """ return self._client_secret_key @client_secret_key.setter @@ -159,7 +219,11 @@ class KeycloakAdmin: @property def verify(self): - """Get verify.""" + """Get verify. + + :returns: Verify indicator + :rtype: bool + """ return self._verify @verify.setter @@ -168,7 +232,11 @@ class KeycloakAdmin: @property def username(self): - """Get username.""" + """Get username. + + :returns: Admin username + :rtype: str + """ return self._username @username.setter @@ -177,7 +245,11 @@ class KeycloakAdmin: @property def password(self): - """Get password.""" + """Get password. + + :returns: Admin password + :rtype: str + """ return self._password @password.setter @@ -186,7 +258,11 @@ class KeycloakAdmin: @property def totp(self): - """Get totp.""" + """Get totp. + + :returns: TOTP + :rtype: str + """ return self._totp @totp.setter @@ -195,7 +271,11 @@ class KeycloakAdmin: @property def token(self): - """Get token.""" + """Get token. + + :returns: Access and refresh token + :rtype: dict + """ return self._token @token.setter @@ -204,12 +284,20 @@ class KeycloakAdmin: @property def auto_refresh_token(self): - """Get auto refresh token.""" + """Get auto refresh token. + + :returns: List of methods for automatic token refresh + :rtype: list + """ return self._auto_refresh_token @property def user_realm_name(self): - """Get user realm name.""" + """Get user realm name. + + :returns: User realm name + :rtype: str + """ return self._user_realm_name @user_realm_name.setter @@ -218,7 +306,11 @@ class KeycloakAdmin: @property def custom_headers(self): - """Get custom headers.""" + """Get custom headers. + + :returns: Custom headers + :rtype: dict + """ return self._custom_headers @custom_headers.setter @@ -247,13 +339,16 @@ class KeycloakAdmin: Wrapper function to paginate GET requests. :param url: The url on which the query is executed + :type url: str :param query: Existing query parameters (optional) + :type query: dict :return: Combined results of paginated queries + :rtype: list """ results = [] - # initalize query if it was called with None + # initialize query if it was called with None if not query: query = {} page = 0 @@ -274,8 +369,16 @@ class KeycloakAdmin: return results def __fetch_paginated(self, url, query=None): - query = query or {} + """Make a specific paginated request. + :param url: The url on which the query is executed + :type url: str + :param query: Pagination settings + :type query: dict + :returns: Response + :rtype: dict + """ + query = query or {} return raise_error_from_response(self.raw_get(url, **query), KeycloakGetError) def import_realm(self, payload): @@ -287,8 +390,9 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_realmrepresentation :param payload: RealmRepresentation - + :type payload: dict :return: RealmRepresentation + :rtype: dict """ data_raw = self.raw_post(urls_patterns.URL_ADMIN_REALMS, data=json.dumps(payload)) return raise_error_from_response(data_raw, KeycloakPostError, expected_codes=[201]) @@ -299,10 +403,13 @@ class KeycloakAdmin: RealmRepresentation https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_partialexport - :param export-clients: Skip if not want to export realm clients - :param export-groups-and-roles: Skip if not want to export realm groups and roles + :param export_clients: Skip if not want to export realm clients + :type export_clients: bool + :param export_groups_and_role: Skip if not want to export realm groups and roles + :type export_groups_and_role: bool :return: realm configurations JSON + :rtype: dict """ params_path = { "realm-name": self.realm_name, @@ -318,6 +425,7 @@ class KeycloakAdmin: """List all realms in Keycloak deployment. :return: realms list + :rtype: list """ data_raw = self.raw_get(urls_patterns.URL_ADMIN_REALMS) return raise_error_from_response(data_raw, KeycloakGetError) @@ -329,7 +437,9 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_realmrepresentation :param realm_name: Realm name (not the realm id) + :type realm_name: str :return: RealmRepresentation + :rtype: dict """ params_path = {"realm-name": realm_name} data_raw = self.raw_get(urls_patterns.URL_ADMIN_REALM.format(**params_path)) @@ -342,8 +452,11 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_realmrepresentation :param payload: RealmRepresentation + :type payload: dict :param skip_exists: Skip if Realm already exist. - :return: Keycloak server response (RealmRepresentation) + :type skip_exists: bool + :return: Keycloak server response (RealmRepresentation) + :rtype: dict """ data_raw = self.raw_post(urls_patterns.URL_ADMIN_REALMS, data=json.dumps(payload)) return raise_error_from_response( @@ -353,15 +466,18 @@ class KeycloakAdmin: def update_realm(self, realm_name, payload): """Update a realm. - This wil only update top level attributes and will ignore any user, + This will only update top level attributes and will ignore any user, role, or client information in the payload. RealmRepresentation: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_realmrepresentation :param realm_name: Realm name (not the realm id) + :type realm_name: str :param payload: RealmRepresentation + :type payload: dict :return: Http response + :rtype: dict """ params_path = {"realm-name": realm_name} data_raw = self.raw_put( @@ -373,7 +489,9 @@ class KeycloakAdmin: """Delete a realm. :param realm_name: Realm name (not the realm id) + :type realm_name: str :return: Http response + :rtype: dict """ params_path = {"realm-name": realm_name} data_raw = self.raw_delete(urls_patterns.URL_ADMIN_REALM.format(**params_path)) @@ -388,7 +506,9 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_userrepresentation :param query: Query parameters (optional) + :type query: dict :return: users list + :rtype: list """ query = query or {} params_path = {"realm-name": self.realm_name} @@ -406,6 +526,9 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_identityproviderrepresentation :param: payload: IdentityProviderRepresentation + :type payload: dict + :returns: Keycloak server response + :rtype: dict """ params_path = {"realm-name": self.realm_name} data_raw = self.raw_post( @@ -419,8 +542,12 @@ class KeycloakAdmin: IdentityProviderRepresentation https://www.keycloak.org/docs-api/15.0/rest-api/index.html#_identity_providers_resource - :param: alias: alias for IdP to update + :param: idp_alias: alias for IdP to update + :type idp_alias: str :param: payload: The IdentityProviderRepresentation + :type payload: dict + :returns: Keycloak server response + :rtype: dict """ params_path = {"realm-name": self.realm_name, "alias": idp_alias} data_raw = self.raw_put( @@ -435,7 +562,11 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_identityprovidermapperrepresentation :param: idp_alias: alias for Idp to add mapper in + :type idp_alias: str :param: payload: IdentityProviderMapperRepresentation + :type payload: dict + :returns: Keycloak server response + :rtype: dict """ params_path = {"realm-name": self.realm_name, "idp-alias": idp_alias} data_raw = self.raw_post( @@ -450,9 +581,13 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_update :param: idp_alias: alias for Idp to fetch mappers + :type idp_alias: str :param: mapper_id: Mapper Id to update + :type mapper_id: str :param: payload: IdentityProviderMapperRepresentation + :type payload: dict :return: Http response + :rtype: dict """ params_path = { "realm-name": self.realm_name, @@ -476,7 +611,9 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_getmappers :param: idp_alias: alias for Idp to fetch mappers + :type idp_alias: str :return: array IdentityProviderMapperRepresentation + :rtype: list """ params_path = {"realm-name": self.realm_name, "idp-alias": idp_alias} data_raw = self.raw_get(urls_patterns.URL_ADMIN_IDP_MAPPERS.format(**params_path)) @@ -491,6 +628,7 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_identityproviderrepresentation :return: array IdentityProviderRepresentation + :rtype: list """ params_path = {"realm-name": self.realm_name} data_raw = self.raw_get(urls_patterns.URL_ADMIN_IDPS.format(**params_path)) @@ -500,6 +638,9 @@ class KeycloakAdmin: """Delete an ID Provider. :param: idp_alias: idp alias name + :type idp_alias: str + :returns: Keycloak server response + :rtype: dict """ params_path = {"realm-name": self.realm_name, "alias": idp_alias} data_raw = self.raw_delete(urls_patterns.URL_ADMIN_IDP.format(**params_path)) @@ -514,10 +655,13 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_userrepresentation :param payload: UserRepresentation + :type payload: dict :param exist_ok: If False, raise KeycloakGetError if username already exists. Otherwise, return existing user ID. + :type exist_ok: bool :return: UserRepresentation + :rtype: dict """ params_path = {"realm-name": self.realm_name} @@ -540,8 +684,10 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_users_resource :param query: (dict) Query parameters for users count + :type query: dict :return: counter + :rtype: int """ query = query or dict() params_path = {"realm-name": self.realm_name} @@ -557,8 +703,10 @@ class KeycloakAdmin: https://www.keycloak.org/docs-api/18.0/rest-api/index.html#_userrepresentation :param username: id in UserRepresentation + :type username: str :return: user_id + :rtype: str """ lower_user_name = username.lower() users = self.get_users(query={"search": lower_user_name}) @@ -2870,7 +3018,7 @@ class KeycloakAdmin: def get_required_action_by_alias(self, action_alias): """Get a required action by its alias. - :param action_alias: the alias of the requried action. + :param action_alias: the alias of the required action. :type action_alias: str :return: the required action (RequiredActionProviderRepresentation). :rtype: dict diff --git a/tests/test_keycloak_admin.py b/tests/test_keycloak_admin.py index 2d34a18..f259915 100644 --- a/tests/test_keycloak_admin.py +++ b/tests/test_keycloak_admin.py @@ -1820,7 +1820,7 @@ def test_auto_refresh(admin: KeycloakAdmin, realm: str): def test_get_required_actions(admin: KeycloakAdmin, realm: str): - """Test requried actions.""" + """Test required actions.""" admin.realm_name = realm ractions = admin.get_required_actions() assert isinstance(ractions, list) diff --git a/tox.ini b/tox.ini index 16768bb..06a0855 100644 --- a/tox.ini +++ b/tox.ini @@ -13,6 +13,7 @@ commands = black --check --diff src/keycloak tests docs isort -c --df src/keycloak tests docs flake8 src/keycloak tests docs + codespell src tests docs [testenv:apply-check] commands = @@ -50,3 +51,7 @@ commands = max-line-length = 99 docstring-convention = all ignore = D203, D213, W503 +docstring_style = sphinx + +[darglint] +enable = DAR104 \ No newline at end of file