[GH-ISSUE #1021] [BUG] creating new users in parallel using GraphQL API and sqlite as database can result in error returned from database: (code: 5) database is locked #369

Closed
opened 2026-02-27 08:16:54 +03:00 by kerem · 2 comments
Owner

Originally created by @tasansga on GitHub (Oct 29, 2024).
Original GitHub issue: https://github.com/lldap/lldap/issues/1021

Describe the bug

Creating new users in parallel using GraphQL API and sqlite as database can result in error returned from database: (code: 5) database is locked. The affected user isn't created.

To Reproduce

The following bash script starts lldap:latest in a Docker container and then proceeds to create 50 users at once, it yields the error reliably on my machine, usually several times:

#!/usr/bin/env bash

set -eo pipefail

function auth() {
  local lldap_http_host="$1"
  local password="$2"
  local response
  response=$(curl \
    --silent \
    --request POST \
    --url "${lldap_http_host}/auth/simple/login" \
    --header 'Content-Type: application/json' \
    --data "{ \"username\" : \"admin\", \"password\" : \"${password}\" }")
  echo "$response" | jq --raw-output '.token'
}

function create_user() {
  local lldap_http_host="$1"
  local token="$2"
  local username="$3"
  local request
  request="$(cat <<EOF
{
  "query" : "mutation CreateUser(\$user: CreateUserInput!) {createUser(user: \$user) {id creationDate}}",
  "operationName" : "CreateUser",
  "variables" : {
    "user" : {
        "id": "${username}",
        "email": "${username}@mail.test"
    }
  }
}
EOF
)"
  local response
  response=$(curl \
    --silent \
    --request POST \
    --url "${lldap_http_host}/api/graphql" \
    --header "Authorization: Bearer ${token}" \
    --header 'Content-Type: application/json' \
    --data "$request")
  if [[ ! "$response" == '{"data":{"createUser":{"id":"testuser'* ]]
  then
    >&2 echo "Unexpected response: ${response}"
  fi
}

password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 18; echo)
cnt_id=$(docker run \
    --detach \
    --rm \
    --env "LLDAP_LDAP_USER_PASS=${password}" \
    lldap/lldap:latest)

function on_exit {
    docker stop "$cnt_id" > /dev/null || true
}

trap on_exit EXIT

docker logs -f "$cnt_id" &
sleep 3 # need to wait for lldap to properly start up

cnt_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cnt_id")
lldap_http_host="http://${cnt_ip}:17170"
token=$(auth "$lldap_http_host" "$password")

for i in $(seq 1 50)
do
  create_user "$lldap_http_host" "$token" "testuser${i}" &
done

Expected behavior

At least for me it's:

  • not expected that LLDAP doesn't simply wait for the lock
  • not expected that LLDAP passes database errors unfiltered to the client, these can have security implications

Logs

Example lldap log output from above script:

2024-10-29T15:44:56.019184062+00:00  ERROR    🚨 [error]:  | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked`
2024-10-29T15:44:56.019348453+00:00  ERROR    🚨 [error]:  | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked`
2024-10-29T15:44:56.019863107+00:00  ERROR    🚨 [error]:  | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked`
Originally created by @tasansga on GitHub (Oct 29, 2024). Original GitHub issue: https://github.com/lldap/lldap/issues/1021 **Describe the bug** Creating new users in parallel using GraphQL API and sqlite as database can result in `error returned from database: (code: 5) database is locked`. The affected user isn't created. **To Reproduce** The following bash script starts `lldap:latest` in a Docker container and then proceeds to create 50 users at once, it yields the error reliably on my machine, usually several times: ``` #!/usr/bin/env bash set -eo pipefail function auth() { local lldap_http_host="$1" local password="$2" local response response=$(curl \ --silent \ --request POST \ --url "${lldap_http_host}/auth/simple/login" \ --header 'Content-Type: application/json' \ --data "{ \"username\" : \"admin\", \"password\" : \"${password}\" }") echo "$response" | jq --raw-output '.token' } function create_user() { local lldap_http_host="$1" local token="$2" local username="$3" local request request="$(cat <<EOF { "query" : "mutation CreateUser(\$user: CreateUserInput!) {createUser(user: \$user) {id creationDate}}", "operationName" : "CreateUser", "variables" : { "user" : { "id": "${username}", "email": "${username}@mail.test" } } } EOF )" local response response=$(curl \ --silent \ --request POST \ --url "${lldap_http_host}/api/graphql" \ --header "Authorization: Bearer ${token}" \ --header 'Content-Type: application/json' \ --data "$request") if [[ ! "$response" == '{"data":{"createUser":{"id":"testuser'* ]] then >&2 echo "Unexpected response: ${response}" fi } password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 18; echo) cnt_id=$(docker run \ --detach \ --rm \ --env "LLDAP_LDAP_USER_PASS=${password}" \ lldap/lldap:latest) function on_exit { docker stop "$cnt_id" > /dev/null || true } trap on_exit EXIT docker logs -f "$cnt_id" & sleep 3 # need to wait for lldap to properly start up cnt_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cnt_id") lldap_http_host="http://${cnt_ip}:17170" token=$(auth "$lldap_http_host" "$password") for i in $(seq 1 50) do create_user "$lldap_http_host" "$token" "testuser${i}" & done ``` **Expected behavior** At least for me it's: - not expected that LLDAP doesn't simply wait for the lock - not expected that LLDAP passes database errors unfiltered to the client, these can have security implications **Logs** Example lldap log output from above script: ``` 2024-10-29T15:44:56.019184062+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` 2024-10-29T15:44:56.019348453+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` 2024-10-29T15:44:56.019863107+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` ```
kerem 2026-02-27 08:16:54 +03:00
Author
Owner

@nitnelave commented on GitHub (Oct 29, 2024):

Thanks for the bug and the reproduction! This is something that I expected
the ORM to handle, but it might take a bit more massaging to make it
happen. I haven't really tested contention for LLDAP.

On another note, how is displaying the database error a potential security
issue? Do you have a specific scenario in mind, or a recommendation from
some security experts?

On Tue, 29 Oct 2024, 17:27 Ansgar Tasler, @.***> wrote:

Describe the bug

Creating new users in parallel using GraphQL API and sqlite as database
can result in error returned from database: (code: 5) database is locked.

To Reproduce

The following bash script starts lldap:latest in a Docker container and
then proceeds to create 50 users at once, it yields the error reliably on
my machine, usually several times:

#!/usr/bin/env bash

set -eo pipefail

function auth() {
local lldap_http_host="$1"
local password="$2"
local response
response=$(curl
--silent
--request POST
--url "${lldap_http_host}/auth/simple/login"
--header 'Content-Type: application/json'
--data "{ "username" : "admin", "password" : "${password}" }")
echo "$response" | jq --raw-output '.token'
}

function create_user() {
local lldap_http_host="$1"
local token="$2"
local username="$3"
local request
request="$(cat <<EOF
{
"query" : "mutation CreateUser($user: CreateUserInput!) {createUser(user: $user) {id creationDate}}",
"operationName" : "CreateUser",
"variables" : {
"user" : {
"id": "${username}",
"email": @.**"
}
}
}
EOF
)"
local response
response=$(curl
--silent
--request POST
--url "${lldap_http_host}/api/graphql"
--header "Authorization: Bearer ${token}"
--header 'Content-Type: application/json'
--data "$request")
if [[ ! "$response" == '{"data":{"createUser":{"id":"testuser'
]]
then
>&2 echo "Unexpected response: ${response}"
fi
}

password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 18; echo)
cnt_id=$(docker run
--detach
--rm
--env "LLDAP_LDAP_USER_PASS=${password}"
lldap/lldap:latest)

function on_exit {
docker stop "$cnt_id" > /dev/null || true
}

trap on_exit EXIT

docker logs -f "$cnt_id" &
sleep 3 # need to wait for lldap to properly start up

cnt_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cnt_id")
lldap_http_host="http://${cnt_ip}:17170"
token=$(auth "$lldap_http_host" "$password")

for i in $(seq 1 50)
do
create_user "$lldap_http_host" "$token" "testuser${i}" &
done

Expected behavior

At least for me it's:

  • not expected that LLDAP doesn't simply wait for the lock
  • not expected that LLDAP passes database errors unfiltered to the
    client, these can have security implications

Logs

Example lldap log output from above script:

2024-10-29T15:44:56.019184062+00:00 ERROR 🚨 [error]: | error: Database error: Execution Error: error returned from database: (code: 5) database is locked
2024-10-29T15:44:56.019348453+00:00 ERROR 🚨 [error]: | error: Database error: Execution Error: error returned from database: (code: 5) database is locked
2024-10-29T15:44:56.019863107+00:00 ERROR 🚨 [error]: | error: Database error: Execution Error: error returned from database: (code: 5) database is locked


Reply to this email directly, view it on GitHub
https://github.com/lldap/lldap/issues/1021, or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAGCPWKGJUZO4YI5GP525ETZ56ZN3AVCNFSM6AAAAABQ2IFSU6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGYZDCNZWHA4DSNA
.
You are receiving this because you are subscribed to this thread.Message
ID: @.***>

<!-- gh-comment-id:2445258447 --> @nitnelave commented on GitHub (Oct 29, 2024): Thanks for the bug and the reproduction! This is something that I expected the ORM to handle, but it might take a bit more massaging to make it happen. I haven't really tested contention for LLDAP. On another note, how is displaying the database error a potential security issue? Do you have a specific scenario in mind, or a recommendation from some security experts? On Tue, 29 Oct 2024, 17:27 Ansgar Tasler, ***@***.***> wrote: > *Describe the bug* > > Creating new users in parallel using GraphQL API and sqlite as database > can result in error returned from database: (code: 5) database is locked. > > *To Reproduce* > > The following bash script starts lldap:latest in a Docker container and > then proceeds to create 50 users at once, it yields the error reliably on > my machine, usually several times: > > #!/usr/bin/env bash > > set -eo pipefail > > function auth() { > local lldap_http_host="$1" > local password="$2" > local response > response=$(curl \ > --silent \ > --request POST \ > --url "${lldap_http_host}/auth/simple/login" \ > --header 'Content-Type: application/json' \ > --data "{ \"username\" : \"admin\", \"password\" : \"${password}\" }") > echo "$response" | jq --raw-output '.token' > } > > function create_user() { > local lldap_http_host="$1" > local token="$2" > local username="$3" > local request > request="$(cat <<EOF > { > "query" : "mutation CreateUser(\$user: CreateUserInput!) {createUser(user: \$user) {id creationDate}}", > "operationName" : "CreateUser", > "variables" : { > "user" : { > "id": "${username}", > "email": ***@***.***" > } > } > } > EOF > )" > local response > response=$(curl \ > --silent \ > --request POST \ > --url "${lldap_http_host}/api/graphql" \ > --header "Authorization: Bearer ${token}" \ > --header 'Content-Type: application/json' \ > --data "$request") > if [[ ! "$response" == '{"data":{"createUser":{"id":"testuser'* ]] > then > >&2 echo "Unexpected response: ${response}" > fi > } > > password=$(tr -dc A-Za-z0-9 </dev/urandom | head -c 18; echo) > cnt_id=$(docker run \ > --detach \ > --rm \ > --env "LLDAP_LDAP_USER_PASS=${password}" \ > lldap/lldap:latest) > > function on_exit { > docker stop "$cnt_id" > /dev/null || true > } > > trap on_exit EXIT > > docker logs -f "$cnt_id" & > sleep 3 # need to wait for lldap to properly start up > > cnt_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "$cnt_id") > lldap_http_host="http://${cnt_ip}:17170" > token=$(auth "$lldap_http_host" "$password") > > for i in $(seq 1 50) > do > create_user "$lldap_http_host" "$token" "testuser${i}" & > done > > *Expected behavior* > > At least for me it's: > > - not expected that LLDAP doesn't simply wait for the lock > - not expected that LLDAP passes database errors unfiltered to the > client, these can have security implications > > *Logs* > > Example lldap log output from above script: > > 2024-10-29T15:44:56.019184062+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` > 2024-10-29T15:44:56.019348453+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` > 2024-10-29T15:44:56.019863107+00:00 ERROR 🚨 [error]: | error: Database error: `Execution Error: error returned from database: (code: 5) database is locked` > > — > Reply to this email directly, view it on GitHub > <https://github.com/lldap/lldap/issues/1021>, or unsubscribe > <https://github.com/notifications/unsubscribe-auth/AAGCPWKGJUZO4YI5GP525ETZ56ZN3AVCNFSM6AAAAABQ2IFSU6VHI2DSMVQWIX3LMV43ASLTON2WKOZSGYZDCNZWHA4DSNA> > . > You are receiving this because you are subscribed to this thread.Message > ID: ***@***.***> >
Author
Owner

@nitnelave commented on GitHub (Oct 30, 2024):

Relevant:
https://github.com/launchbadge/sqlx/issues/459
https://github.com/launchbadge/sqlx/issues/451

We can probably use a pool of a single worker for our use case.

<!-- gh-comment-id:2447233281 --> @nitnelave commented on GitHub (Oct 30, 2024): Relevant: https://github.com/launchbadge/sqlx/issues/459 https://github.com/launchbadge/sqlx/issues/451 We can probably use a pool of a single worker for our use case.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/lldap-lldap#369
No description provided.