
Product
Announcing Socket Fix 2.0
Socket Fix 2.0 brings targeted CVE remediation, smarter upgrade planning, and broader ecosystem support to help developers get to zero alerts.
Python module to automate Keycloak or Red Hat Single Sign-On (RHSSO) configuration.
pip install kcapi
To run the test you would need a Keycloak instance, you can run one locally or in the cloud then you just have to follow this steps:
python3.10 -m venv .venv
source .venv/bin/activate
pip install requests
# Setup SSO server - go to https://developers.redhat.com/developer-sandbox/get-started,
# launch sandbox environment, +Add, select some "Red Hat Single Sign-On..." template.
export KC_USER=admin
export KC_PASSWORD=admin_password
export KC_REALM=myrealm # do not use master realm, it cannot be removed
export KC_ENDPOINT=https://my-first-sso-me-me-dev.apps.sandbox.x8i5.p1.openshiftapps.com
python -m unittest
This class takes care of OpenID login using password owner credentials flow.
from rhsso import OpenID
oid_client = OpenID({
"client_id": "admin-cli",
"username": USER,
"password": PASSWORD,
"grant_type":"password",
"realm" : "master"
}, endpoint)
password
).https://my_keycloak.com
.This will initiate a session with the Keycloak server and will return a OpenID token back.
oid_client.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA
This static method should be used in order to access the master Realm in Keycloak.
oidc = OpenID.createAdminClient(self.USER, self.PASSWORD)
oidc.getToken() #glTeDLlmmpLYoAAUMcFQqNOMjw5dA
This class builds all the Keycloak configuration REST resources by using REST conventions we can target the majority of Keycloak services.
kc = Keycloak(token, self.ENDPOINT)
The constructor takes two parameters:
https://my_keycloak.com
.This methods build a REST client (capabilities detailed below) targeting a specific Keycloak REST resource.
groups = kc.build('groups', 'my_realm')
# Create a group called DC
state = groups.create({"name": "DC"}).isOk()
In this example we build the 'groups' API for
my_realm
Realm.
Here is a quick list of supported resources:
As long as you find a REST endpoint that follow the standard you can use this method to build a client around it, an example of this is the non well documented
components
endpoint.
components: This API allows you configure things like user federation or Realm keys.
authentication: Provide access to built-in and/or custom authentication flows.
Similar to the build
method but the client points to the master
realm, allowing us operation such as realm creation.
main_realm = kc.admin()
# Creates a realm called my_realm
main_realm.create({"enabled": "true", "id": my_realm, "realm": my_realm})
When you use the build
or admin
methods you will get back a REST class pointing to the Keycloak resource, keep in mind that this class don't check that the resource is valid, this is done to keep it flexible and to make it easy to adapt to new Keycloak REST API changes in the future.
In order to create one you need to build
method we have used before:
batman = {
"enabled":'true',
"attributes":{},
"username":"batman",
"firstName":"Bruce",
"lastName":"Wayne",
"emailVerified":""
}
users = kc.build('users', 'DC')
# Create a user called batman in DC
state = users.create(batman).isOk()
Following the example above lets see the methods we have starting with the usual CRUD methods:
This method POST
a dictionary into any given resource:
batman = {
"enabled":'true',
"attributes":{},
"username":"batman",
"firstName":"Bruce",
"lastName":"Wayne",
"emailVerified":""
}
state = users.create(batman).isOk()
This method performs a PUT
on the resource.
batman_update = {
"firstName":"Bruno",
"emailVerified": True
}
id = 'bf81a9d9-811f-4807-bd69-3d74eecbe9f4'
state = users.update(id, batman_update).isOk()
This method sends a DELETE
to the pointed resource.
batman_update = {
"firstName":"Bruno",
"emailVerified": True
}
id = 'bf81a9d9-811f-4807-bd69-3d74eecbe9f4'
state = users.remove(id).isOk()
Send a GET
request to retrieve a specific Keycloak resource.
id = 'bf81a9d9-811f-4807-bd69-3d74eecbe9f4'
user = users.get(id).response()
Return all objects of a particular resource type.
users = kc.build('users', 'DC')
# Create a user called batman in DC
user_list = users.all() # [ {id:'xxx-yyy', username: 'batman', ...} ]
Finds a resource by passing an arbitrary key/value pair.
users = kc.build('users', 'DC')
users.findFirst({"key":"username", "value": 'batman'})
Check if a resource matching the provided id
exists:
users = kc.build('users', 'DC')
id = 'bf81a9d9-811f-4807-bd69-3d74eecbe9f4'
users.exists(id) #True
Check if a resource matching the provided key/value pair, exists.
users = kc.build('users', 'DC')
users.existByKV("username", 'batman') #False
Each CRUD method returns a ResponseHandler
class with the following methods.
returns the requests response object.
users.update(id, batman_update).response().status_code #HTTP 201
Return True
if the request complete successfully otherwise it will raise an exception.
state = users.update(id, batman_update).isOk() # Return True here.
Does the same as isOk
but it allow you to chain more methods.
batman_update = {
"firstName":"Bruno",
"emailVerified": True
}
id = 'bf81a9d9-811f-4807-bd69-3d74eecbe9f4'
cookies = users.update(id, batman_update).verify().response().cookies # Get cookies.
This class handles the Keycloak caches.
# Creates a REST API instance target the Realms API.
realms = kc.build('realms', 'my_realm')
# Gets the cache Realms cache API.
caches = realms.caches(self.REALM)
This method tells Keycloak to clear the user cache.
caches.clearUserCache()
This method tells Keycloak to clear the realm cache.
caches.clearRealmCache()
This method tells Keycloak to clear the external public key cache for clients and identity providers.
caches.clearKeyCache()
For more information on how this caches works follow this link.
Update user credentials.
user_credentials = {
'temporary': False,
'value':'12345'
}
state = users.updateCredentials(user_info, user_credentials).isOk() # Updated user password.
Where:
True
provide a temporary password just for the first login.Add a user into a existing group.
First we need a group:
def createDCGroup():
group = kc.build('groups', 'heroes')
return group.create({"name": "DC"}).isOk()
Then we can join the group the following way:
createDCGroup()
users = kc.build('users', 'heroes')
user = {"key": "username", "value": "batman"}
group = {"key": "name", "value": "DC"}
users.joinGroup(user, group).isOk()
The API works by matching the first occurrence between the provided
key/value
for the two resources (User and Group), this can help in various situation for example if we want to target the user byuuid
.
Using uuid
as user identifier.
createDCGroup()
users = kc.build('users', 'heroes')
user = {"key": "uuid", "value": "23e4567-e89b-..."}
group = {"key": "name", "value": "DC"}
users.joinGroup(user, group).isOk()
Or we want to use the group id
:
user = {"key": "uuid", "value": "23e4567-e89b-..."}
group = {"key": "id", "value": "f8d91722-a1f0-45e..."}
users.joinGroup(user, group).isOk()
If the field criteria don't return a unique value, the first entry in the list will be used.
Remove a user from a group.
createDCGroup()
users = kc.build('users', 'heroes')
user = {"key": "username", "value": "batman"}
group = {"key": "uuid", "value": "123e4567-e89b-..."}
users.leaveGroup(user, group).isOk()
user = {"key": "uuid", "value": "12d3-a456-4"}
group = {"key": "id", "value": "123e4567-e89b-..."}
users.leaveGroup(user, group).isOk()
The same rules for
key/value
discussed above also applies here.
To manage the relationship between realm level roles and groups, we can use the RealmsRolesMapping.
To get an instance of this class you need to instantiate the group
resource class:
groups = kc.build('groups', 'heroes')
And use the method realmRoles
passing a valid group dictionary:
realmsRoles = groups.realmRoles({"key":"name", "value":'DC'})
Then we get a class with following methods:
Add a list of existing roles to a group.
def makeRoles(self):
roles = kc.build('roles', self.realm)
lvl1 = roles.create({"name": "level-1"}).isOk()
lvl2 = roles.create({"name": "level-2"}).isOk()
return lvl1 and lvl2
if makeRoles():
realmsRoles = groups.realmRoles({"key":"name", "value":'DC'})
realmsRoles.add(["level-1", "level-2"])
Remove a list of associated roles from a group.
realmsRoles = groups.realmRoles({"key":"name", "value":'DC'})
realmsRoles.remove(["level-1", "level-2"])
In Keycloak we can map roles to other roles, this method allow you to do just that.
role_watch = self.kc.build('roles', 'my-realm').find('watch')
added = role_watch.add_composite('view')
FAQs
A module to automate stuff in Keycloak.
We found that kcapi demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket Fix 2.0 brings targeted CVE remediation, smarter upgrade planning, and broader ecosystem support to help developers get to zero alerts.
Security News
Socket CEO Feross Aboukhadijeh joins Risky Business Weekly to unpack recent npm phishing attacks, their limited impact, and the risks if attackers get smarter.
Product
Socket’s new Tier 1 Reachability filters out up to 80% of irrelevant CVEs, so security teams can focus on the vulnerabilities that matter.