Skip to content
Closed
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
18 changes: 18 additions & 0 deletions Untitled-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "mini-lab",
"description": "mini-lab IdP",
"type": "Traditional",
"oidcClientMetadata": {
"redirectUris": [
{
"postLogoutRedirectUris": [
"http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"
]
}
],
"postLogoutRedirectUris": [
"http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"
]
},
"isThirdParty": true
}
2 changes: 2 additions & 0 deletions deploy_control_plane.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
tags: valkey
- name: auth-dex
tags: auth
- name: logto
tags: auth
- name: metal-roles/control-plane/roles/metal
tags: metal

Expand Down
24 changes: 24 additions & 0 deletions files/certs/logto-admin/server.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"CN": "logto",
"hosts": [
"localhost",
"logto",
"logto.metal-control-plane.svc",
"logto.metal-control-plane.svc.cluster.local",
"logto-admin.172.17.0.1.nip.io",
"logto.172.17.0.1.nip.io"
],
"key": {
"algo": "rsa",
"size": 4096
},
"names": [
{
"C": "DE",
"L": "Muenchen",
"O": "metal-stack",
"OU": "DevOps",
"ST": "Bayern"
}
]
}
9 changes: 9 additions & 0 deletions inventories/group_vars/control-plane/logto.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
auth_logto_admin_ingress_dns: "logto-admin.{{ metal_control_plane_ingress_dns }}"
auth_logto_ingress_dns: "logto.{{ metal_control_plane_ingress_dns }}"
auth_logto_issuer_url: http://logto.{{ metal_control_plane_ingress_dns }}


logto_admin_certs_server_key: "{{ lookup('file', 'certs/logto-admin/server-key.pem') }}"
logto_admin_certs_server_cert: "{{ lookup('file', 'certs/logto-admin/server.pem') }}"
logto_admin_certs_ca: "{{ lookup('file', 'certs/ca.pem') }}"
93 changes: 93 additions & 0 deletions logto-admin.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/bin/bash
set -euo pipefail

# ===============================
# Konfiguration
# ===============================
LOGTO_DB_CONTAINER="logto-postgres-1"
LOGTO_DB_USER="postgres"
LOGTO_DB_NAME="logto"
LOGTO_API_URL="http://localhost:3002"
CLIENT_ID="m-admin"
RESOURCE="https://admin.logto.app/api"
SCOPE="all"

APP_NAME="mini-lab"
APP_DESCRIPTION="mini-lab IdP"
REDIRECT_URI="http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"

# ===============================
# 1. Hole m-admin secret aus der Datenbank
# ===============================
echo "🔑 Hole Client Secret für ${CLIENT_ID}..."
CLIENT_SECRET=$(docker exec -it "$LOGTO_DB_CONTAINER" sh -c \
"psql -U $LOGTO_DB_USER -d $LOGTO_DB_NAME -t -A -c \"SELECT secret FROM applications WHERE id = '$CLIENT_ID';\"" \
| tr -d '\r')

if [[ -z "$CLIENT_SECRET" ]]; then
echo "❌ Konnte Client Secret nicht finden. Bitte prüfe, ob die Datenbank läuft und m-admin existiert."
exit 1
fi

echo "✅ Secret gefunden: ${CLIENT_SECRET}"

# ===============================
# 2. Hole Access Token
# ===============================
echo "🔐 Fordere Access Token an..."
ACCESS_TOKEN=$(curl -s --location \
--request POST "$LOGTO_API_URL/oidc/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
--data-urlencode "resource=$RESOURCE" \
--data-urlencode "scope=$SCOPE" \
| jq -r '.access_token')

if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then
echo "❌ Fehler beim Abrufen des Access Tokens."
exit 1
fi

echo "✅ Access Token erfolgreich erhalten."

# ===============================
# 3. (Optional) Liste bestehende Third-Party-Apps
# ===============================
echo "📜 Bestehende Third-Party-Anwendungen:"
curl -s --location \
--request GET "$LOGTO_API_URL/api/applications?isThirdParty=true" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
| jq '.[] | {id, name, description}'

# ===============================
# 4. Erstelle mini-lab Anwendung
# ===============================
echo "🚀 Erstelle neue Anwendung: $APP_NAME ..."
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request POST "$LOGTO_API_URL/api/applications" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"name\": \"$APP_NAME\",
\"description\": \"$APP_DESCRIPTION\",
\"type\": \"Traditional\",
\"oidcClientMetadata\": {
\"redirectUris\": [\"$REDIRECT_URI\"],
\"postLogoutRedirectUris\": [\"$REDIRECT_URI\"]
},
\"isThirdParty\": true
}")

HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')

if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Erstellen der Anwendung (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi

echo "✅ Anwendung erfolgreich erstellt:"
echo "$BODY" | jq .
161 changes: 161 additions & 0 deletions logto-user.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/bin/bash
set -euo pipefail

# ===============================
# Konfiguration
# ===============================
LOGTO_DB_CONTAINER="logto-postgres-1"
LOGTO_DB_USER="postgres"
LOGTO_DB_NAME="logto"
LOGTO_API_URL="http://localhost:3002"
CLIENT_ID="m-admin"
RESOURCE="https://admin.logto.app/api"
SCOPE="all"

APP_NAME="mini-lab"
APP_DESCRIPTION="mini-lab IdP"
REDIRECT_URI="http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"

ADMIN_NAME="admin"
ADMIN_PW="password1234"

# ===============================
# 1. Hole m-admin secret aus der Datenbank
# ===============================
echo "🔑 Hole Client Secret für ${CLIENT_ID}..."
CLIENT_SECRET=$(docker exec -it "$LOGTO_DB_CONTAINER" sh -c \
"psql -U $LOGTO_DB_USER -d $LOGTO_DB_NAME -t -A -c \"SELECT secret FROM applications WHERE id = '$CLIENT_ID';\"" \
| tr -d '\r')
if [[ -z "$CLIENT_SECRET" ]]; then
echo "❌ Konnte Client Secret nicht finden. Bitte prüfe, ob die Datenbank läuft und m-admin existiert."
exit 1
fi
echo "✅ Secret gefunden: ${CLIENT_SECRET}"

# ===============================
# 2. Hole Access Token
# ===============================
echo "🔐 Fordere Access Token an..."
ACCESS_TOKEN=$(curl -s --location \
--request POST "$LOGTO_API_URL/oidc/token" \
--header "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "grant_type=client_credentials" \
--data-urlencode "client_id=$CLIENT_ID" \
--data-urlencode "client_secret=$CLIENT_SECRET" \
--data-urlencode "resource=$RESOURCE" \
--data-urlencode "scope=$SCOPE" \
| jq -r '.access_token')
if [[ "$ACCESS_TOKEN" == "null" || -z "$ACCESS_TOKEN" ]]; then
echo "❌ Fehler beim Abrufen des Access Tokens."
exit 1
fi
echo "✅ Access Token erfolgreich erhalten."

# Create admin-user
echo "👤 Erstelle Admin-Benutzer..."
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request POST "$LOGTO_API_URL/api/users" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"username\": \"$ADMIN_NAME\",
\"password\": \"$ADMIN_PW\"
}")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Erstellen des Adminusers (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Adminuser erfolgreich erstellt:"
echo "$BODY" | jq .
USERID=$(echo "$BODY" | jq -r '.id')

# Create admin-user
echo "Add user to organisation"
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request POST "$LOGTO_API_URL/api/organizations/t-default/users" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"userIds\": [\"$USERID\"]
}")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Hinzufügen des Adminusers zur Organisation (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Adminuser erfolgreich hinzugefügt:"


echo "Adminrechte der Organisation zugeweisen"
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request POST "$LOGTO_API_URL/api/organizations/t-default/users/roles" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"userIds\": [\"$USERID\"],
\"organizationRoleIds\": [\"admin\"]
}")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Hinzufügen der Adminrechte zur Organisation (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Adminrechte erfolgreich hinzugefügt:"

echo "Rollen laden"
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request GET "$LOGTO_API_URL/api/roles?type=User" \
--header "Authorization: Bearer $ACCESS_TOKEN")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Laden der Rollen (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Rollen erfolgreich geladen:"
echo "$BODY" | jq .
ROLE_IDS=$(echo "$BODY" | jq -r '.[].id' | jq -R . | paste -sd, -)
echo "Gefundene Rollen IDs: $ROLE_IDS"

echo "Rollen zu Adminuser zuweisen"
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request POST "$LOGTO_API_URL/api/users/$USERID/roles" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"roleIds\": [$(echo "$ROLE_IDS" | paste -sd, -)]
}")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Zuweisen der Rollen (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Rollen erfolgreich zugewiesen:"

echo "Login anpassen"
CREATE_RESPONSE=$(curl -s -w "\n%{http_code}" --location \
--request PATCH "$LOGTO_API_URL/api/sign-in-exp" \
--header "Authorization: Bearer $ACCESS_TOKEN" \
--header "Content-Type: application/json" \
--data "{
\"tenantId\": \"admin\",
\"signInMode\": \"SignIn\"
}")
HTTP_CODE=$(echo "$CREATE_RESPONSE" | tail -n1)
BODY=$(echo "$CREATE_RESPONSE" | sed '$d')
if [[ "$HTTP_CODE" != "200" && "$HTTP_CODE" != "201" ]]; then
echo "❌ Fehler beim Anpassen des Logins (HTTP $HTTP_CODE):"
echo "$BODY" | jq .
exit 1
fi
echo "✅ Login erfolgreich angepasst:"
73 changes: 73 additions & 0 deletions logto.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
curl --location \
--request POST 'http://localhost:3001/oidc/token' \
--header 'Authorization: Basic MHN4ZTd3NWV1eGdqcDFrZnJid3g3OlVueVp3d0RCY2gzUjA1NTRzcUJRR0VuSWVjU0hyMXk5' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'resource=https://default.logto.app/api' \
--data-urlencode 'scope=all'

-------

RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a

curl --location \
--request POST 'http://localhost:3002/oidc/token' \
--header 'Authorization: Basic bS1hZG1pbjpSRnRsUU5tUnhINEhMRE1aVnJhNlphZDBWZVdOc1Q4YQ' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'resource=https://default.logto.app/api' \
--data-urlencode 'scope=all'

curl \
--request POST 'http://localhost:3001/api/applications' \
--header "Authorization: Bearer RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a" \
--header "Content-Type: application/json" \
--data '{"name":"mini-lab","description":"Mini-Lab","type":"MachineToMachine"}'


----

./logto-create-admin --baseUrl=http://localhost:3002 --appSecret=RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a --username=admin --password=password123

----

Solution:

1. Get m-admin token
docker exec -it logto-postgres-1 sh -c 'psql -U postgres -d logto -t -A -c "SELECT secret FROM applications WHERE id = '\''m-admin'\'';"'

2. Use the token to get access token for m-admin
curl --location \
--request POST 'http://localhost:3002/oidc/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=m-admin' \
--data-urlencode 'client_secret=RFtlQNmRxH4HLDMZVra6Zad0VeWNsT8a' \
--data-urlencode 'resource=https://admin.logto.app/api' \
--data-urlencode 'scope=all' \
| jq -r '.access_token'

3. Use the access token to manage entities
curl --location \
--request GET 'http://localhost:3002/api/applications?isThirdParty=true' \
--header 'Authorization: Bearer eyJhbGciOiJFUzM4NCIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjlobWw4NDl5NUZYQk5mUE93bnA1Q1g3ZUVkdERTejl5ejd5SllOZ0RnajAifQ.eyJqdGkiOiI5aFZDZWlaV202Q1p4Z0VDRTJWVDIiLCJzdWIiOiJtLWFkbWluIiwiaWF0IjoxNzYxNzQ0NjA1LCJleHAiOjE3NjE3NDgyMDUsInNjb3BlIjoiYWxsIiwiY2xpZW50X2lkIjoibS1hZG1pbiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMi9vaWRjIiwiYXVkIjoiaHR0cHM6Ly9hZG1pbi5sb2d0by5hcHAvYXBpIn0.u7GEcRma56PDiFSPF4_281xtodMUD1ZlpQu_NNAWKhpAj5RAg_zZKFk7sR3euXk3mgPqjko2oPBBTbDh9i0hiwjRDY-Iv_pYDlD9L18xUbjjIyoPI6X3hqTGNXpK-u0t'

4. Create mini-lab oidc app
curl --location \
--request POST 'http://localhost:3002/api/applications' \
--header 'Authorization: Bearer eyJhbGciOiJFUzM4NCIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjlobWw4NDl5NUZYQk5mUE93bnA1Q1g3ZUVkdERTejl5ejd5SllOZ0RnajAifQ.eyJqdGkiOiI5aFZDZWlaV202Q1p4Z0VDRTJWVDIiLCJzdWIiOiJtLWFkbWluIiwiaWF0IjoxNzYxNzQ0NjA1LCJleHAiOjE3NjE3NDgyMDUsInNjb3BlIjoiYWxsIiwiY2xpZW50X2lkIjoibS1hZG1pbiIsImlzcyI6Imh0dHA6Ly9sb2NhbGhvc3Q6MzAwMi9vaWRjIiwiYXVkIjoiaHR0cHM6Ly9hZG1pbi5sb2d0by5hcHAvYXBpIn0.u7GEcRma56PDiFSPF4_281xtodMUD1ZlpQu_NNAWKhpAj5RAg_zZKFk7sR3euXk3mgPqjko2oPBBTbDh9i0hiwjRDY-Iv_pYDlD9L18xUbjjIyoPI6X3hqTGNXpK-u0t' \
--header 'Content-Type: application/json' \
--data '{
"name": "mini-lab",
"description": "mini-lab IdP",
"type": "Traditional",
"oidcClientMetadata": {
"redirectUris": [
"http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"
],
"postLogoutRedirectUris": [
"http://v2.api.172.17.0.1.nip.io:8080/auth/oidc/callback"
]
},
"isThirdParty": true
}'
Loading
Loading