step1: keycloakをlocalhost:8080で起動する。
環境変数で管理者である"admin"のパスワードを"admin"に設定している
docker run -t --rm -p 8080:8080 -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin quay.io/keycloak/keycloak:21.0.2 start-dev --http-port=8080
step2: 以下のPythonを実行
- 最初にアクセストークンを取得
- 新しいrealmであるnewrealmを作成
- newrealmにuser1,user2,user3を追加、各ユーザーのパスワードとして"password"を設定
from typing import Dict, Optional
from urllib import parse, request, error
import os
import json
baseurl="http://localhost:8080"
email_domain="example.com"
def main():
code, res = req(
"/realms/master/protocol/openid-connect/token",
data_urlencoded={"username":"admin", "password":"admin", "grant_type":"password", "client_id":"admin-cli"}
)
token=res["access_token"]
realm="newrealm"
add_realm(realm, token)
for username in ["user1", "user2", "user3"]:
add_user(username, "password", realm, token)
def add_realm(realm, token):
return req(
"/admin/realms",
data_json={
"id": realm,
"realm": realm,
"displayName": "New Realm",
"enabled": True,
"sslRequired": "external",
"registrationAllowed": False,
"loginWithEmailAllowed": True,
"duplicateEmailsAllowed": False,
"resetPasswordAllowed": False,
"editUsernameAllowed": False,
"bruteForceProtected": True
},
headers=get_headers(token)
)
def add_user(username, password, realm, token):
return req(
"/admin/realms/{}/users".format(realm),
data_json={
"enabled":True,
"username":username,
"email":"{}@{}".format(username, email_domain),
"emailVerified":True,
"credentials":[{"type":"password","value":password,"temporary":False}]
},
headers=get_headers(token)
)
def get_headers(token):
return {
"Content-Type":"application/json",
"Authorization":"Bearer {}".format(token)
}
def req(url, data_json:Optional[Dict]=None, data_urlencoded:Optional[Dict]=None, headers:Optional[Dict]=None):
headers=headers or {}
data=None
if data_json:
data=json.dumps(data_json)
if data_urlencoded:
data=parse.urlencode(data_urlencoded)
url=baseurl+url
print('{} {} \n--data "{}"'.format(("POST" if data else "GET"), url, data), end=" ")
req = request.Request(url,data.encode('utf-8'),headers)
def defer(res):
code, data=res.getcode(), json.loads(res.read().decode("utf-8") or "{}")
print(code, data)
return code, data
try:
with request.urlopen(req) as res:
return defer(res)
except error.HTTPError as e:
return defer(e)
if __name__=="__main__":
main()
実行結果
POST http://localhost:8080/realms/master/protocol/openid-connect/token
--data "username=admin&password=admin&grant_type=password&client_id=admin-cli" 200 {'access_token': 'eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ0VE41WkdtSG5RTTBRd1FlQnhKR3JUMXN1dzN1QWdNNDduNUpKZ1FBQi1rIn0.eyJleHAiOjE2OTU
wOTMwNzAsImlhdCI6MTY5NTA5MzAxMCwianRpIjoiY2ZiMjAyNzEtZTQ4Mi00MDVkLWJmZDktMzdhNTYyZTE1YTYxIiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo5MDgwL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiIxZWFkYzQ0OC1lMTQzLTQ1NGItOTM5ZS1iYmQwNjA2OWJlYjEiLCJ0eXAiOiJCZWFyZXI
iLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoiMWE4MDI1NzktMGZhYi00OGQ1LThjM2UtMmI1ZjZiODJkYzM2IiwiYWNyIjoiMSIsInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsInNpZCI6IjFhODAyNTc5LTBmYWItNDhkNS04YzNlLTJiNWY2YjgyZGMzNiIsImVtYWlsX3ZlcmlmaWVkIjp
mYWxzZSwicHJlZmVycmVkX3VzZXJuYW1lIjoiYWRtaW4ifQ.eP0VXJ7TRq2uyelLbl50hDQL4kKf_7wzE9L_61qOBq1OUh_9M7LaFiLaV7TO6vS0KVd0oIalz18lSqC0ti0Z9LsFtlXq8SlGDYAtJ0Vcdx-JfDEg52zPzKF1lF8CdwvbGegA3O8vxKur6X6qwPW8bmp6GMGrYRXWiZ01EfkwMdbyY0PQDU2s
kN3KObe0iwPObZV5j05uT19gcsqQ-PyKL9wWUP98ipK8Q90lYlpTLWS5erJ1SUd0qTJWkEOYSJ3U46G6D0LuORzgpb9NKDg7eVgQYT7gdyUWayim4pimVgOx1KjiO2oMCssEmHexuGxJ_li021atgegDAjPiUHSSZQ', 'expires_in': 60, 'refresh_expires_in': 1800, 'refresh_token':
'eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJlZjg0YTkzOS1lODhmLTQ2M2EtOWJmMC1jMzhmM2Y5NzQxYmQifQ.eyJleHAiOjE2OTUwOTQ4MTAsImlhdCI6MTY5NTA5MzAxMCwianRpIjoiMDY0NzI2ZTktNjc5My00YjdkLTk3ZTYtMjU1ZTIzMWRlOWM4IiwiaXNzIjoiaHR0cDov
L2xvY2FsaG9zdDo5MDgwL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjkwODAvcmVhbG1zL21hc3RlciIsInN1YiI6IjFlYWRjNDQ4LWUxNDMtNDU0Yi05MzllLWJiZDA2MDY5YmViMSIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJhZG1pbi1jbGkiLCJzZXNzaW9uX3N0YXRlIjoi
MWE4MDI1NzktMGZhYi00OGQ1LThjM2UtMmI1ZjZiODJkYzM2Iiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwic2lkIjoiMWE4MDI1NzktMGZhYi00OGQ1LThjM2UtMmI1ZjZiODJkYzM2In0.KwswB_Adc887l3FN1pBmbYTumm6R1q6ManFjCTTfUis', 'token_type': 'Bearer', 'not-before-policy': 0, 'session_state': '1a802579-0fab-48d5-8c3e-2b5f6b82dc36', 'scope': 'email profile'}
POST http://localhost:8080/admin/realms
--data "{"id": "newrealm", "realm": "newrealm", "displayName": "New Realm", "enabled": true, "sslRequired": "external", "registrationAllowed": false, "loginWithEmailAllowed": true, "duplicateEmailsAllowed": false, "resetPasswordAllowed": false, "editUsernameAllowed": false, "bruteForceProtected": true}" 201 {}
POST http://localhost:8080/admin/realms/newrealm/users
--data "{"enabled": true, "username": "user1", "email": "user1@example.com", "emailVerified": true, "credentials": [{"type": "password", "value": "password", "temporary": false}]}" 201 {}
POST http://localhost:8080/admin/realms/newrealm/users
--data "{"enabled": true, "username": "user2", "email": "user2@example.com", "emailVerified": true, "credentials": [{"type": "password", "value": "password", "temporary": false}]}" 201 {}
POST http://localhost:8080/admin/realms/newrealm/users
--data "{"enabled": true, "username": "user3", "email": "user3@example.com", "emailVerified": true, "credentials": [{"type": "password", "value": "password", "temporary": false}]}" 201 {}