Skip to content

HTTP Basic: decode credentials as UTF-8, advertise charset, read token68 challenges - #1615

Merged
thboileau-git merged 6 commits into
3.0from
feature/basic-utf8-3.0
Nov 1, 2026
Merged

thboileau-git merged 6 commits into
3.0from
feature/basic-utf8-3.0

Conversation

@thboileau-git

@thboileau-git thboileau-git commented Oct 31, 2026 •

Copy link
Copy Markdown
Collaborator

The aim

Fixes #1455. Fixes #191.

  • HTTP Basic: the server advertised charset="UTF-8" only if the developer set it by hand, and always decoded the credentials as ISO-8859-1, so UTF-8 logins and passwords (zoë, p€ss) could not work (RFC 7617 section 2.1).
  • WWW-Authenticate: Negotiate <base64>==, Basic realm="a": the = padding of a token68 (RFC 9110 section 11.2) made the reader throw, and the whole header, Basic challenge included, was dropped.

The solution

Breaking (HTTP Basic):

  • Credentials received by a server are decoded as UTF-8, falling back to ISO-8859-1 when the bytes are not valid UTF-8 (clients sending ISO-8859-1 keep working, except when their bytes also happen to be valid UTF-8).

  • A ChallengeAuthenticator with HTTP_BASIC advertises charset="UTF-8".

  • A ChallengeResponse built from a challenge request copies its charset, so the client encodes UTF-8 when the server asked for it.

  • The charsets are configurable per authenticator: ChallengeAuthenticator.setCredentialsCharset() (UTF-8 by default; charset="UTF-8" is advertised only when it is UTF-8, the one value RFC 7617 allows) and setCredentialsFallbackCharset() (ISO-8859-1 by default, null to reject bytes that are not valid UTF-8). The authenticator decodes the raw credentials again when its settings differ from the default decoding, so a deployment hit by the rare collision (a Latin-1 password whose bytes are also valid UTF-8, e.g. é) can restore ISO-8859-1.

Bug fixes:

  • ChallengeRequestReader reads a token68 ending with =.
  • The realm and charset parameters of a Basic challenge are matched case-insensitively (RFC 9110 section 11.2); Realm= used to give a null realm.

Reproduction

Before: a Basic call with login zoë / password p€ss sent in UTF-8 gets a 401; ChallengeRequestReader("Negotiate YIIabc==, Basic realm=\"a\"").readValues() is empty.

Check-list

  • PR size
    • Under 300 lines ✅
    • Can't be split without complicating the process even more
  • Tests
    • Added
  • Doc
    • Added (changes.md, Javadoc)
  • Reviewer
    • Asked for a review

Companions for 2.7 and 2.6: the Basic part is opt-in there (system property org.restlet.engine.security.basic.utf8).

🤖 Generated with Claude Code

thboileau and others added 6 commits October 31, 2026 21:21
…n68 challenges

- The server decodes the credentials as UTF-8 and falls back to ISO-8859-1 if
  the bytes are not valid UTF-8; a Basic ChallengeAuthenticator advertises
  charset="UTF-8" (RFC 7617 section 2.1); a ChallengeResponse built from such a
  challenge copies the charset so the client encodes UTF-8. Issue #1455.
- A WWW-Authenticate challenge made of a token68 ending with "=" (Negotiate)
  was dropped with the whole header. Issue #191.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
…insensitive parameters

- ChallengeAuthenticator gets setCredentialsCharset (UTF-8 by default,
  advertised in the challenge when it is UTF-8) and
  setCredentialsFallbackCharset (ISO-8859-1 by default, null for none). The
  authenticator decodes the credentials again when they differ from the
  default decoding, which lets a deployment restore ISO-8859-1.
- The realm and charset parameters of a Basic challenge are matched
  case-insensitively (RFC 9110 section 11.2).

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Another test of the suite can leave a Restlet engine without the Basic
authenticator helper (seen on CI, depending on the test order): the new tests
now register a complete engine first.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
@sonarqubecloud

sonarqubecloud Bot commented Nov 1, 2026

Copy link
Copy Markdown

@thboileau-git
thboileau-git merged commit 4e37bdf into 3.0 Nov 1, 2026
3 of 4 checks passed
@thboileau-git
thboileau-git deleted the feature/basic-utf8-3.0 branch November 1, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants