{
OAUTH_STATE_INIT = 0,
OAUTH_STATE_ERROR,
+ OAUTH_STATE_ERROR_DISCOVERY,
OAUTH_STATE_FINISHED,
};
break;
case OAUTH_STATE_ERROR:
+ case OAUTH_STATE_ERROR_DISCOVERY:
/*
* Only one response is valid for the client during authentication
errmsg("malformed OAUTHBEARER message"),
errdetail("Client did not send a kvsep response."));
- /* The (failed) handshake is now complete. */
+ /*
+ * The (failed) handshake is now complete. Don't report discovery
+ * requests in the server log unless the log level is high enough.
+ */
+ if (ctx->state == OAUTH_STATE_ERROR_DISCOVERY)
+ {
+ ereport(DEBUG1, errmsg("OAuth issuer discovery requested"));
+
+ ctx->state = OAUTH_STATE_FINISHED;
+ return PG_SASL_EXCHANGE_ABANDONED;
+ }
+
+ /* We're not in discovery, so this is just a normal auth failure. */
ctx->state = OAUTH_STATE_FINISHED;
return PG_SASL_EXCHANGE_FAILURE;
errmsg("malformed OAUTHBEARER message"),
errdetail("Message contains additional data after the final terminator."));
- if (!validate(ctx->port, auth))
+ if (auth[0] == '\0')
+ {
+ /*
+ * An empty auth value represents a discovery request; the client
+ * expects it to fail. Skip validation entirely and move directly to
+ * the error response.
+ */
+ generate_error_response(ctx, output, outputlen);
+
+ ctx->state = OAUTH_STATE_ERROR_DISCOVERY;
+ status = PG_SASL_EXCHANGE_CONTINUE;
+ }
+ else if (!validate(ctx->port, auth))
{
generate_error_response(ctx, output, outputlen);
/* Missing auth headers should be handled by the caller. */
Assert(header);
-
- if (header[0] == '\0')
- {
- /*
- * A completely empty auth header represents a query for
- * authentication parameters. The client expects it to fail; there's
- * no need to make any extra noise in the logs.
- *
- * TODO: should we find a way to return STATUS_EOF at the top level,
- * to suppress the authentication error entirely?
- */
- return NULL;
- }
+ /* Empty auth (discovery) should be handled before calling validate(). */
+ Assert(header[0] != '\0');
if (pg_strncasecmp(header, BEARER_SCHEME, strlen(BEARER_SCHEME)))
{
qr/oauth_validator: issuer="\Q$issuer\E", scope="openid postgres"/,
qr/connection authenticated: identity="test" method=oauth/,
qr/connection authorized/,
- ]);
+ ],
+ log_unlike => [qr/FATAL.*OAuth bearer authentication failed/]);
# Enable PGOAUTHDEBUG for all remaining tests.
$ENV{PGOAUTHDEBUG} = "UNSAFE";
qr|oauth_validator: issuer="\Q$issuer/.well-known/oauth-authorization-server/alternate\E", scope="openid postgres alt"|,
qr/connection authenticated: identity="testalt" method=oauth/,
qr/connection authorized/,
- ]);
+ ],
+ log_unlike => [qr/FATAL.*OAuth bearer authentication failed/]);
# The issuer linked by the server must match the client's oauth_issuer setting.
$node->connect_fails(