Coder Social home page Coder Social logo

python-keycloak's Introduction

Hi there 馃憢


Hi! I'm Marcos Pereira, graduated in Computer Science. I am currently a Technical Manager(Software Expert) at Mercado Livre Brasil. I have been involved in software development since 2010. I currently use Golang, but I have experience with Python, Java, and C++.

At Mercado Livre, I am responsible for designing, developing, and maintaining solutions used by the marketplace and logistics.

I鈥檝e worked in a few companies:

  • I started my career as an intern at the Federal University of Alagoas;
  • I was a programmer and software engineer at ADM Projetos e Consultorias (Macei贸/Alagoas);
  • I was a Software Engineer and Team Leader at Oolah Consultoria e Servi莽os Empresariais (Macei贸/Alagoas);
  • I was Software Engineer and Team Leader at NYX Knowledge (S茫o Paulo/AL);
  • I was a Software Engineer and Architect at Agriness (Florian贸polis/SC);
  • I was a Software Engineer and technical leader at Mercado Livre. Where I am currently a Software Expert (Technical Manager).

My Statistics

marcospereirampj's Github Stats marcospereirampj

python-keycloak's People

Contributors

arminfelder avatar asyd avatar cainotis avatar dependabot[bot] avatar domste avatar faffeldt avatar filirom1 avatar fredlb avatar ggallard avatar hadeer-e avatar iglimanajambersearch avatar jeronimomendes avatar kisamoto avatar lcgkm avatar lucapaganin avatar marcospereirampj avatar merle-nerger avatar mklassen avatar paoloromolini avatar pehala avatar rafaelweingartner avatar remcokranenburg avatar ryshoooo avatar ryshoooo-adamatics avatar salemwafi avatar spanierm42 avatar surbas avatar sweh avatar tobiasge avatar zerek-cheng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

python-keycloak's Issues

missing dependency dataclasses

On a Ubuntu 18.04.3 LTS with no previous installation of python keycloak

$ python3 -m pip install keycloak
Collecting keycloak
Downloading https://files.pythonhosted.org/packages/c9/e9/34f64356eb46972cbfde2ac1f7347d05faec74c990877d0e8b783a47f007/keycloak-2.0.0-py3-none-any.whl
Collecting cached-property (from keycloak)
Downloading https://files.pythonhosted.org/packages/3b/86/85c1be2e8db9e13ef9a350aecd6dea292bd612fa288c2f40d035bb750ded/cached_property-1.5.1-py2.py3-none-any.whl
Collecting pyyaml (from keycloak)
Downloading https://files.pythonhosted.org/packages/3d/d9/ea9816aea31beeadccd03f1f8b625ecf8f645bd66744484d162d84803ce5/PyYAML-5.3.tar.gz (268kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 276kB 2.3MB/s
Collecting cryptography (from keycloak)
Downloading https://files.pythonhosted.org/packages/45/73/d18a8884de8bffdcda475728008b5b13be7fbef40a2acc81a0d5d524175d/cryptography-2.8-cp34-abi3-manylinux1_x86_64.whl (2.3MB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 2.3MB 609kB/s
Collecting requests (from keycloak)
Downloading https://files.pythonhosted.org/packages/1a/70/1935c770cb3be6e3a8b78ced23d7e0f3b187f5cbfab4749523ed65d7c9b1/requests-2.23.0-py2.py3-none-any.whl (58kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 61kB 10.4MB/s
Collecting pyjwt (from keycloak)
Downloading https://files.pythonhosted.org/packages/87/8b/6a9f14b5f781697e51259d81657e6048fd31a113229cf346880bb7545565/PyJWT-1.7.1-py2.py3-none-any.whl
Collecting cffi!=1.11.3,>=1.8 (from cryptography->keycloak)
Downloading https://files.pythonhosted.org/packages/f1/c7/72abda280893609e1ddfff90f8064568bd8bcb2c1770a9d5bb5edb2d1fea/cffi-1.14.0-cp36-cp36m-manylinux1_x86_64.whl (399kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 399kB 3.9MB/s
Collecting six>=1.4.1 (from cryptography->keycloak)
Downloading https://files.pythonhosted.org/packages/65/eb/1f97cb97bfc2390a276969c6fae16075da282f5058082d4cb10c6c5c1dba/six-1.14.0-py2.py3-none-any.whl
Collecting idna<3,>=2.5 (from requests->keycloak)
Downloading https://files.pythonhosted.org/packages/89/e3/afebe61c546d18fb1709a61bee788254b40e736cff7271c7de5de2dc4128/idna-2.9-py2.py3-none-any.whl (58kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 61kB 13.1MB/s
Collecting certifi>=2017.4.17 (from requests->keycloak)
Cache entry deserialization failed, entry ignored
Downloading https://files.pythonhosted.org/packages/b9/63/df50cac98ea0d5b006c55a399c3bf1db9da7b5a24de7890bc9cfd5dd9e99/certifi-2019.11.28-py2.py3-none-any.whl (156kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 163kB 813kB/s
Collecting chardet<4,>=3.0.2 (from requests->keycloak)
Downloading https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl (133kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 143kB 5.9MB/s
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests->keycloak)
Cache entry deserialization failed, entry ignored
Downloading https://files.pythonhosted.org/packages/e8/74/6e4f91745020f967d09332bb2b8b9b10090957334692eb88ea4afe91b77f/urllib3-1.25.8-py2.py3-none-any.whl (125kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 133kB 10.9MB/s
Collecting pycparser (from cffi!=1.11.3,>=1.8->cryptography->keycloak)
Downloading https://files.pythonhosted.org/packages/68/9e/49196946aee219aead1290e00d1e7fdeab8567783e83e1b9ab5585e6206a/pycparser-2.19.tar.gz (158kB)
100% |鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅鈻堚枅| 163kB 6.0MB/s
Building wheels for collected packages: pyyaml, pycparser
Running setup.py bdist_wheel for pyyaml ... done
Stored in directory: /home/rgarcia/.cache/pip/wheels/e4/76/4d/a95b8dd7b452b69e8ed4f68b69e1b55e12c9c9624dd962b191
Running setup.py bdist_wheel for pycparser ... done
Stored in directory: /home/rgarcia/.cache/pip/wheels/f2/9a/90/de94f8556265ddc9d9c8b271b0f63e57b26fb1d67a45564511
Successfully built pyyaml pycparser
Installing collected packages: cached-property, pyyaml, pycparser, cffi, six, cryptography, idna, certifi, chardet, urllib3, requests, pyjwt, keycloak
Successfully installed cached-property-1.5.1 certifi-2019.11.28 cffi-1.14.0 chardet-3.0.4 cryptography-2.8 idna-2.9 keycloak-2.0.0 pycparser-2.19 pyjwt-1.7.1 pyyaml-5.3 requests-2.23.0 six-1.14.0 urllib3-1.25.8

$ cat > tests.py
from keycloak import KeycloakOpenID
^D

$ python3 tests.py
Traceback (most recent call last):
File "tests.py", line 1, in
from keycloak import KeycloakOpenID
File "/home/rgarcia/.local/lib/python3.6/site-packages/keycloak/init.py", line 7, in
from .mixins.authentication import AuthenticationMixin
File "/home/rgarcia/.local/lib/python3.6/site-packages/keycloak/mixins/authentication.py", line 9, in
from ..config import config
File "/home/rgarcia/.local/lib/python3.6/site-packages/keycloak/config.py", line 6, in
from dataclasses import dataclass, fields
ModuleNotFoundError: No module named 'dataclasses'

Feature request: add custom headers to requests

Keycloak can be placed behind a reverse proxy that require some custom header to be present for security reason.
It would be nice to have an option to add those custom headers to objects creation

delete_client fails with a 404

Am trying to delete a client in a realm and it fails with the following error:
{noformat}
.tox/py37-cdp/lib/python3.7/site-packages/keycloak/keycloak_admin.py:662: in delete_client
return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)


response = <Response [404]>, error = <class 'keycloak.exceptions.KeycloakGetError'>, expected_code = 204, skip_exists = False

def raise_error_from_response(response, error, expected_code=200, skip_exists=False):
    if expected_code == response.status_code:
        if expected_code == requests.codes.no_content:
            return {}

        try:
            return response.json()
        except ValueError:
            return response.content

    if skip_exists and response.status_code == 409:
        return {"Already exists"}

    try:
        message = response.json()['message']
    except (KeyError, ValueError):
        message = response.content

    if isinstance(error, dict):
        error = error.get(response.status_code, KeycloakOperationError)
    else:
        if response.status_code == 401:
            error = KeycloakAuthenticationError

    raise error(error_message=message,
                response_code=response.status_code,
              response_body=response.content)

E keycloak.exceptions.KeycloakGetError: 404: b''
{noformat}

KeycloakAdmin create_user in specific realm

Hi!

In our use case, we need to specify realm, where user will be created :)

Example: User from realm "master" create users in another realms.

I want to do PR for this feature and other API methods, if you approve.

Example:

def create_user(self, payload, realm=None):
    realm = realm if realm else self.realm_name
    params_path = {"realm-name": realm}

      ...

#5 solution slightly ugly :))

delete/update realm

I only found create_realm, how can I delete or update a realm? Is there any plan to add these functions? Thank you very much!

`create_user` transparently returns existing users, which leads to a race condition

Suppose we want to register a new user; we also want to ensure user with such name doesn't already exist. Currently create_user transparently checks this and returns existing user ID if that's the case. This defeats the whole said aim - we could try and workaround this by running get_user_id by ourselves before create_user to find out whether the user already exists; however this;

  1. Leads to two get_user_id requests;
  2. Creates a race condition; user could be created between two get_user_id requests by another client and we'll never find out.

Token decode gives error 'Invalid audience'

I am trying to decode the token using
token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options)

KEYCLOAK_PUBLIC_KEY
-----BEGIN PUBLIC KEY-----\n xxxx xxxx \n-----END PUBLIC KEY-----

options
{'exp': True, 'verify_signature': False, 'verify_aud': True}

Error
`token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options)

Traceback (most recent call last):
File "", line 1, in
File "/venv/lib/python3.5/site-packages/keycloak/keycloak_openid.py", line 346, in decode_token
audience=self.client_id, **kwargs)
File "/venv/lib/python3.5/site-packages/jose/jwt.py", line 172, in decode
options=defaults)
File "/venv/lib/python3.5/site-packages/jose/jwt.py", line 495, in _validate_claims
_validate_aud(claims, audience=audience)
File "/venv/lib/python3.5/site-packages/jose/jwt.py", line 357, in _validate_aud
raise JWTClaimsError('Invalid audience')
jose.exceptions.JWTClaimsError: Invalid audience
`

checking authority/permissions on a resource

Just a question I guess from glancing at the code a bit.

In the example for:
keycloak_openid.get_permissions(...)

Does it perform keycloak permission check against the defined resources using permission argument of the rest api, as per the docs, like this:

https://www.keycloak.org/docs/latest/authorization_services/index.html#_service_obtaining_permissions
...
curl -X POST \ http://${host}:${port}/auth/realms/${realm}/protocol/openid-connect/token \ -H "Authorization: Bearer ${access_token}" \ --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \ --data "audience={resource_server_client_id}" \ --data "permission=Resource A#Scope A" \ --data "permission=Resource B#Scope B"

OR

Is it looking at the permissions as taken from the json file that was given from authorizations export to json file in the admin console of keycloak?

I think it may be the second one, and maybe it is not using the rest api.
In that case, if the admin has changed roles or any policy config, the file contents would be stale, plus we're storing details about the resource server locally in the client which seems less than ideal.

If it is like the second one, would it make sense to provide a permission check function that will do the rest api call to keycloak to validate the user is allowed, rather than relying on a file?

thx for providing this free code! I'm just playing around with it a bit.

Added UserRepresentation class object easy to initialize

Is possible to implement a simple UserRepresentation?

Like this class:

#
class UserRepresentation(object):
    """This objects represents the KeyCloak User .

    :Parameters:
      - `username`:
      - `password`:
      - `firstname`:
      - `lastname`:
      - `email`:
      - `isEditAttributeEnabled`:
      - `isEditCredentialsEnabled`:
      - `attributes`:
    """
    #
    def __init__(self, email='', firstname='', lastname='', password='', username = None ):
        self.username                   	= email if not username else username
        self.password                   	= password
        self.firstname                  	= firstname
        self.lastname                   	= lastname
        self.email                     		= email
        self.isEditAttributeEnabled     	= True
        self.isEditCredentialsEnabled   	= True
        self.isEditRequiredActionsEnabled   	= False
        self.attributes                     	= dict()
        self.requiredActions                	= []
    #
    def __str__(self):
        data = unidecode.unidecode('''{
                "username": "%s",
                "email": "%s",
                "totp": false,
                "emailVerified": "true",
                "firstName": "%s",
                "lastName": "%s",
                "enabled": true,
                "realmRoles": [
                    "offline_access", "uma_authorization"
                ],
                "clientRoles": {
                    "realm-management": [
                        "view-clients"
                    ]
                }
                ''' % (self.username, self.email, self.firstname, self.lastname))
        if self.isEditAttributeEnabled:
            data += ''',
            "attributes":  { '''
            for key,value in self.attributes.items():
                    data += '''"%s": ["%s"],'''%(key,value)
            data = data[:-1]+'}'
        if self.isEditRequiredActionsEnabled:
            data += ''',
            "requiredActions" :[ '''
            for action in self.requiredActions:
                data += '''"%s",'''%(action)
            data = data[:-1]+''']'''

        if self.isEditCredentialsEnabled:
            data += ''',
            "credentials": [
                    {
                        "type": "password",
                        "temporary": "false",
                        "value": "%s"
                    }
                ]'''% (self.password)
        data += '}'
        return data
    #
    def addAttribute(self, key, value):
        self.attributes[key]= value
    #
    def terror(self, status, code, message):
        result = {}
        result['status'] = status
        result['code'] = code
        result['message'] = message
        return result
    #
#

0.19.0 Release is broken because of changes to raw delete

Problem commit: #56

Every instance of raw delete in KeycloakAdmin where the data parameter is not explicitly passed to raw_delete is now broken thanks to this change. There are 5 methods that are broken as a result of this commit:

delete_client_role
delete_user
group_user_remove
delete_group
delete_client

Calling any of them will get you this error message:

TypeError: raw_delete() missing 1 required positional argument: 'data'

@gitfrosh

This can be fixed simply by making data an optional argument instead of a required one.

Mismatch in GroupRepresentation and implementation

In reference to the code per permalink:

path = payload['path']
- I see the link referenced to in the docstring is invalid and not reachable now.
Hence, docstring's need to be updated per support of the API's.

Now, In the keycloak documentation for group representation: https://www.keycloak.org/docs-api/5.0/rest-api/index.html#_grouprepresentation I see both Name and Path are optional but the implementation mandates both name and path in create_group. Is this expected?

Creating user return empty bytes

Hey guys,

I don't know if this is the issue with library or my keycloak setup. But when I am doing keycloak-admin.createuser(userrepresentation). I am getting null empty byte string.

Screen Shot 2020-02-16 at 3 51 14 AM

The first one was creating a existing user. I agree that it returns right id but creating new user is returning empty byte string. Am I missing anything?

KeycloakAdmin expired access_token

When KeycloakAdmin's access_token expires, call to the api will return KeylcoakAuthenticationError.

There is no easy way to refresh the token. Although you have refresh_token, the KeycloakOpenID instance used to get the access_token is not persisted. And thus it's refresh_token method is not available.

It would be nice to have a kind of "auto_refresh" feature that would retry the request with a refreshed token whenever the access_token expires.

Issue with "id:" in search parameter

Hi.

I'm seeing an issue when calling get_users with a search parameter that includes a colon. e.g.:
k.get_users({"search":"id:a4af3986-ff21-4978-b59d-a05ce4d58b14"})

According to the Java docs, this should be valid however it just hangs when I make the call. Accessing the url directly works fine. e.g.
http://localhost:8080/auth/admin/realms/my-realm/users/?search=id:a4af3986-ff21-4978-b59d-a05ce4d58b14

The relevant java doc is here : https://www.keycloak.org/docs-api/7.0/javadocs/org/keycloak/admin/client/resource/UsersResource.html#search-java.lang.String-java.lang.Integer-java.lang.Integer-

I'm using python-keycloak==0.19.0 and Python==3.6.8

KeycloakAdmin can't connect to realm

Connecting to the master realm work:

k=KeycloakAdmin(server_url="http://keycloak.dev.local:9000/auth/",username='admin',password='Pa55w0rd',verify=False)
But can't connect to a specific realm:
k=KeycloakAdmin(server_url="http://keycloak.dev.local:9000/auth/",username='admin',password='Pa55w0rd',verify=False, realm_name="myrealm")

return

keycloak.exceptions.KeycloakAuthenticationError: 401: b'{"error":"invalid_grant","error_description":"Invalid user credentials"}'

Stale state causing KeycloakAuthenticationError for admin access? Works on restart of flask application

Hi,
I'm using the KeycloakAdmin object to access the Admin API. It consistently fails after a few hits giving an KeycloakAuthenticationError. On restarting my app, the error goes away only to return after a while. My code is

keycloak_admin_api = KeycloakAdmin(server_url=keycloak_config['keycloak_url'],
                                   username=keycloak_config['keycloak_admin'],
                                   password=keycloak_config['keycloak_password'],
                                   verify=True)
...

 keycloak_admin_api.get_user(user_id)

giving the error:

...
   owner = keycloak_admin_api.get_user(custom_id)
  File "/Users/rabraham/Documents/dev/fifteenrock/compute/venv/lib/python3.6/site-packages/keycloak/keycloak_admin.py", line 247, in get_user
    return raise_error_from_response(data_raw, KeycloakGetError)
  File "/Users/rabraham/Documents/dev/fifteenrock/compute/venv/lib/python3.6/site-packages/keycloak/exceptions.py", line 102, in raise_error_from_response
    response_body=response.content)
keycloak.exceptions.KeycloakAuthenticationError: 401: b''

Note: I'm running this within a flask application with incremental hot loading. I didn't have this problem before if I remember correctly. I'm on jboss/keycloak:4.1.0.Final image.

logout does not work: "Some clients have been not been logged out for user ..."

   from keycloak import KeycloakOpenID

    keycloak_openid = KeycloakOpenID(server_url="http://<my IP>:8080/auth/",
                        client_id="<client_id>",
                        realm_name="<my realm name>",
                        client_secret_key="<my secret>",
                        verify=True)
    config_well_know = keycloak_openid.well_know()
    token = keycloak_openid.token("<username>", "<password>")
    print(token) # all tokens returned ok

    userinfo = keycloak_openid.userinfo(token['access_token'])
    print ("userinfo:", userinfo) # userinfo returned ok 

    keycloak_openid.logout(token['refresh_token'])

in the container log:
Some clients have been not been logged out for user <username> in <my realm name> realm: <client_id>
No logout happens, still can browse the site.

get_authentication_flows() gives 403: b'{"error":"unknown_error"}'

When trying to access authentication flows from keycloak, its giving me 403 error.
Although create_user() and get_users() are working fine, so I believe there is not problem with the connection.
Here are the logs:

File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/keycloak/keycloak_admin.py", line 1000, in get_authentication_flows
return raise_error_from_response(data_raw, KeycloakGetError)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/keycloak/exceptions.py", line 102, in raise_error_from_response
response_body=response.content)
keycloak.exceptions.KeycloakGetError: 403: b'{"error":"unknown_error"}'

grant_type bug in keycloak_admin.py

The following lines (1166 and 1167) in keycloak_admin.py:
if self.client_secret_key: grant_type = ["client_credentials"]

will cause an error when using a confidential client by forcing the client to obtain an access token outside of the context of the admin user (which is what a client_credentials grant type does)

Auto refresh does not work in case of stale refresh token

Steps to reproduce:

  1. Instantiate KeycloakAdmin with refresh token

  2. Login in the keycloak administration console

  3. Use the previously instantiated KeycloakAdmin

You should get an error:

400: b'{"error":"invalid_grant","error_description":"Stale refresh token"}'

The issue is within the refresh_token method. It only checks for expired token, not stale tokens:

if e.response_code == 400 and b'Refresh token expired' in e.response_body:

keycloak.exceptions.KeycloakGetError: 403: b'{"error":"unknown_error"}'

If i pass a dictionary like #77 with this method (inside the class):

def transform_to_dict(self):
    return json.loads( str( self ) )
#

    new_user    = keycloak_admin.create_user( fdata )
  File "/home/ies/.local/share/virtualenvs/fitwithme-backend-Jv2WLX8i/lib/python3.7/site-packages/keycloak/keycloak_admin.py", line 231, in create_user
    exists = self.get_user_id(username=payload['username'])
  File "/home/ies/.local/share/virtualenvs/fitwithme-backend-Jv2WLX8i/lib/python3.7/site-packages/keycloak/keycloak_admin.py", line 263, in get_user_id
    users = self.get_users(query={"search": username})
  File "/home/ies/.local/share/virtualenvs/fitwithme-backend-Jv2WLX8i/lib/python3.7/site-packages/keycloak/keycloak_admin.py", line 203, in get_users
    return self.__fetch_all(URL_ADMIN_USERS.format(**params_path), query)
  File "/home/ies/.local/share/virtualenvs/fitwithme-backend-Jv2WLX8i/lib/python3.7/site-packages/keycloak/keycloak_admin.py", line 148, in __fetch_all
    KeycloakGetError)
  File "/home/ies/.local/share/virtualenvs/fitwithme-backend-Jv2WLX8i/lib/python3.7/site-packages/keycloak/exceptions.py", line 102, in raise_error_from_response
    response_body=response.content)
keycloak.exceptions.KeycloakGetError: 403: b'{"error":"unknown_error"}'

Keycloak closes connection after 60s

By default Keycloak closes a connection unused for 60s (source: tomcat's documentation).

This is not an issue for the current release of python-keycloak since KeycloakAdmin and KeycloakOpendID are meant to be initialized each time you want to call Keycloak. By instantiating a new version of KeycloakAdmin/KeycloakOpendID, you are also initiating a new ConnectionManager thus a new requests.Session thus a new connection to Keycloak server.
To put it simply, python-keycloak does not take advantage of requests.Session's persistent connection.

That being said, If PR #32 is accepted, then only one instance of KeycloakAdmin/KeycloakOpendID is needed. The persistent connection is being used. But since Keycloak closes the connection after 60s of inactivity, we get a

'Connection aborted.', RemoteDisconnected('Remote end closed connection without response'

delete_client_roles_of_user and delete_client_role doesn't works well

delete_client_roles_of_user - deleting all mapping of specified user.

delete_client_role - It's complicated... While I tested delete methods on roles named as "awsdwasdwafreweqwd", everything is good... But, when i testing on true SAML 2.0 roles as "arn:aws:iam::533977602915:role/G-Federated-Admin,arn:aws:iam::533977602915:saml-provider/GoogleAppsTest", I getting keycloak.exceptions.KeycloakGetError: 404: b''. Its not metter how i created this roles, they are in the same containter, composite: false, clientRole: true.

Best regards, Gabriel

send_update_account throws KeycloakException: 204: b'' with Keycloak 10

Hi

i use send_update_account to let a user reset his/hers password.
My call looks like so: send_update_account(user_id, '["UPDATE_PASSWORD"]', client_id='MY_CLIENT_ID', redirect_uri='/whatever').

However, since i updated to Keycloak 10.0.1, the underlying HTTP-call returns with 204 instead of 200.
Which results in a KeycloakException.
I am pretty sure this wasnt a problem in Keycloak 9.

How do you use the client when Keycloak is running over https

When I run Keycloak in SSL mode when I try to use the client I don't see an option of passing in any certificates. When I try the https url anyways for keycloak I am getting a handshake error when I try to use KeycloakOpenID.

SSLError(SSLError("bad handshake: Error([('SSL routines', 'tls_process_server_certificate', 'certificate verify failed'

Admin in a different realm

Admin user can be outside of the realm, in another realm. In this case, the realm used for connection cannot be the same as the one used for realm administration.

You can have a realm called: myrealm but its administrator a user from master realm with appropriate roles on myrealm-realm client.

python-keycloak fails with keycloak 7.0.1

Dear Marcos,

I am using python-keycloak for setting up keycloak clients through python API. Recently, we switched from an old keycloak server (4.6.0) to a newer one (7.0.0). Since then, my script for setting up the client silently fails with an "403 unkown error". Here is my script:

import sys

from keycloak import KeycloakAdmin

if __name__ == "__main__":

    keycloak_admin = KeycloakAdmin(server_url="https://login.ill.fr/auth/",
                                   username="keycloak-user",
                                   password="blabla",
                                   realm_name="my-realm",
                                   verify=True)

    client_name = "test-client"
    client_ip = "192.168.13.207"
    client_port = "8080"

    visa_jupyter_client_id = keycloak_admin.get_client_id(client_name)
    if visa_jupyter_client_id:
        keycloak_admin.delete_client(visa_jupyter_client_id)

    _ = keycloak_admin.create_client({"clientId": client_name,
                                      "attributes":{"login_theme":"ill"},
                                      "name": client_name,
                                      "clientAuthenticatorType":"client-secret",
                                      "description":"my client",
                                      "consentRequired": False,
                                      "publicClient": False,
                                      "baseUrl": "/",
                                      "protocol":"openid-connect",
                                      "rootUrl":"http://%s:%s" % (client_ip,client_port),
                                      "redirectUris":["*"],
                                      "webOrigins":[],
                                      "adminUrl": "",
                                      "serviceAccountsEnabled": True,
                                      "enabled": True}, skip_exists=True)

    visa_jupyter_client_id = keycloak_admin.get_client_id(client_name)

    client_info = {"id":client_name, "secret":keycloak_admin.get_client_secrets(visa_jupyter_client_id)["value"]}

    print(client_info)

And here is the traceback I get when running that script with our newer keycloak server:

Traceback (most recent call last):
  File "get_client_new_api.py", line 36, in <module>
    "enabled": True}, skip_exists=True)
  File "/home/pellegrini/.local/lib/python3.6/site-packages/keycloak/keycloak_admin.py", line 686, in create_client
    return raise_error_from_response(data_raw, KeycloakGetError, expected_code=201, skip_exists=skip_exists)
  File "/home/pellegrini/.local/lib/python3.6/site-packages/keycloak/exceptions.py", line 102, in raise_error_from_response
    response_body=response.content)
keycloak.exceptions.KeycloakGetError: 403: b'{"error":"unknown_error"}'

Would you have any idea why this script turned to fail with keycloak v7.0.1 ?

Many thanks in advance for your help

EDIT: the following simpler example taken from the docs also fails with keycloak 7.0.1:

import sys

from keycloak import KeycloakAdmin

if __name__ == "__main__":

    keycloak_admin = KeycloakAdmin(server_url="https://login.ill.fr/auth/",
                                   username="keycloak-user",
                                   password="blabla",
                                   realm_name="my-realm",
                                   verify=True)

    print(keycloak_admin.users_count())

Where is the client_secret_key coming from?

I have this basic code

from keycloak import KeycloakAdmin

keycloak_admin = KeycloakAdmin(server_url="http://localhost:8080/auth/",
                               username='admin',
                               password='admin',
                               realm_name="master",
                               client_secret_key="client-secret",
                               verify=True)

Where can I find/set the client_secret_key in Keycloak?

License headers in some files indicate LGPL instead of MIT

Hi,

I found your library and it is quite handy. Thanks for providing that!

After cursory looking through the code base I found two files [1,2] that have a LGPL instead of an MIT header. Is this intended? If so what is the reason behind that? If there is no special reason for having this, would it be possible to adjust the headers to the project license (MIT)?

The reason I am asking is that we would like to use your library for our project [3], which is EPL 2.0 licensed and would have a clash in the licensing conditions.

[1] https://github.com/marcospereirampj/python-keycloak/blob/master/keycloak/__init__.py
[2] https://github.com/marcospereirampj/python-keycloak/blob/master/keycloak/authorization/__init__.py
[3] https://www.eclipse.org/kuksa/

ValueError: Could not deserialize key data.

keycloak 10, python-keycloak 0.20.0, python 3.7

from keycloak import KeycloakOpenID

# Configure client
keycloak_openid = KeycloakOpenID(server_url="https://path/to/my/server", client_id="ocfapi", realm_name="ocf", client_secret_key="my-secret-key")

# Get WellKnow
config_well_know = keycloak_openid.well_know()

# Get Token
token = keycloak_openid.token("username", "password")

print(token)
print(type(token))

# error happens somewhere after here

KEYCLOAK_PUBLIC_KEY = keycloak_openid.public_key()
options = {"verify_signature": True, "verify_aud": True, "exp": True}
token_info = keycloak_openid.decode_token(token['access_token'], key=KEYCLOAK_PUBLIC_KEY, options=options)

print(token_info)

Gives the error...

Traceback (most recent call last):
  File "/lib/python3.7/site-packages/jose/backends/cryptography_backend.py", line 236, in __init__
    self.prepared_key = load_pem_public_key(key, self.cryptography_backend())
  File "/lib/python3.7/site-packages/cryptography/hazmat/primitives/serialization/base.py", line 20, in load_pem_public_key
    return backend.load_pem_public_key(data)
  File "/lib/python3.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1077, in load_pem_public_key
    self._handle_key_loading_error()
  File "/lib/python3.7/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1335, in _handle_key_loading_error
    raise ValueError("Could not deserialize key data.")
ValueError: Could not deserialize key data.

Setting "verify_signature": False makes this work as expected.

Get user roles as client (without using admin authentication)

I'm trying to create a client that checks if a user has access to a specific resource.

# Configure client
keycloak_openid = KeycloakOpenID(server_url="http://localhost:8080/auth/",
                    client_id="example_client",
                    realm_name="example_realm",
                    client_secret_key="secret")

# Get Token
token = keycloak_openid.token("user", "password")

# check resource permissions - 
# not sure how to do this
if SOME_ROLE in keycloak_openid.user_roles(token):
    we_have_permissions_to_access_this_yay()

I don't want to give these clients admin credentials thru KeycloakAdmin when they don't need it. It seems like this is a basic use case for keycloak clients so I feel like we could make it a bit easier.

Bad token when initiating connection to Keycloak

During the first phase of connection with Keycloak, le token generated isn't working. It is a small token who generate a 403 error (forbidden) when trying to use to make a request.

Example of the error :

image

When using the generated token (in Postman for example), we get the following error :
image

Origin of the problem :

In the __init__ function of the KeycloakAdmin class, the following actions are executed :

  • Creation of a connexion with OpenIdConnect
  • Asking for a token
  • Creation of a connection with the previously generated token

image

When debug, I noticed that the token fetched at this moment is the non working token.
However, if I reproduce the same steps after the initialization of the KeycloakAdmin class the newly generated token is working just fine :

image

image

Temporary solution :

For now I'm working with this dirty solution (and it works fine) but it's definitely not the right way to do it. Any advice on a better way to avoid the problem ? Is it a bug inherit to this module ?

image

Add support for get_user_groups_count

No support for this API. My implementation follows:

from urls_patterns.py:

URL_ADMIN_USER_GROUP_COUNT = "admin/realms/{realm-name}/users/{id}/groups/count"

from keycloak_admin.py:

from .urls_patterns import URL_ADMIN_SERVER_INFO, URL_ADMIN_CLIENT_AUTHZ_RESOURCES, URL_ADMIN_CLIENT_ROLES,
URL_ADMIN_GET_SESSIONS, URL_ADMIN_RESET_PASSWORD, URL_ADMIN_SEND_UPDATE_ACCOUNT,
URL_ADMIN_USER_CLIENT_ROLES_COMPOSITE, URL_ADMIN_USER_GROUP, URL_ADMIN_REALM_ROLES, URL_ADMIN_GROUP_CHILD,
URL_ADMIN_USER_CONSENTS, URL_ADMIN_SEND_VERIFY_EMAIL, URL_ADMIN_CLIENT, URL_ADMIN_USER, URL_ADMIN_CLIENT_ROLE,
URL_ADMIN_USER_GROUPS, URL_ADMIN_CLIENTS, URL_ADMIN_FLOWS_EXECUTIONS, URL_ADMIN_GROUPS, URL_ADMIN_USER_CLIENT_ROLES,
URL_ADMIN_REALMS, URL_ADMIN_USERS_COUNT, URL_ADMIN_FLOWS, URL_ADMIN_GROUP, URL_ADMIN_CLIENT_AUTHZ_SETTINGS,
URL_ADMIN_GROUP_MEMBERS, URL_ADMIN_USER_STORAGE, URL_ADMIN_GROUP_PERMISSIONS, URL_ADMIN_IDPS,
URL_ADMIN_USER_CLIENT_ROLES_AVAILABLE, URL_ADMIN_USERS, URL_ADMIN_CLIENT_SCOPES,
URL_ADMIN_CLIENT_SCOPES_ADD_MAPPER, URL_ADMIN_CLIENT_SCOPE, URL_ADMIN_CLIENT_SECRETS,
URL_ADMIN_USER_REALM_ROLES, URL_ADMIN_USER_GROUP_COUNT

def get_user_group_count(self, user_id):
    """
    Returns a number of groups of which the user is a member

    :param user_id: User id

    :return: count of groups user is member of
    """
    params_path = {"realm-name": self.realm_name, "id": user_id}
    data_raw = self.raw_get(URL_ADMIN_USER_GROUP_COUNT.format(**params_path))
    return raise_error_from_response(data_raw, KeycloakGetError)

create_user returns ID instead or UserRepresentation

According to the docs

def create_user(self, payload):
"""
Create a new user. Username must be unique
UserRepresentation
https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_userrepresentation
:param payload: UserRepresentation
:return: UserRepresentation
"""
params_path = {"realm-name": self.realm_name}
exists = self.get_user_id(username=payload['username'])
if exists is not None:
return str(exists)
data_raw = self.raw_post(URL_ADMIN_USERS.format(**params_path),
data=json.dumps(payload))
raise_error_from_response(data_raw, KeycloakGetError, expected_code=201)
_last_slash_idx = data_raw.headers['Location'].rindex('/')
return data_raw.headers['Location'][_last_slash_idx + 1:]
UserRepresentation should be returned, in fact it is the users ID, in both cases for existing and new users.

Cannot add user to group

I've set-up an instance of keycloak 6, and I've been able to create users, but I'm not able to add the user to any group. I've looked at the rest API from keycloak, and the next code does not return any error, but it seems to do nothing:

new_user = keycloak_admin.create_user({"email": "[email protected]", "username": "testing", "enabled": True, "firstName": "Example", "lastName": "Example", "groups": ['87ce8237-7b0b-4437-b302-8e1404f4b799']})

Also tried:

update = keycloak_admin.update_user(user_id="a1e52cbd-99cd-46c2-8cbe-f34fa9d16e81",payload={'groups': ['87ce8237-7b0b-4437-b302-8e1404f4b799'],'enabled': False})

The user gets disable, so the update works, but it does not get added to the group.

Gotta remark, everything else works perfectly, and when I submit this also seems to work, no errors. I tried also the group name instead of ID but it does not work either.

Documentation on disabling ssl checks

I have tried disabling ssl checks in order to test the library in a development setting.
In particular, using
https://stackoverflow.com/questions/35875298/python-3-urllib-with-self-signed-certificates
I tried various variations of
ssl._create_default_https_context = ssl._create_unverified_context
at initialization, but I still get the same SSL error:
HTTPSConnectionPool(host='a.b.c.d', port=8443): Max retries exceeded with url: /auth/realms/REALM/.well-known/openid-configuration (Caused by SSLError(SSLError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:847)'),))

Can you add some documentation regarding this?

I have also created an issue at django-keycloak; please coordinate with django-keycloak as appropriate.
Peter-Slump/django-keycloak#21

Thank you.

keycloak_openid.decode_token fails if user has client role assigned

Hi, I'm facing the problem, that keycloak_openid.decode_token() fails to decode my token if I assign any client role to my user. Without any client role assigned, everything works fine, but if I assign e.g. "view-clients" or "realm-admin", decode fails with "Invalid audience".

here is the corresponding line of code:

token_info = keycloak_openid.decode_token(token, keycloak_openid.certs(),algorithms=['RS512'])

Debug info:
Exception: Invalid audience

Unable to perform any actions on any other realm other than admin

As KeycloakAdmin class is tied to KeycloakOpenID to perform any action, and instantiation of keycloak_openid object consumes the keycloakadmin attributes, an admin from master realm cannot perform any action in any other realm.

The solution would be to accept separate parameter action_realm_name in KeycloakAdmin class that would be then used as path parameter realm_name instead of the realm_name(master) that is used to retrieve accesstoken from keycloak_openid object.

add support for paging in get_users

The current implementation only supports retrieving all users, even though you have optional first and max parameters that are essentially ignored.
My keycloak has > 50,000 users and I can't block as the call returns all users. My changes follow:

#
def __fetch_page(self, url, query):
    ''' NEW: Wrapper function for *real* paginated GET requests
    '''
    results = []

    # initalize query if it was called with None
    if not query:
        return results

    results = raise_error_from_response(
            self.raw_get(url, **query),
            KeycloakGetError)
    return results

def get_users(self, query=None):
    """
    Return a list of users, filtered according to query parameters

    UserRepresentation
    https://www.keycloak.org/docs-api/8.0/rest-api/index.html#_userrepresentation

    :param query: Query parameters (optional)
    :return: users list
    """
    params_path = {"realm-name": self.realm_name}

    if query != None and 'max' in query:
        return self.__fetch_page(URL_ADMIN_USERS.format(**params_path), query)
    else:
        return self.__fetch_all(URL_ADMIN_USERS.format(**params_path), query)

Keycloak Release Version Targeting

This is a general question with regards to keycloak release versions.

What version(s) is this api wrapper targetting?

I am currently working with resources, policies, permessions in authorization (ABAC)

I understand that this currently isnt implemented in this api wrapper, but also understand that these may be new additions to keycloak.

Are there any plans to test against specific versions of keycloak, or have a release process in line with API changes/additions in keycloak?

Error Handling

Hello, I'm currently using python-keycloak, but I cannot find any documentation about error handling. I've tried: try: ... except keycloak.KeycloakGetError: print (keycloak.KeycloakGetError)

But the error is not specified.

Keycloak 4.5 user password set error

Hi, since I was working with Keycloak 4.4 my python script works, but with KC 4.5 : Traceback (most recent call last): File "./KC_CreateFakeUsers.py", line 25, in password = keycloak_admin.set_user_password(user_id="stress"+str(x), password="secret", temporary=False) File "/usr/local/lib/python3.6/dist-packages/keycloak/keycloak_admin.py", line 233, in set_user_password return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204) File "/usr/local/lib/python3.6/dist-packages/keycloak/exceptions.py", line 93, in raise_error_from_response response_body=response.content) keycloak.exceptions.KeycloakGetError: 404: b''

Is there a change in KC 4.5 api url ?

Bug: Cannot delete user using KeycloakAdmin.delete_user

When using function delete_user from keycloak_admin (keycloak_admin.py::382), no data parameter is provided to raw_delete, which leads to a runtime error.

Please, change keycloak_admin.py::382 line to:

data_raw = self.raw_delete(URL_ADMIN_USER.format(**params_path), data = dict())

This will fix the problem.

Best regards

realmRoles doesn't work

I tried to in the admin client create a new user with role "admin". Client creates user but does not assign the realm role at all.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    馃枛 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 馃搳馃搱馃帀

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google 鉂わ笍 Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.