Prérequis
Démarrer Keycloak (testé avec la version 20)
docker run --publish 8888:8080 \
--env KEYCLOAK_ADMIN=admin --env KEYCLOAK_ADMIN_PASSWORD=admin \
--name kc-example --rm \
--detach keycloak/keycloak:20.0 start-dev
Initialisation
Initialisation d’un Realm avec un Client et un User.
base_url=http://localhost:8888
# Authenticate and get token
token=$(curl -s -d "client_id=admin-cli" -d "username=admin" -d "password=admin" -d "grant_type=password" \
"$base_url/realms/master/protocol/openid-connect/token" \
| jq -r .access_token)
# Create realm
curl -H "Authorization: bearer $token" -H "Content-Type: application/json" \
-d '{"realm":"sewatech", "enabled":true}' \
$base_url/admin/realms
# Create private client (with secret)
curl -H "Authorization: bearer $token" -H "Content-Type: application/json" \
-d '{"clientId":"private-jtips", "enabled":true, "standardFlowEnabled":true, \
"directAccessGrantsEnabled":true, "rootUrl":"http://localhost:4200", \
"redirectUris":["http://localhost:4200/*"], "secret":"example-secret"}' \
$base_url/admin/realms/sewatech/clients
# Create public client (without secret)
curl -H "Authorization: bearer $token" -H "Content-Type: application/json" \
-d '{"clientId":"public-jtips", "enabled":true, "standardFlowEnabled":true, \
"directAccessGrantsEnabled":true, "rootUrl":"http://localhost:4200", \
"redirectUris":["http://localhost:4200/*"], "publicClient":true}' \
$base_url/admin/realms/sewatech/clients
# Create user with password
curl -H "Authorization: bearer $token" -H "Content-Type: application/json" \
-d '{"username":"jtips", "enabled":true, \
"credentials": [{"type":"password","value":"jtipspwd","temporary":false}]}' \
$base_url/admin/realms/sewatech/users
Identifiants
Pour retrouver l’id du client:
clientId=$(curl -s -H "Authorization: bearer $token" -H "Content-Type: application/json" \
$base_url/admin/realms/sewatech/clients?clientId=public-jtips \
| jq -r .[0].id)
Direct flow
Le direct flow est activé par défaut. On peut l’utiliser dans Postman ou en ligne de commande.
curl -d "client_id=public-jtips" -d "grant_type=password" \
-d "username=jtips" -d "password=jtipspwd" \
$base_url/realms/sewatech/protocol/openid-connect/token
Ce flow peut être désactivé au niveau du client.
client=$(curl -s -H "Authorization: bearer $token" $base_url/admin/realms/sewatech/clients/$clientId \
| jq -r '.directAccessGrantsEnabled=false')
curl -s -H "Authorization: bearer $token" -H "Content-Type: application/json" -X PUT \
-d "$client" $base_url/admin/realms/sewatech/clients/$clientId
X.509 direct flow
Configuration du direct flow (utilisé depuis postman) pour authentification par un certificat X.509.
Attention, il y a des prérequis sur les certificats et sur le démarrage de keycloak.
# base_url et token sont initialisé comme ci-dessus
# X509 direct flow
curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"alias":"x509 direct grant", "providerId": "basic-flow", "topLevel": true, \
"authenticationExecutions": [{ \
"authenticator\": "direct-grant-auth-x509-username", \
"requirement": "REQUIRED", \
"priority": 0, \
"userSetupAllowed": false, \
"autheticatorFlow": false \
}]}' \
$base_url/admin/realms/sewatech/authentication/flows
curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"provider":"direct-grant-auth-x509-username"}' \
$base_url/admin/realms/sewatech/authentication/flows/x509%20direct%20grant/executions/execution
curl -X PUT --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"directGrantFlow": "x509 direct grant"}' \
$base_url/admin/realms/sewatech
execution_id=$(curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
$base_url/admin/realms/sewatech/authentication/flows/x509%20direct%20grant/executions \
| jq -r .[0].id)
...
SubjectDN
L’attribut CN du SubjectDN sert de username.
...
curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"config": {"x509-cert-auth.mapping-source-selection": "Subject's Common Name", \
"x509-cert-auth.canonical-dn-enabled": "true", \
"x509-cert-auth.user-attribute-name": "usercertificate", \
"x509-cert-auth.confirmation-page-disallowed": true}, \
"alias":"X509"}' \
$base_url/admin/realms/sewatech/authentication/executions/$execution_id/config
Serial et IssuerDN
Dans cet exemple, la correspondance entre le certificat et l’utilisateur est faite par le n° de série et le DN de l’émetteur.
...
curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"config": {"x509-cert-auth.mapping-source-selection":"Certificate Serial Number and IssuerDN", \
"x509-cert-auth.mapper-selection":"Custom Attribute Mapper",
"x509-cert-auth.mapper-selection.user-attribute-name":"SerialNumber##IssuerDN", \
"x509-cert-auth.canonical-dn-enabled":true, \
"x509-cert-auth.user-attribute-name":"usercertificate", \
"x509-cert-auth.confirmation-page-disallowed":true}, \
"alias":"X509serial"}' \
$base_url/admin/realms/sewatech/authentication/executions/$execution_id/config
Pour être trouvé, l’utilisateur doit avoir par 2 attributs personnalisés : SerialNumber et IssuerDN.
# Create user with Serial and IssuerDN
curl --silent --header "Authorization: bearer $token" --header "Content-Type: application/json" \
--data '{"username":"swserialuser", "enabled":true, \
"attributes":{"SerialNumber":["2"],"IssuerDN":["o=sewatech,cn=client-ca"]}}' \
$base_url/admin/realms/sewatech/users
L’IssuerDN est en minuscules parce qu’on a activé le format canonical.