Repository navigation
Missing Administrator Account
Only one backend should access the local SQLite database during this procedure.
Stop the running backend with Ctrl+C.
cd /Users/rodrigosilveira/projects/EnterpriseRemoteSystems
git fetch origin
git worktree add --detach \
../EnterpriseRemoteSystems-development-bootstrap \
origin/developmentConfirm that Development contains Bite 28B authentication:
test -f \
../EnterpriseRemoteSystems-development-bootstrap/backend/migrations/000042_user_authentication_foundation.up.sql \
&& echo "Bite 28B authentication is present"If that file is missing, do not continue with this procedure.
Check the database configuration in your main working tree:
cd /Users/rodrigosilveira/projects/EnterpriseRemoteSystems
grep -E '^(DB_PATH|DATABASE_PATH)=' backend/.envIf neither variable is present, the normal default database is:
/Users/rodrigosilveira/projects/EnterpriseRemoteSystems/backend/data/app.db
Set the exact database file:
LOCAL_DB="/Users/rodrigosilveira/projects/EnterpriseRemoteSystems/backend/data/app.db"
Adjust that value if your .env specifies another file.
Confirm it exists:
ls -lh "$LOCAL_DB"
cd /Users/rodrigosilveira/projects/EnterpriseRemoteSystems-development-bootstrap
DB_PATH="$LOCAL_DB" make local-backendLeave this terminal running.
Bite 28C did not introduce a new database migration in the files you listed, so the Bite 28B authentication schema should remain compatible.
Set the API address:
BASE_URL="http://127.0.0.1:8080/api/v1"Retrieve the Actor records and preserve the complete response:
HTTP_STATUS=$(
curl -sS \
-D /tmp/ers-development-authz-actors.headers \
-o /tmp/ers-development-authz-actors.json \
-w '%{http_code}' \
-H "X-Actor-ID: bootstrap-admin" \
-H "X-Tenant-ID: default" \
"$BASE_URL/authz/actors"
)
echo "HTTP $HTTP_STATUS"
jq . /tmp/ers-development-authz-actors.jsonExpected:
HTTP 200
Now extract bootstrap-admin using a query that supports both possible response shapes:
jq -e '
def actors:
if (.data | type) == "array" then
.data
elif (.data.items | type) == "array" then
.data.items
else
[]
end;
actors
| map(select(.actorKey == "bootstrap-admin"))
| first
| if . == null then
error("bootstrap-admin was not found")
else
{
actorRecordId: .id,
actorKey: .actorKey,
displayName: .displayName,
active: .active,
applicationAdminGrants: [
(.roleGrants // .grants // [])[]
| select(
.roleCode == "APPLICATION_ADMIN"
and .tenantId == "*"
)
]
}
end
' /tmp/ers-development-authz-actors.jsonExpected result should resemble:
{
"actorRecordId": "some-internal-uuid",
"actorKey": "bootstrap-admin",
"displayName": "Bootstrap Administrator",
"active": true,
"applicationAdminGrants": [
{
"roleCode": "APPLICATION_ADMIN",
"tenantId": "*",
"active": true
}
]
}
Confirm:
- actorKey is bootstrap-admin.
- active is true.
- applicationAdminGrants contains at least one record.
- Its roleCode is APPLICATION_ADMIN.
- Its tenantId is *.
- If the response includes grant active, it is true.
After the preceding command succeeds:
BOOTSTRAP_ACTOR_RECORD_ID=$(
jq -er '
def actors:
if (.data | type) == "array" then
.data
elif (.data.items | type) == "array" then
.data.items
else
[]
end;
actors[]
| select(.actorKey == "bootstrap-admin")
| .id
' /tmp/ers-development-authz-actors.json
)
echo "Bootstrap Actor record ID: $BOOTSTRAP_ACTOR_RECORD_ID"The result should be a UUID or other internal database identifier—not:
bootstrap-admin
bootstrap-admin is the Actor key; BOOTSTRAP_ACTOR_RECORD_ID is the internal Actor record ID required when creating the authentication account.
If the command says that bootstrap-admin was not found, list the available Actor keys:
jq -r '
if (.data | type) == "array" then
.data
elif (.data.items | type) == "array" then
.data.items
else
[]
end
| .[]
| [.actorKey, .displayName, (.active | tostring)]
| @tsv
' /tmp/ers-development-authz-actors.jsoncurl -sS \
-H "X-Actor-ID: bootstrap-admin" \
-H "X-Tenant-ID: default" \
"$BASE_URL/auth/accounts" \
| jq \
--arg actorId "$BOOTSTRAP_ACTOR_RECORD_ID" \
'.data[]
| select(.actorId == $actorId)
| {
accountId: .id,
login,
active,
actorActive,
mustChangePassword
}'Proceed according to the result.
Choose credentials:
ADMIN_LOGIN="local.application.admin@example.com"
ADMIN_PASSWORD='Local-ERS-Admin-Password-28C!'Create the account:
jq -n \
--arg actorId "$BOOTSTRAP_ACTOR_RECORD_ID" \
--arg login "$ADMIN_LOGIN" \
--arg password "$ADMIN_PASSWORD" \
'{
actorId: $actorId,
login: $login,
temporaryPassword: $password,
mustChangePassword: false
}' \
| curl -sS \
-D /tmp/ers-create-local-admin.headers \
-o /tmp/ers-create-local-admin.json \
-w 'HTTP %{http_code}\n' \
-H "X-Actor-ID: bootstrap-admin" \
-H "X-Tenant-ID: default" \
-H "Content-Type: application/json" \
--data-binary @- \
"$BASE_URL/auth/accounts"
cat /tmp/ers-create-local-admin.headers
jq . /tmp/ers-create-local-admin.jsonExpected:
HTTP 201
Extract its account ID and login:
ACCOUNT_JSON=$(
curl -sS \
-H "X-Actor-ID: bootstrap-admin" \
-H "X-Tenant-ID: default" \
"$BASE_URL/auth/accounts" \
| jq -c \
--arg actorId "$BOOTSTRAP_ACTOR_RECORD_ID" \
'.data[]
| select(.actorId == $actorId)'
)
ACCOUNT_ID=$(jq -er '.id' <<<"$ACCOUNT_JSON")
ADMIN_LOGIN=$(jq -er '.login' <<<"$ACCOUNT_JSON")
ADMIN_PASSWORD='Local-ERS-Admin-Password-28C!'
echo "Account: $ACCOUNT_ID"
echo "Login: $ADMIN_LOGIN"Issue a reset token:
RESET_TOKEN=$(
curl -sS \
-X POST \
-H "X-Actor-ID: bootstrap-admin" \
-H "X-Tenant-ID: default" \
"$BASE_URL/auth/accounts/$ACCOUNT_ID/password-reset-tokens" \
| jq -er '.data.token'
)
echo "Reset token obtained."Reset the password:
jq -n \
--arg token "$RESET_TOKEN" \
--arg password "$ADMIN_PASSWORD" \
'{
token: $token,
newPassword: $password
}' \
| curl -sS \
-o /tmp/ers-reset-local-admin.json \
-w 'HTTP %{http_code}\n' \
-H "Content-Type: application/json" \
--data-binary @- \
"$BASE_URL/auth/password/reset"Expected:
HTTP 204
The reset token is one-time use and should not be retained.
Stop the Development backend with Ctrl+C.
Then restart the backend from the real Bite 28C working tree:
cd /Users/rodrigosilveira/projects/EnterpriseRemoteSystems
make local-backendIn another terminal:
BASE_URL="http://127.0.0.1:8080/api/v1"
ADMIN_COOKIE="/tmp/ers-b28c-admin.cookies"
rm -f "$ADMIN_COOKIE"
Use the ADMIN_LOGIN and ADMIN_PASSWORD established above:
jq -n \
--arg login "$ADMIN_LOGIN" \
--arg password "$ADMIN_PASSWORD" \
'{
login: $login,
password: $password
}' \
| curl -sS \
-D /tmp/ers-b28c-admin-login.headers \
-o /tmp/ers-b28c-admin-login.json \
-w 'HTTP %{http_code}\n' \
-c "$ADMIN_COOKIE" \
-H "Content-Type: application/json" \
--data-binary @- \
"$BASE_URL/auth/login"
jq . /tmp/ers-b28c-admin-login.jsonExpected:
HTTP 200
Then verify Application Admin access:
curl -sS \
-D /tmp/ers-b28c-admin-actors.headers \
-o /tmp/ers-b28c-admin-actors.json \
-w 'HTTP %{http_code}\n' \
-b "$ADMIN_COOKIE" \
-H "X-Tenant-ID: default" \
"$BASE_URL/authz/actors"
jq . /tmp/ers-b28c-admin-actors.jsonExpected:
HTTP 200
After the administrator login works under Bite 28C:
cd /Users/rodrigosilveira/projects/EnterpriseRemoteSystems
git worktree remove \
../EnterpriseRemoteSystems-development-bootstrap