28 const char *sasl_mechanism);
30 char *
input,
int inputlen,
31 char **
output,
int *outputlen);
49 const char *sasl_mechanism)
57 Assert(sasl_mechanism != NULL);
103 static const char *
const resp_format =
"n,," kvsep "auth=%s%s" kvsep kvsep;
106 const char *authn_scheme;
107 char *response = NULL;
113 authn_scheme =
token =
"";
121 authn_scheme =
"Bearer ";
128 "internal error: no OAuth token was set for the connection");
137 response = strdup(
buf.data);
151#define ERROR_STATUS_FIELD "status"
152#define ERROR_SCOPE_FIELD "scope"
153#define ERROR_OPENID_CONFIGURATION_FIELD "openid-configuration"
170#define oauth_json_has_error(ctx) \
171 (PQExpBufferDataBroken((ctx)->errbuf) || (ctx)->errmsg)
173#define oauth_json_set_error(ctx, ...) \
175 appendPQExpBuffer(&(ctx)->errbuf, __VA_ARGS__); \
176 (ctx)->errmsg = (ctx)->errbuf.data; \
276 "internal error: target scalar found at nesting level %d during OAUTHBEARER parsing",
317#define HTTPS_SCHEME "https://"
318#define HTTP_SCHEME "http://"
321#define WK_PREFIX "/.well-known/"
322#define OPENID_WK_SUFFIX "openid-configuration"
323#define OAUTH_WK_SUFFIX "oauth-authorization-server"
332 const char *authority_start = NULL;
333 const char *wk_start;
336 ptrdiff_t start_offset,
357 if (!authority_start)
360 "OAuth discovery URI \"%s\" must use HTTPS",
374 if (strpbrk(authority_start,
"?#") != NULL)
377 "OAuth discovery URI \"%s\" must not contain query or fragment components",
388 wk_start = strstr(authority_start,
WK_PREFIX);
392 "OAuth discovery URI \"%s\" is not a .well-known URI",
415 if (!wk_end || (*wk_end !=
'/' && *wk_end !=
'\0'))
418 "OAuth discovery URI \"%s\" uses an unsupported .well-known suffix",
435 const char *path_start;
437 path_start = strchr(authority_start,
'/');
440 if (wk_start != path_start)
443 "OAuth discovery URI \"%s\" uses an invalid format",
450 issuer = strdup(wkuri);
462 start_offset = wk_start - wkuri;
463 end_offset = wk_end - wkuri;
464 end_len = strlen(wk_end) + 1;
466 memmove(issuer + start_offset, issuer + end_offset, end_len);
489 if (strlen(msg) != msglen)
492 "server's error message contained an embedded NULL, and was discarded");
503 "server's error response is not valid UTF-8");
534 errmsg =
"<unexpected empty error>";
542 "failed to parse server's error response: %s",
554 char *discovery_issuer;
567 if (!discovery_issuer)
573 "server's discovery document at %s (issuer \"%s\") is incompatible with oauth_issuer (%s)",
577 free(discovery_issuer);
581 free(discovery_issuer);
594 "server's discovery document has moved to %s (previous location was %s)",
615 "server sent error response without a status");
619 if (strcmp(ctx.
status,
"invalid_token") != 0)
626 "server rejected OAuth bearer token: %s",
659 "user-defined OAuth flow provided neither a token nor an async callback");
679 "user-defined OAuth flow did not provide a token");
697 "user-defined OAuth flow did not provide a socket for polling");
721 state->async_ctx = NULL;
777 request_copy =
malloc(
sizeof(*request_copy));
784 memcpy(request_copy, &request,
sizeof(request));
788 state->async_ctx = request_copy;
854 "server requires OAuth authentication, but oauth_issuer and oauth_client_id are not both set");
909 char *
input,
int inputlen,
910 char **
output,
int *outputlen)
914 bool discover =
false;
988 *outputlen = strlen(*
output);
1014 "server sent unexpected additional OAuth data");
1028 *outputlen = strlen(*
output);
1054 "server requires OAuth authentication, but no discovery metadata was provided");
1092 "internal error: OAuth flow did not set a token");
1110 "server sent additional OAuth data after error");
1160 const char *env = getenv(
"PGOAUTHDEBUG");
1162 return (env && strcmp(env,
"UNSAFE") == 0);
static void cleanup(void)
int errmsg(const char *fmt,...)
void err(int eval, const char *fmt,...)
PostgresPollingStatusType pg_fe_run_oauth_flow(PGconn *conn)
void pg_fe_cleanup_oauth_flow(PGconn *conn)
#define ERROR_SCOPE_FIELD
static bool setup_token_request(PGconn *conn, fe_oauth_state *state)
static char * issuer_from_well_known_uri(PGconn *conn, const char *wkuri)
static bool handle_oauth_sasl_error(PGconn *conn, const char *msg, int msglen)
static void cleanup_user_oauth_flow(PGconn *conn)
static bool setup_oauth_parameters(PGconn *conn)
#define oauth_json_set_error(ctx,...)
static JsonParseErrorType oauth_json_object_field_start(void *state, char *name, bool isnull)
static JsonParseErrorType oauth_json_scalar(void *state, char *token, JsonTokenType type)
const pg_fe_sasl_mech pg_oauth_mech
static SASLStatus oauth_exchange(void *opaq, bool final, char *input, int inputlen, char **output, int *outputlen)
static bool oauth_channel_bound(void *opaq)
#define oauth_json_has_error(ctx)
static JsonParseErrorType oauth_json_array_start(void *state)
static JsonParseErrorType oauth_json_object_end(void *state)
static void oauth_free(void *opaq)
#define ERROR_OPENID_CONFIGURATION_FIELD
void pqClearOAuthToken(PGconn *conn)
static void * oauth_init(PGconn *conn, const char *password, const char *sasl_mechanism)
static char * client_initial_response(PGconn *conn, bool discover)
#define ERROR_STATUS_FIELD
static JsonParseErrorType oauth_json_object_start(void *state)
static PostgresPollingStatusType run_user_oauth_flow(PGconn *conn)
bool oauth_unsafe_debugging_enabled(void)
@ FE_OAUTH_REQUESTING_TOKEN
PQauthDataHook_type PQauthDataHook
void libpq_append_conn_error(PGconn *conn, const char *fmt,...)
Assert(PointerIsAligned(start, uint64))
JsonParseErrorType pg_parse_json(JsonLexContext *lex, const JsonSemAction *sem)
JsonLexContext * makeJsonLexContextCstringLen(JsonLexContext *lex, const char *json, size_t len, int encoding, bool need_escapes)
void setJsonLexContextOwnsTokens(JsonLexContext *lex, bool owned_by_context)
char * json_errdetail(JsonParseErrorType error, JsonLexContext *lex)
void freeJsonLexContext(JsonLexContext *lex)
PostgresPollingStatusType
@ PQAUTHDATA_OAUTH_BEARER_TOKEN
void explicit_bzero(void *buf, size_t len)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
void initPQExpBuffer(PQExpBuffer str)
void appendPQExpBuffer(PQExpBuffer str, const char *fmt,...)
void termPQExpBuffer(PQExpBuffer str)
#define PQExpBufferDataBroken(buf)
json_struct_action object_start
json_ofield_action object_field_start
json_scalar_action scalar
json_struct_action array_start
json_struct_action object_end
void(* cleanup)(PGconn *conn, struct PGoauthBearerRequest *request)
const char * openid_configuration
PostgresPollingStatusType(* async)(PGconn *conn, struct PGoauthBearerRequest *request, SOCKTYPE *altsock)
const char * target_field_name
char * oauth_discovery_uri
void(* cleanup_async_auth)(PGconn *conn)
bool client_finished_auth
PostgresPollingStatusType(* async_auth)(PGconn *conn)
int pg_encoding_verifymbstr(int encoding, const char *mbstr, int len)