Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions calm-hub/keycloak-dev/device-code-flow-entraid.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/bin/bash

CLIENT_ID="0cda28f4-102e-4913-b61c-d57a664e1b2b" #calm-hub-device-flow
SCOPE="api://calm-hub-producer-app/architectures:read api://calm-hub-producer-app/architectures:all"
TENANT_ID="3c9baf76-e5a3-42b6-8b21-46660e5d2cfb"

DEVICE_AUTH_ENDPOINT="https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/devicecode"
DEVICE_AUTH_RESPONSE=$(curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$CLIENT_ID" -d "scope=$SCOPE" \
$DEVICE_AUTH_ENDPOINT)

# Extract values from the device auth response.
DEVICE_CODE=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.device_code')
USER_CODE=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.user_code')
VERIFICATION_URI=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.verification_uri')
VERIFICATION_URI_COMPLETE=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.verification_uri_complete')
EXPIRES_IN=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.expires_in')
INTERVAL=$(echo "$DEVICE_AUTH_RESPONSE" | jq -r '.interval')

echo -e "Please open the link on a browser $VERIFICATION_URI, User Code:[$USER_CODE] \nCorresponding device code [$DEVICE_CODE] will expires in $EXPIRES_IN seconds.\n"

# Poll the token endpoint
# TrialTenantm0w91qAV.onmicrosoft.com
TOKEN_URL="https://login.microsoftonline.com/$TENANT_ID/oauth2/v2.0/token"
ACCESS_TOKEN=""
POLL_INTERVAL=15 #Seconds
poll_token() {
while true; do
RESPONSE=$(curl -X POST "$TOKEN_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=$CLIENT_ID" \
-d "device_code=$DEVICE_CODE" \
-d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
-d "scope=$SCOPE")

echo "Response: $RESPONSE \n"

ERROR=$(echo "$RESPONSE" | jq -r '.error')
if [[ "$ERROR" == "authorization_pending" ]]; then
echo "Waiting for user authorization..."
sleep $POLL_INTERVAL
elif [[ "$ERROR" == "expired_token" ]]; then
echo "Device code expired. Restart the flow."
exit 1
elif [[ "$ERROR" == "slow_down" ]]; then
echo "Server requested slower polling. "
POLL_INTERVAL=$((POLL_INTERVAL + 10))
sleep $POLL_INTERVAL
else
ACCESS_TOKEN=$(echo "$RESPONSE" | jq -r '.access_token')
echo "Access Token: $ACCESS_TOKEN"
break;
fi
done
}

#Start token polling
poll_token

echo "Proceed to get patterns"
read
if [[ -n $ACCESS_TOKEN ]]; then
curl --insecure -v -X GET "https://localhost:8443/calm/namespaces/finos/patterns" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"
fi
#Reference: https://github.com/keycloak/keycloak-community/blob/main/design/oauth2-device-authorization-grant.md
26 changes: 20 additions & 6 deletions calm-hub/keycloak-dev/device-code-flow.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/bin/bash

CLIENT_ID="calm-hub-device-flow"
SCOPE="architectures:all architectures:read"
CLIENT_ID="calm-hub-admin-app"
SCOPE="namespace:admin"
DEVICE_AUTH_ENDPOINT="https://localhost:9443/realms/calm-hub-realm/protocol/openid-connect/auth/device"
DEVICE_AUTH_RESPONSE=$(curl --insecure -X POST \
-H "Content-Type: application/x-www-form-urlencoded" \
Expand Down Expand Up @@ -54,11 +54,25 @@ poll_token() {
#Start token polling
poll_token

echo -e "\nPress enter to get patterns"
echo -e "\nPositive Case: Press enter to create a sample user-access for finos resources."
read
if [[ -n $ACCESS_TOKEN ]]; then
curl --insecure -v "https://localhost:8443/calm/namespaces/finos/patterns" \
curl -X POST --insecure -v "https://localhost:8443/calm/namespaces/finos/user-access" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{ "namespace": "finos", "resourceType": "patterns", "permission": "read", "username": "demo" }'

echo -e "\nPositive Case: Press enter to get list of user-access details associated to namespace:finos"
read
curl --insecure -v "https://localhost:8443/calm/namespaces/finos/user-access" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"

echo
echo -e "\nFailure Case: Press enter to create a sample user-access for traderx namespace."
read
curl -X POST --insecure -v "https://localhost:8443/calm/namespaces/traderx/user-access" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-d '{ "namespace": "traderx", "resourceType": "patterns", "permission": "read", "username": "demo" }'
fi
#Reference: https://github.com/keycloak/keycloak-community/blob/main/design/oauth2-device-authorization-grant.md
90 changes: 90 additions & 0 deletions calm-hub/keycloak-dev/imports/realm.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,45 @@
"adrs:read",
"architectures:all"
]
},
{
"clientId": "calm-hub-admin-app",
"name": "calm-hub-admin-app",
"description": "CalmHub Admin for Managing UserAccess",
"surrogateAuthRequired": false,
"enabled": true,
"alwaysDisplayInConsole": true,
"clientAuthenticatorType": "client-secret",
"redirectUris": [],
"webOrigins": [],
"notBefore": 0,
"bearerOnly": false,
"consentRequired": false,
"standardFlowEnabled": false,
"implicitFlowEnabled": false,
"directAccessGrantsEnabled": false,
"serviceAccountsEnabled": false,
"publicClient": true,
"frontchannelLogout": true,
"protocol": "openid-connect",
"attributes": {
"realm_client": "false",
"oidc.ciba.grant.enabled": "false",
"backchannel.logout.session.required": "true",
"post.logout.redirect.uris": "+",
"display.on.consent.screen": "false",
"oauth2.device.authorization.grant.enabled": "true",
"backchannel.logout.revoke.offline.tokens": "false"
},
"authenticationFlowBindingOverrides": {},
"fullScopeAllowed": true,
"nodeReRegistrationTimeout": -1,
"defaultClientScopes": [
"profile"
],
"optionalClientScopes": [
"namespace:admin"
]
}
],
"clientScopes": [
Expand Down Expand Up @@ -559,13 +598,30 @@
}
}
]
},
{
"name": "namespace:admin",
"protocol": "openid-connect",
"protocolMappers": [
{
"name": "audience",
"protocol": "openid-connect",
"protocolMapper": "oidc-audience-mapper",
"config": {
"included.client.audience": "calm-hub-producer-app",
"id.token.claim": "true",
"access.token.claim": "true"
}
}
]
}
],
"defaultOptionalClientScopes": [
"adrs:read",
"adrs:all",
"architectures:read",
"architectures:all",
"namespace:admin",
"offline_access",
"service_account"
],
Expand All @@ -591,6 +647,12 @@
"roles": [
"calm-hub-readonly"
]
},
{
"clientScope": "namespace:admin",
"roles": [
"calm-hub-admin"
]
}
],
"roles": {
Expand All @@ -601,6 +663,13 @@
"description": "Readonly role with access to read scopes",
"composite": false,
"attributes": {}
},
{
"name": "calm-hub-admin",
"clientRole": false,
"description": "Admin role to grant access to calm-hub users",
"composite": false,
"attributes": {}
}
]
},
Expand All @@ -625,6 +694,27 @@
"realmRoles": [
"calm-hub-readonly"
]
},
{
"username": "demo_admin",
"enabled": true,
"email": "demo_admin@calm-hub.finos.org",
"firstName": "Demo User",
"lastName": "Admin",
"attributes": {
"department": "Technology",
"location": "HQ"
},
"credentials": [
{
"type": "password",
"value": "changeme",
"temporary": true
}
],
"realmRoles": [
"calm-hub-admin"
]
}
]
}
55 changes: 55 additions & 0 deletions calm-hub/mongo/init-mongo.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ if (db.counters.countDocuments({ _id: "flowStoreCounter" }) === 0) {
print("flowStoreCounter already exists, no initialization needed");
}

if (db.counters.countDocuments({ _id: "userAccessStoreCounter" }) === 0) {
db.counters.insertOne({
_id: "userAccessStoreCounter",
sequence_value: 6
});
print("Initialized userAccessStoreCounter with sequence_value 6");
} else {
print("userAccessStoreCounter already exists, no initialization needed");
}

db.schemas.insertMany([ // Insert initial documents into the schemas collection
{
version: "2025-03",
Expand Down Expand Up @@ -2665,3 +2675,48 @@ db.architectures.insertMany([
}]
}
]);

db.userAccess.insertMany([
{
"userAccessId": NumberInt(1),
"username": "demo_admin",
"permission": "write",
"namespace": "finos",
"resourceType": "all"
},
{
"userAccessId": NumberInt(2),
"username": "demo_admin",
"permission": "write",
"namespace": "workshop",
"resourceType": "patterns"
},
{
"userAccessId": NumberInt(3),
"username": "demo_admin",
"permission": "read",
"namespace": "traderx",
"resourceType": "all"
},
{
"userAccessId": NumberInt(4),
"username": "demo",
"permission": "read",
"namespace": "finos",
"resourceType": "all"
},
{
"userAccessId": NumberInt(5),
"username": "demo",
"permission": "read",
"namespace": "traderx",
"resourceType": "all"
},
{
"userAccessId": NumberInt(6),
"username": "demo",
"permission": "read",
"namespace": "workshop",
"resourceType": "all"
}
]);
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ public static void counterSetup(MongoDatabase database) {
Document patternStoreCounter = new Document("_id", "patternStoreCounter").append("sequence_value", 0);
Document architectureStoreCounter = new Document("_id", "architectureStoreCounter").append("sequence_value", 0);
Document adrStoreCounter = new Document("_id", "adrStoreCounter").append("sequence_value", 0);
Document userAccessStoreCounter = new Document("_id", "userAccessStoreCounter").append("sequence_value", 0);
database.getCollection("counters").insertOne(patternStoreCounter);
database.getCollection("counters").insertOne(architectureStoreCounter);
database.getCollection("counters").insertOne(adrStoreCounter);
database.getCollection("counters").insertOne(userAccessStoreCounter);
}
}
}
Loading
Loading