Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PUT /_node/{node-name}/_config/jwt_keys/{key} does not accept valid key #5091

Closed
Stwissel opened this issue Jun 18, 2024 · 2 comments
Closed

Comments

@Stwissel
Copy link

Description

While trying to programmatically setup JWT authentication with a key derived from a JWKS key, the update using
PUT /_node/{node-name}/_config/jwt_keys/{key} fails with an error (see reproducer) when a valid key is provided, but works for arbitrary strings

Steps to Reproduce

The reproducer uses a local container couch with admin/password and no persistence configured, so it can easily be reproduced repeatedly.

step 1: create temp couchDB instance

docker run --rm --name testcouch -e COUCHDB_USER=admin -e COUCHDB_PASSWORD=password  -p 5984:5984 apache/couchdb:latest

step 2: create _user, replicator to silence the "_user" is missing in the log (works)

curl --request PUT 'http:https://localhost:5984/_users' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ='
curl --request PUT 'http:https://localhost:5984/_replicator' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ='

both complete with HTTP 201 {"ok":true}

step 3: update the authentication methods

curl --request PUT 'http:https://localhost:5984/_node/_local/_config/chttpd/authentication_handlers' \
--header 'Content-Type: text/plain' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \
--data '"{chttpd_auth, cookie_authentication_handler}, {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, default_authentication_handler}"'

Ends with HTTP 200 and "" (seems to be the old value)

step 4a: check current jwt_keys configuration

curl 'http:https://localhost:5984/_node/nonode@nohost/_config/jwt_keys' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ='

Ends with http 200 and {} (as expected)

step 4b: Add JWT key ( that one fails)

curl --request PUT 'http:https://localhost:5984/_node/nonode@nohost/_config/jwt_keys/rsa:S1-oBDEUlMfN-FP5EeG6UcaKdeCs01_dx5AIw-SogiQ' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \
--data '"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9SJFyVWvBonL3K+giuzeQ4Vp1bH9ftu\nzjrtLMMBUWESQEMXsml7s58/8UOWQ40j71eu+63sLvCnLhcP9jmKI8vwofkMo91ulZn2ntKTsawJ\nmnrR7k1W5okbLlnwYq1KN3SRcjeHYa3JruoDmHHW9dO5dAGu09ookgWxYr2K1jXT1+L1NFOfBXqs\njFqr3a+ArMOg5POcg9I6lI9kmi8aOJgTfRydJbuUC8vtgc7rdHY4g7IdGlOM+LWdor23P16vzfVK\nGNDNbi072S0vzkt+Q/WLb9UuQi64wB3LxVLDfUKNg2OGJ6/ju1bZX+Fo02hG6lkMa2BO3CwmirGR\nLiWb4wIDAQAB\n-----END PUBLIC KEY-----\n"'

Ends with http 400, {"error":"bad_request","reason":"Invalid configuration value"} and no entry in jwt_keys created

Expected Behaviour

End with http 20x and creation of jwt_key entry:

curl 'http:https://localhost:5984/_node/nonode@nohost/_config/jwt_keys' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ='

to result in

{
    "rsa:S1-oBDEUlMfN-FP5EeG6UcaKdeCs01_dx5AIw-SogiQ": "-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9SJFyVWvBonL3K+giuz\\neQ4Vp1bH9ftuzjrtLMMBUWESQEMXsml7s58/8UOWQ40j71eu+63sLvCnLhcP9jmK\\nI8vwofkMo91ulZn2ntKTsawJmnrR7k1W5okbLlnwYq1KN3SRcjeHYa3JruoDmHHW\\n9dO5dAGu09ookgWxYr2K1jXT1+L1NFOfBXqsjFqr3a+ArMOg5POcg9I6lI9kmi8a\\nOJgTfRydJbuUC8vtgc7rdHY4g7IdGlOM+LWdor23P16vzfVKGNDNbi072S0vzkt+\\nQ/WLb9UuQi64wB3LxVLDfUKNg2OGJ6/ju1bZX+Fo02hG6lkMa2BO3CwmirGRLiWb\\n4wIDAQAB\\n-----END PUBLIC KEY-----\\n"
}

additional test conducted

  • PUT an arbitrary String as body -> get accepted (but is useless for JWT)
  • tried the key rsa:_default -> same error 400
  • manually edit /opt/couchdb/etc/local.d
cat << EOF > jwt.ini
[chttpd]
authentication_handlers = {chttpd_auth, cookie_authentication_handler}, {chttpd_auth, jwt_authentication_handler}, {chttpd_auth, default_authentication_handler}

[jwt_keys]
rsa:S1-oBDEUlMfN-FP5EeG6UcaKdeCs01_dx5AIw-SogiQ = -----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9SJFyVWvBonL3K+giuz\neQ4Vp1bH9ftuzjrtLMMBUWESQEMXsml7s58/8UOWQ40j71eu+63sLvCnLhcP9jmK\nI8vwofkMo91ulZn2ntKTsawJmnrR7k1W5okbLlnwYq1KN3SRcjeHYa3JruoDmHHW\n9dO5dAGu09ookgWxYr2K1jXT1+L1NFOfBXqsjFqr3a+ArMOg5POcg9I6lI9kmi8a\nOJgTfRydJbuUC8vtgc7rdHY4g7IdGlOM+LWdor23P16vzfVKGNDNbi072S0vzkt+\nQ/WLb9UuQi64wB3LxVLDfUKNg2OGJ6/ju1bZX+Fo02hG6lkMa2BO3CwmirGRLiWb\n4wIDAQAB\n-----END PUBLIC KEY-----\n

EOF

then restart couchdb, JWT auth works like a charm

Your Environment

  • Couch in a docker container on current macOS
  • Chrome, current version
{
    "couchdb": "Welcome",
    "version": "3.3.3",
    "git_sha": "40afbcfc7",
    "uuid": "0882075ae09fe0a7a70fb7c6c4a1f01e",
    "features": [
        "access-ready",
        "partitioned",
        "pluggable-storage-engines",
        "reshard",
        "scheduler"
    ],
    "vendor": {
        "name": "The Apache Software Foundation"
    }
}

Additional Context

The public key is derived from a jwks entry found here and converted using this project with the goal to allow automatic updates when IdP keys change

@Stwissel
Copy link
Author

.... aaaaand once submitted the ticket, the solution presented itself:

WRONG

curl --request PUT 'http:https://localhost:5984/_node/nonode@nohost/_config/jwt_keys/rsa:S1-oBDEUlMfN-FP5EeG6UcaKdeCs01_dx5AIw-SogiQ' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \
--data '"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9SJFyVWvBonL3K+giuzeQ4Vp1bH9ftu\nzjrtLMMBUWESQEMXsml7s58/8UOWQ40j71eu+63sLvCnLhcP9jmKI8vwofkMo91ulZn2ntKTsawJ\nmnrR7k1W5okbLlnwYq1KN3SRcjeHYa3JruoDmHHW9dO5dAGu09ookgWxYr2K1jXT1+L1NFOfBXqs\njFqr3a+ArMOg5POcg9I6lI9kmi8aOJgTfRydJbuUC8vtgc7rdHY4g7IdGlOM+LWdor23P16vzfVK\nGNDNbi072S0vzkt+Q/WLb9UuQi64wB3LxVLDfUKNg2OGJ6/ju1bZX+Fo02hG6lkMa2BO3CwmirGR\nLiWb4wIDAQAB\n-----END PUBLIC KEY-----\n"'

Right

curl --request PUT 'http:https://localhost:5984/_node/nonode@nohost/_config/jwt_keys/rsa:S1-oBDEUlMfN-FP5EeG6UcaKdeCs01_dx5AIw-SogiQ' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic YWRtaW46cGFzc3dvcmQ=' \
--data '"-----BEGIN PUBLIC KEY-----\\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx9SJFyVWvBonL3K+giuzeQ4Vp1bH9ftu\\nzjrtLMMBUWESQEMXsml7s58/8UOWQ40j71eu+63sLvCnLhcP9jmKI8vwofkMo91ulZn2ntKTsawJ\\nmnrR7k1W5okbLlnwYq1KN3SRcjeHYa3JruoDmHHW9dO5dAGu09ookgWxYr2K1jXT1+L1NFOfBXqs\\njFqr3a+ArMOg5POcg9I6lI9kmi8aOJgTfRydJbuUC8vtgc7rdHY4g7IdGlOM+LWdor23P16vzfVK\\nGNDNbi072S0vzkt+Q/WLb9UuQi64wB3LxVLDfUKNg2OGJ6/ju1bZX+Fo02hG6lkMa2BO3CwmirGR\\nLiWb4wIDAQAB\\n-----END PUBLIC KEY-----\\n"'

http treats \n as new line on submission, but the ini value needs to be the String \n, so it needs another \ to be sent as \\n. Then it works as advertised.

@rnewson
Copy link
Member

rnewson commented Jun 18, 2024

Glad you figured it out. To confirm, this is your shell converting the \n in your --data into actual newline characters, and it is that which the config PUT code is rejecting (for not matching the regexp "^[[:graph:]\t\s]*$").

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants