I'm using keycloak python API to assign user roles. Here is the code:
from keycloak import KeycloakAdmin
# make connection
admin = KeycloakAdmin(server_url = "https://xxx.xx.xx/auth/",
username = 'xx',
password = 'xxx',
realm_name = "xxx-xxx",
verify = True)
# get an user id via user name
userID = admin.get_user_id(self.userName)
# assign user role
admin.assign_client_role(client_id = "client_id",
user_id = userID,
#role_id = "role_id",
role_name = "test")
The make connection and get user id via user name part is successful. But assign_client_role() gives me an error:
TypeError: assign_client_role() got an unexpected keyword argument 'role_name'
It seems that the arguments are not corrsponding to those defined in the function. My code refers to the example from this website.
Could anyone tell me how to make it right?
Had the same problem. It turns out that the documentation for python-keycloak is not correct. Here's how I managed to fix the issue
First, make sure you're using client_id from url not the client id from keycloak interface (see picture):
client_id picture
Second, make sure your admin user has manage-users and manage-clients roles assigned to it:
roles picture
Third, assign_client_role() accepts argument role_name as an array, not string
Here's my code:
keycloak_admin = KeycloakAdmin(server_url="http://localhost:8088/auth/",
username='azat_admin',
password='some_password',
realm_name="realm_name",
verify=True)
new_user = keycloak_admin.create_user({"email": "some_email",
"username": "some_username",
"enabled": True,
"firstName": "some_firstname",
"lastName": "some_lastname",
"credentials": [{"value": "some_password","type": "password",}]})
roles = keycloak_admin.get_client_roles(client_id="2b50a8e3-dc91-4658-a552-83fb768badc8")
keycloak_admin.assign_client_role(client_id = "2b50a8e3-dc91-4658-a552-83fb768badc8",
user_id = new_user,
roles=[roles[0]])
Wang.
Another option is this:
from keycloak import KeycloakAdmin
# make connection
admin = KeycloakAdmin(server_url = "https://xxx.xx.xx/auth/",
username = 'xx',
password = 'xxx',
realm_name = "xxx-xxx",
verify = True)
# get an user id via user name
user_id = admin.get_user_id("username")
role = admin.get_client_roles(client_id="client_id", role_name="test")
# assign user client role
admin.assign_client_role(client_id = "client_id",
user_id = user_id,
roles=[role])
I will fixe de documentation about that.
The new oficial repository is "python-keycloak".
As stated in example documentation. You should certainly try first:
# Get client role id from name
role_id = keycloak_admin.get_client_role_id(client_id=client_id, role_name="test")
then
# Assign client role to user. Note that BOTH role_name and role_id appear to be required.
keycloak_admin.assign_client_role(client_id=client_id, user_id=user_id, role_id=role_id, role_name="test")
Or can you share more of your code and explain why you commented the 'role_id' argument?
It turns out that the documentation is wrong, I check the source code of keycloak_admin.py found the definition of function assign_client_role():
def assign_client_role(self, user_id, client_id, roles):
"""
Assign a client role to a user
:param client_id: id of client (not client-id)
:param user_id: id of user
:param client_id: id of client containing role,
:param roles: roles list or role (use RoleRepresentation)
:return Keycloak server response
"""
payload = roles if isinstance(roles, list) else [roles]
params_path = {"realm-name": self.realm_name, "id": user_id, "client-id":client_id}
data_raw = self.connection.raw_post(URL_ADMIN_USER_CLIENT_ROLES.format(**params_path),
data=json.dumps(payload))
return raise_error_from_response(data_raw, KeycloakGetError, expected_code=204)
The URL_ADMIN_USER_CLIENT_ROLES is defined in urls_patterns.py:
URL_ADMIN_USER_CLIENT_ROLES = "admin/realms/{realm-name}/users/{id}/role-mappings/clients/{client-id}"
As you can see, the realm-name, userid and client-id is used to form the url, if one of these parameters goes wrong, there will be 404 error because of the incorrect url. Content of parameter roles is warpped into post data, so if the format of roles parameter is wrong, there will probably be 500 error.
In order to get the right url example and the correct roles data structure, I used browser to manually assign a role, and check the url and post json data sent by the browser. Then change the code to produce the correct url and json data. Below is the final code that works:
from keycloak import KeycloakAdmin
# make connection
admin = KeycloakAdmin(server_url = "https://xxx.xx.xx/auth/",
username = 'xx',
password = 'xxx',
realm_name = "xxx-xxx",
verify = True)
# get user id
userID = admin.get_user_id('one user's name')
# make sure you have the right realm name
realmName = 'xxx-xxx'
clientID = admin.get_client_id(realmName)
admin.assign_client_role(user_id = userID,
client_id = clientID,
roles = [{"id":"34a02t60-2435-40da-v911-a3ee1xm58921",
"name":"USER",
"description":"xxxxx",
"composite":False,
"clientRole":True,
"containerId":"aa102d71-4jk1-4u2a-a8w4-a6cv5j7626i1"}])
Related
How can I get UserId for AWS SSO Users using Boto3.
I wanted to use it to assign permissions to a user for a specific aws account using below code, however, this requires PrincipalId which is some 16-20 digit number associated with each user and is called User ID in the AWS console.
You can read about it - here
response = client.create_account_assignment(
InstanceArn='string',
TargetId='string',
TargetType='AWS_ACCOUNT',
PermissionSetArn='string',
PrincipalType='USER'|'GROUP',
PrincipalId='string'
)
If you have the UserName for the user you'd like to assign permissions for, you can programmatically use IAM to determine that user's UserId:
import boto3
# Get the UserId.
user_name = 'the user name here'
iam_client = boto3.client('iam')
result = iam_client.get_user(UserName=user_name)
user_id = result['User']['UserId']
# Assign permissions to the UserId.
sso_admin_client = boto3.client('sso-admin')
response = sso_admin_client.create_account_assignment(
InstanceArn='string',
TargetId='string',
TargetType='AWS_ACCOUNT',
PermissionSetArn='string',
PrincipalType='USER',
PrincipalId=user_id
)
You'll also need to use the 'identitystore' to get user or group IDs. Try this from the docs -
import boto3
client = boto3.client('identitystore')
response = client.get_user_id(
IdentityStoreId='string',
AlternateIdentifier={
'ExternalId': {
'Issuer': 'string',
'Id': 'string'
},
'UniqueAttribute': {
'AttributePath': 'string',
'AttributeValue': {...}|[...]|123|123.4|'string'|True|None
}
}
)
Although I personally found that the above method didn't work for me due to it not being available in my installed version of Boto3, so I did this instead which worked perfectly -
import boto3
client = boto3.client('identitystore')
response = client.list_users(
IdentityStoreId='string',
Filters=[
{
'AttributePath': 'UserName',
'AttributeValue': 'string'
},
]
)
print(response["Users"][0]["UserId"])
Sources:
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/identitystore.html#id24
https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/identitystore.html#IdentityStore.Client.get_user_id
https://botocore.amazonaws.com/v1/documentation/api/latest/reference/services/identitystore.html#IdentityStore.Client.list_users
I have setup AWS Lambda function that is triggered on an AWS Cognito. The trigger on a successful email confirmation. The Lambda function is in Python3.6.
I am referring to the AWS documentation for Cognito postConfirmation trigger.
https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-post-confirmation.html
"response": {}
So far I have tried returning None, {}, '{}'(empty json string) or valid dictionary like {'status':200, 'message':'the message string'} but it is giving error.
botocore.errorfactory.InvalidLambdaResponseException: An error occurred (InvalidLambdaResponseException) when calling the ConfirmSignUp operation: Unrecognizable lambda output
What should be a valid response for the post confirmation function?
here is the part of code.
from DBConnect import user
import json
def lambda_handler(event, context):
ua = event['request']['userAttributes']
print("create user ua = ", ua)
if ('name' in ua):
name = ua['name']
else:
name = "guest"
newUser = user.create(
name = name,
uid = ua['sub'],
owner = ua['sub'],
phoneNumber = ua['phone_number'],
email = ua['email']
)
print(newUser)
return '{}' # <--- I am using literals here only.
You need to return the event object:
return event
This is not obvious in the examples they provide in the documentation. You may want to check and ensure the event object does contain a response key (it should).
I am trying to get emails from users on slack. All of the user id's come from channels.info, this also includes bot user id's. When I run users.info to see the info for all the users in the channel, it won't let me get emails because the bot user's which are also passed through the API don't have an email field.
def get_users():
url = 'https://slack.com/api/users.info'
headers = {'Accept': 'application/x-www-form-urlencoded'}
users = get_channel()
result = []
for user in users:
payload = {
'token': API_KEY,
'user': user
}
r = requests.get(url, headers=headers, params=payload)
if r.status_code == 200:
result.append(r.json()['user']['profile']['email])
return result
I am currently getting a KeyErorr with'email' because the bot users don't have an email field. Is there a way to ignore the bot user's all together. Currently all the user id's are taken from channels.info and looped through users.info, so the info is gathered for each user id from channels.info
To avoid the exception on the client side, you can use dictionary.get() to have it return None instead of throwing a KeyError.
email = r.json()['user']['profile'].get('email')
if email is not None:
result.append(email)
There is some more detail about dictionary.get() in this question and it's answers: Why dict.get(key) instead of dict[key]?
I am not sure how exactly you are retrieving the list of users for a channel (are you calling conversations.members?).
But anyways there is no way to preselect to only receive user and not bots in any of the API methods.
But the user object you get from a user.info contains the field is_bot, which you could check in your loop.
I need to get the current user id.
In Javascript I use this to obtain the id
uid = firebase.auth().currentUser.uid // uid= ABO0Xc2E6KSDodEhenICkXF371x1
how do I get the uid in python
?
This is the code to retrieve the user id without login or signup.
auth.current_user['localId']
user = auth.sign_in_with_email_and_password(email,password)
print(user['localId'])
this will display the current firebase UID on output screen
You didn't mention a library, but all your other questions are using Pyrebase, so skimming over the documentation (which you should definitely be reading)...
# Get a reference to the auth service
auth = firebase.auth()
# Log the user in
user = auth.sign_in_with_email_and_password(email, password)
# Get the user's idToken
token = user['idToken']
Resurfacing an old question, but looking in to the documentation of Pyrebase here, I noticed that when you refresh the token, the userId is (compared to the other auth functions) retreived. So my solution is:
user = auth.sign_in_with_email_and_password("email", "pass")
user = auth.refresh(user['refreshToken'])
print(user['userId'])
EDIT:
I now see there is a 'localId' variable in the user object even before refreshing - as #Abdul indicated.
we would like to use parse to track our user's scores in our kivy app. Our app requires an encoded secure login so when we try to link the User's parse information (e.g., objectId, username, etc) to their score we get the following error: parse_rest.core.ResourceRequestLoginRequired: save requires a logged-in session
This message is thrown by line 26 in the parse_rest user.py. Our current code attempts to feed parse the sessionToken but it doesn't work for some reason. Please help us figure out how to get this code to work:
main.py (Note: our session token is identified and set to equal 'sessionToken' in our LoginScreen class. we know this works because we can use 'print LoginScreen.sessionToken' to print the session token when executing a method in any of the app's classes)
def game_score(self):
userScore = User(score="")
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/users/objectId', userScore.save(),
{"X-Parse-Application-Id": "Parse_app_id",
"X-Parse-REST-API-Key": "Parse_rest_API_key",
"X-Parse-Session-Token": LoginScreen.sessionToken})
gameScore = GameScore(score='user_score_pulled_from_game_screen')
gameScore.save()
User.score = gameScore
import json,httplib
connection = httplib.HTTPSConnection('api.parse.com', 443)
connection.connect()
connection.request('PUT', '/1/users/objectId', userScore.save(),
{"X-Parse-Application-Id": "Parse_app_id",
"X-Parse-REST-API-Key": "Parse_rest_API_key",
"X-Parse-Session-Token": LoginScreen.sessionToken})
pass
As an fyi, the code structure we're using comes from the "updating users" section of the Parse documentation: https://parse.com/docs/rest
thanks in advance
This can be accomplished using ParsePy, creating a One-to-One relationship between User and GameScore. The login function will prevent the ResourceRequestLoginRequired error you received. Furthermore, with this method, no session token is required.
def update_game_score(self):
user = User.login(<username>, <password>)
gameScore = GameScore(score='user_score_pulled_from_game_screen')
gameScore.save()
user.gameScores = gameScore
user.save()
Actually, after some work we came to a more robust solution that directly ties a gameScores column in the User table to the gameScore table:
def update_game_score(self):
user = User.login(username, password)
try:
user.gameScores
except AttributeError:
gameScore = GameScore(TotalScore=self.manager.get_screen('game_home_screen').score)
gameScore.save()
user.gameScores = gameScore
user.save()
else:
gameScore = user.gameScores
gameScore.TotalScore += self.manager.get_screen('game_home_screen').score
gameScore.save()
The approach for how to do this comes from the Users section of the ParsePy documentation: https://github.com/dgrtwo/ParsePy