Skip to content

Commit 530e9a8

Browse files
authored
Merge pull request #73 from rcbj/feature/issue-71
Add test to testing framework for the OIDC Authorization Code Flow
2 parents dd0c29d + fbde18a commit 530e9a8

File tree

5 files changed

+312
-42
lines changed

5 files changed

+312
-42
lines changed

.github/workflows/tests.yml

+64-21
Original file line numberDiff line numberDiff line change
@@ -17,37 +17,80 @@ jobs:
1717
- name: Start & configure Keycloak and debugger
1818
id: configure
1919
run: |
20+
# Install testing dependencies
21+
npm install --prefix tests
22+
2023
# Start Docker containers
2124
CONFIG_FILE=./env/local.js docker compose -f docker-compose-with-keycloak.yml up -d --build
2225
sleep 30
2326
24-
# Configure client credentials flow
27+
# Configure Keycloak
2528
KEYCLOAK_ACCESS_TOKEN=$(curl -X POST "http://localhost:8080/realms/master/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=admin-cli" -d "username=keycloak" -d "password=keycloak" -d "grant_type=password" | jq -r '.access_token')
26-
curl -X POST "http://localhost:8080/admin/realms" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"realm": "debugger-testing", "enabled": true}'
27-
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"name": "client-credentials-scope", "protocol": "openid-connect", "attributes": {"display.on.consent.screen": "false", "include.in.token.scope": "true"}}'
28-
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/clients" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" -H "Content-Type: application/json" -d '{"clientId": "client-credentials", "protocol": "openid-connect", "publicClient": false, "serviceAccountsEnabled": true, "authorizationServicesEnabled": false, "standardFlowEnabled": false, "directAccessGrantsEnabled": false, "clientAuthenticatorType": "client-secret"}'
29-
KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_ID=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=client-credentials" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" | jq -r '.[0].id')
30-
KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_CLIENTID=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=client-credentials" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" | jq -r '.[0].clientId')
31-
KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_SECRET=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=client-credentials" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" | jq -r '.[0].secret')
32-
KEYCLOAK_CLIENT_CREDENTIALS_SCOPE_ID=$(curl "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" | jq -r '.[] | select(.name=="client-credentials-scope") | .id')
33-
KEYCLOAK_CLIENT_CREDENTIALS_SCOPE_NAME=$(curl "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN" | jq -r '.[] | select(.name=="client-credentials-scope") | .name')
34-
curl -X PUT "http://localhost:8080/admin/realms/debugger-testing/clients/$KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_ID/optional-client-scopes/$KEYCLOAK_CLIENT_CREDENTIALS_SCOPE_ID" -H "Authorization: Bearer $KEYCLOAK_ACCESS_TOKEN"
35-
36-
# Share variables to next steps
37-
echo "CLIENT_CREDENTIALS_DISCOVERY_ENDPOINT=http://localhost:8080/realms/debugger-testing/.well-known/openid-configuration" >> $GITHUB_OUTPUT
38-
echo "CLIENT_CREDENTIALS_CLIENT_ID=$(echo $KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_CLIENTID)" >> $GITHUB_OUTPUT
39-
echo "CLIENT_CREDENTIALS_CLIENT_SECRET=$(echo $KEYCLOAK_CLIENT_CREDENTIALS_CLIENT_SECRET)" >> $GITHUB_OUTPUT
40-
echo "CLIENT_CREDENTIALS_SCOPE=$(echo $KEYCLOAK_CLIENT_CREDENTIALS_SCOPE_NAME)" >> $GITHUB_OUTPUT
29+
curl -X POST "http://localhost:8080/admin/realms" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"realm": "debugger-testing", "enabled": true}'
30+
31+
for FLOW_VARIABLE in CLIENT_CREDENTIALS AUTHORIZATION_CODE_CONFIDENTIAL AUTHORIZATION_CODE_PUBLIC
32+
do
33+
FLOW_NAME=$(echo ${FLOW_VARIABLE} | tr '[:upper:]' '[:lower:]' | tr '_' '-')
34+
35+
KEYCLOAK_ACCESS_TOKEN=$(curl -X POST "http://localhost:8080/realms/master/protocol/openid-connect/token" -H "Content-Type: application/x-www-form-urlencoded" -d "client_id=admin-cli" -d "username=keycloak" -d "password=keycloak" -d "grant_type=password" | jq -r '.access_token')
36+
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"name": "'${FLOW_NAME}'-scope", "protocol": "openid-connect", "attributes": {"display.on.consent.screen": "false", "include.in.token.scope": "true"}}'
37+
case "${FLOW_VARIABLE}" in
38+
CLIENT_CREDENTIALS)
39+
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/clients" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"clientId": "'${FLOW_NAME}'", "protocol": "openid-connect", "publicClient": false, "serviceAccountsEnabled": true, "authorizationServicesEnabled": false, "standardFlowEnabled": false, "directAccessGrantsEnabled": false, "clientAuthenticatorType": "client-secret"}'
40+
;;
41+
AUTHORIZATION_CODE_CONFIDENTIAL)
42+
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/clients" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"clientId": "'${FLOW_NAME}'", "protocol": "openid-connect", "publicClient": false, "serviceAccountsEnabled": false, "authorizationServicesEnabled": false, "standardFlowEnabled": true, "directAccessGrantsEnabled": false, "clientAuthenticatorType": "client-secret", "frontchannelLogout": true, "redirectUris": ["http://localhost:3000/callback"], "webOrigins": ["/*", "http://localhost:3000/*"], "attributes": {"frontchannel.logout.url": "http://localhost:3000/logout"}}'
43+
;;
44+
AUTHORIZATION_CODE_PUBLIC)
45+
curl -X POST "http://localhost:8080/admin/realms/debugger-testing/clients" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"clientId": "'${FLOW_NAME}'", "protocol": "openid-connect", "publicClient": true, "serviceAccountsEnabled": false, "authorizationServicesEnabled": false, "standardFlowEnabled": true, "directAccessGrantsEnabled": false, "clientAuthenticatorType": null, "frontchannelLogout": true, "redirectUris": ["http://localhost:3000/callback"], "webOrigins": ["/*", "http://localhost:3000/*"], "attributes": {"frontchannel.logout.url": "http://localhost:3000/logout"}}'
46+
;;
47+
esac
48+
49+
CLIENT_ID=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=${FLOW_NAME}" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" | jq -r '.[0].id')
50+
CLIENT_CLIENTID=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=${FLOW_NAME}" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" | jq -r '.[0].clientId')
51+
CLIENT_SECRET=$(curl "http://localhost:8080/admin/realms/debugger-testing/clients?clientId=${FLOW_NAME}" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" | jq -r '.[0].secret')
52+
SCOPE_ID=$(curl "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" | jq -r '.[] | select(.name=="'${FLOW_NAME}'-scope") | .id')
53+
SCOPE_NAME=$(curl "http://localhost:8080/admin/realms/debugger-testing/client-scopes" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" | jq -r '.[] | select(.name=="'${FLOW_NAME}'-scope") | .name')
54+
curl -X PUT "http://localhost:8080/admin/realms/debugger-testing/clients/${CLIENT_ID}/optional-client-scopes/${SCOPE_ID}" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}"
55+
USER_ID=$(curl -X POST "http://localhost:8080/admin/realms/debugger-testing/users" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"username": "'${FLOW_NAME}'", "firstName": "'${FLOW_NAME}'", "lastName": "'${FLOW_NAME}'", "email": "'${FLOW_NAME}'@iyasec.io", "enabled": true, "emailVerified": true}' -i | grep Location | rev | cut -d '/' -f 1 | rev | tr -d ' \n\r')
56+
curl -X PUT "http://localhost:8080/admin/realms/debugger-testing/users/${USER_ID}/reset-password" -H "Authorization: Bearer ${KEYCLOAK_ACCESS_TOKEN}" -H "Content-Type: application/json" -d '{"type": "password", "value": "'${FLOW_NAME}'", "temporary": false}'
57+
58+
echo "${FLOW_VARIABLE}_DISCOVERY_ENDPOINT=http://localhost:8080/realms/debugger-testing/.well-known/openid-configuration" >> $GITHUB_OUTPUT
59+
echo "${FLOW_VARIABLE}_CLIENT_ID=${CLIENT_CLIENTID}" >> $GITHUB_OUTPUT
60+
echo "${FLOW_VARIABLE}_CLIENT_SECRET=${CLIENT_SECRET}" >> $GITHUB_OUTPUT
61+
echo "${FLOW_VARIABLE}_SCOPE=${SCOPE_NAME}" >> $GITHUB_OUTPUT
62+
echo "${FLOW_VARIABLE}_USER=${USER_ID}" >> $GITHUB_OUTPUT
63+
done
4164
4265
- name: Test client credentials flow
4366
id: test_client_credentials
4467
run: |
45-
# Install dependencies
46-
cd tests && npm install
47-
48-
# Test client credentials flow
4968
DISCOVERY_ENDPOINT=${{ steps.configure.outputs.CLIENT_CREDENTIALS_DISCOVERY_ENDPOINT }} \
5069
CLIENT_ID=${{ steps.configure.outputs.CLIENT_CREDENTIALS_CLIENT_ID }} \
5170
CLIENT_SECRET=${{ steps.configure.outputs.CLIENT_CREDENTIALS_CLIENT_SECRET }} \
5271
SCOPE=${{ steps.configure.outputs.CLIENT_CREDENTIALS_SCOPE }} \
53-
node oauth2_client_credentials.js
72+
node tests/oauth2_client_credentials.js
73+
74+
- name: Test authorization code flow
75+
id: test_authorization_code
76+
run: |
77+
for PKCE_ENABLED in true false
78+
do
79+
# Confidential client
80+
DISCOVERY_ENDPOINT=${{ steps.configure.outputs.AUTHORIZATION_CODE_CONFIDENTIAL_DISCOVERY_ENDPOINT }} \
81+
CLIENT_ID=${{ steps.configure.outputs.AUTHORIZATION_CODE_CONFIDENTIAL_CLIENT_ID }} \
82+
CLIENT_SECRET=${{ steps.configure.outputs.AUTHORIZATION_CODE_CONFIDENTIAL_CLIENT_SECRET }} \
83+
SCOPE=${{ steps.configure.outputs.AUTHORIZATION_CODE_CONFIDENTIAL_SCOPE }} \
84+
USER=${{ steps.configure.outputs.AUTHORIZATION_CODE_CONFIDENTIAL_USER }} \
85+
PKCE_ENABLED=${PKCE_ENABLED} \
86+
node tests/oauth2_authorization_code.js
87+
88+
# Public client
89+
DISCOVERY_ENDPOINT=${{ steps.configure.outputs.AUTHORIZATION_CODE_PUBLIC_DISCOVERY_ENDPOINT }} \
90+
CLIENT_ID=${{ steps.configure.outputs.AUTHORIZATION_CODE_PUBLIC_CLIENT_ID }} \
91+
CLIENT_SECRET=${{ steps.configure.outputs.AUTHORIZATION_CODE_PUBLIC_CLIENT_SECRET }} \
92+
SCOPE=${{ steps.configure.outputs.AUTHORIZATION_CODE_PUBLIC_SCOPE }} \
93+
USER=${{ steps.configure.outputs.AUTHORIZATION_CODE_PUBLIC_USER }} \
94+
PKCE_ENABLED=${PKCE_ENABLED} \
95+
node tests/oauth2_authorization_code.js
96+
done

.gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
api/node_modules
22
client/node_modules
3-
node_modules
3+
node_modules
4+
.idea

api/server.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ app.post('/token', (req, res) => {
197197
parameterObject[key] +
198198
"&";
199199
});
200+
200201
var headers = {
201202
'content-type' : 'application/x-www-form-urlencoded'
202203
};
@@ -277,5 +278,4 @@ let options = {
277278

278279
expressSwagger(options)
279280
app.listen(PORT, HOST);
280-
log.info(`Running on http://${HOST}:${PORT}`);
281-
281+
log.info(`Running on http://${HOST}:${PORT}`);

0 commit comments

Comments
 (0)