37static void *
oauth_init(
Port *
port,
const char *selected_mech,
const char *shadow_pass);
39 char **
output,
int *outputlen,
const char **logdetail);
80#define AUTH_KEY "auth"
81#define BEARER_SCHEME "Bearer "
108 errcode(ERRCODE_PROTOCOL_VIOLATION),
109 errmsg(
"client selected an invalid SASL authentication mechanism"));
135 char **
output,
int *outputlen,
const char **logdetail)
168 errcode(ERRCODE_PROTOCOL_VIOLATION),
169 errmsg(
"malformed OAUTHBEARER message"),
171 if (inputlen != strlen(
input))
173 errcode(ERRCODE_PROTOCOL_VIOLATION),
174 errmsg(
"malformed OAUTHBEARER message"),
175 errdetail(
"Message length does not match input length."));
191 errcode(ERRCODE_PROTOCOL_VIOLATION),
192 errmsg(
"malformed OAUTHBEARER message"),
193 errdetail(
"Client did not send a kvsep response."));
200 elog(
ERROR,
"invalid OAUTHBEARER exchange state");
219 errcode(ERRCODE_PROTOCOL_VIOLATION),
220 errmsg(
"malformed OAUTHBEARER message"),
221 errdetail(
"The server does not support channel binding for OAuth, but the client message includes channel binding data."));
229 errcode(ERRCODE_PROTOCOL_VIOLATION),
230 errmsg(
"malformed OAUTHBEARER message"),
231 errdetail(
"Comma expected, but found character \"%s\".",
238 errcode(ERRCODE_PROTOCOL_VIOLATION),
239 errmsg(
"malformed OAUTHBEARER message"),
240 errdetail(
"Unexpected channel-binding flag \"%s\".",
249 errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
250 errmsg(
"client uses authorization identity, but it is not supported"));
253 errcode(ERRCODE_PROTOCOL_VIOLATION),
254 errmsg(
"malformed OAUTHBEARER message"),
255 errdetail(
"Unexpected attribute \"%s\" in client-first-message.",
262 errcode(ERRCODE_PROTOCOL_VIOLATION),
263 errmsg(
"malformed OAUTHBEARER message"),
264 errdetail(
"Key-value separator expected, but found character \"%s\".",
271 errcode(ERRCODE_PROTOCOL_VIOLATION),
272 errmsg(
"malformed OAUTHBEARER message"),
273 errdetail(
"Message does not contain an auth value."));
278 errcode(ERRCODE_PROTOCOL_VIOLATION),
279 errmsg(
"malformed OAUTHBEARER message"),
280 errdetail(
"Message contains additional data after the final terminator."));
314 if (
c >= 0x21 &&
c <= 0x7E)
333 static const char *key_allowed_set =
334 "abcdefghijklmnopqrstuvwxyz"
335 "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
341 errcode(ERRCODE_PROTOCOL_VIOLATION),
342 errmsg(
"malformed OAUTHBEARER message"),
343 errdetail(
"Message contains an empty key name."));
345 span = strspn(
key, key_allowed_set);
346 if (
key[span] !=
'\0')
348 errcode(ERRCODE_PROTOCOL_VIOLATION),
349 errmsg(
"malformed OAUTHBEARER message"),
350 errdetail(
"Message contains an invalid key name."));
361 if (0x21 <= *
val && *
val <= 0x7E)
374 errcode(ERRCODE_PROTOCOL_VIOLATION),
375 errmsg(
"malformed OAUTHBEARER message"),
376 errdetail(
"Message contains an invalid value."));
416 end = strchr(pos,
KVSEP);
419 errcode(ERRCODE_PROTOCOL_VIOLATION),
420 errmsg(
"malformed OAUTHBEARER message"),
421 errdetail(
"Message contains an unterminated key/value pair."));
434 sep = strchr(pos,
'=');
437 errcode(ERRCODE_PROTOCOL_VIOLATION),
438 errmsg(
"malformed OAUTHBEARER message"),
439 errdetail(
"Message contains a key without a value."));
451 errcode(ERRCODE_PROTOCOL_VIOLATION),
452 errmsg(
"malformed OAUTHBEARER message"),
453 errdetail(
"Message contains multiple auth values."));
471 errcode(ERRCODE_PROTOCOL_VIOLATION),
472 errmsg(
"malformed OAUTHBEARER message"),
473 errdetail(
"Message did not contain a final terminator."));
498 errcode(ERRCODE_INTERNAL_ERROR),
499 errmsg(
"OAuth is not properly configured for this user"),
500 errdetail_log(
"The issuer and scope parameters must be set in pg_hba.conf."));
508 if (strstr(ctx->
issuer,
"/.well-known/") == NULL)
530 *outputlen =
buf.len;
560 static const char *
const b64token_allowed_set =
561 "abcdefghijklmnopqrstuvwxyz"
562 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
568 if (header[0] ==
'\0')
584 errcode(ERRCODE_PROTOCOL_VIOLATION),
585 errmsg(
"malformed OAuth bearer token"),
586 errdetail_log(
"Client response indicated a non-Bearer authentication scheme."));
594 while (*
token ==
' ')
601 errcode(ERRCODE_PROTOCOL_VIOLATION),
602 errmsg(
"malformed OAuth bearer token"),
611 span = strspn(
token, b64token_allowed_set);
612 while (
token[span] ==
'=')
615 if (
token[span] !=
'\0')
623 errcode(ERRCODE_PROTOCOL_VIOLATION),
624 errmsg(
"malformed OAuth bearer token"),
625 errdetail_log(
"Bearer token is not in the correct format."));
655 errcode(ERRCODE_INTERNAL_ERROR),
656 errmsg(
"validation of OAuth token requested without a validator loaded"));
661 port->user_name, ret))
664 errcode(ERRCODE_INTERNAL_ERROR),
665 errmsg(
"internal error in OAuth validator module"));
679 errmsg(
"OAuth bearer authentication failed for user \"%s\"",
681 errdetail_log(
"Validator failed to authorize the provided token."));
687 if (
port->hba->oauth_skip_usermap)
703 errmsg(
"OAuth bearer authentication failed for user \"%s\"",
748 Assert(libname && *libname);
758 if (validator_init == NULL)
760 errmsg(
"%s module \"%s\" must define the symbol %s",
761 "OAuth validator", libname,
"_PG_oauth_validator_module_init"));
773 errmsg(
"%s module \"%s\": magic number mismatch",
774 "OAuth validator", libname),
775 errdetail(
"Server has magic number 0x%08X, module has 0x%08X.",
784 errmsg(
"%s module \"%s\" must provide a %s callback",
785 "OAuth validator", libname,
"validate_cb"));
832 errcode(ERRCODE_CONFIG_FILE_ERROR),
833 errmsg(
"oauth_validator_libraries must be set for authentication method %s",
835 errcontext(
"line %d of configuration file \"%s\"",
836 line_num, file_name));
837 *err_msg =
psprintf(
"oauth_validator_libraries must be set for authentication method %s",
849 errcode(ERRCODE_CONFIG_FILE_ERROR),
850 errmsg(
"invalid list syntax in parameter \"%s\"",
851 "oauth_validator_libraries"));
852 *err_msg =
psprintf(
"invalid list syntax in parameter \"%s\"",
853 "oauth_validator_libraries");
859 if (elemlist->
length == 1)
866 errcode(ERRCODE_CONFIG_FILE_ERROR),
867 errmsg(
"authentication method \"oauth\" requires argument \"validator\" to be set when oauth_validator_libraries contains multiple options"),
868 errcontext(
"line %d of configuration file \"%s\"",
869 line_num, file_name));
870 *err_msg =
"authentication method \"oauth\" requires argument \"validator\" to be set when oauth_validator_libraries contains multiple options";
881 errcode(ERRCODE_INVALID_PARAMETER_VALUE),
882 errmsg(
"validator \"%s\" is not permitted by %s",
884 errcontext(
"line %d of configuration file \"%s\"",
885 line_num, file_name));
886 *err_msg =
psprintf(
"validator \"%s\" is not permitted by %s",
893 return (*err_msg == NULL);
static void shutdown_validator_library(void *arg)
static void generate_error_response(struct oauth_ctx *ctx, char **output, int *outputlen)
static bool validate(Port *port, const char *auth)
char * oauth_validator_libraries_string
static const OAuthValidatorCallbacks * ValidatorCallbacks
static void validate_kvpair(const char *key, const char *val)
bool check_oauth_validator(HbaLine *hbaline, int elevel, char **err_msg)
static void * oauth_init(Port *port, const char *selected_mech, const char *shadow_pass)
static const char * validate_token_format(const char *header)
static char * sanitize_char(char c)
static void oauth_get_mechanisms(Port *port, StringInfo buf)
static int oauth_exchange(void *opaq, const char *input, int inputlen, char **output, int *outputlen, const char **logdetail)
static char * parse_kvpairs_for_auth(char **input)
static void load_validator_library(const char *libname)
const pg_be_sasl_mech pg_be_oauth_mech
static ValidatorModuleState * validator_module_state
void set_authn_id(Port *port, const char *id)
#define PG_MAX_AUTH_TOKEN_LENGTH
static void cleanup(void)
void * load_external_function(const char *filename, const char *funcname, bool signalNotFound, void **filehandle)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
int errdetail_log(const char *fmt,...)
#define ereport(elevel,...)
Assert(PointerIsAligned(start, uint64))
int check_usermap(const char *usermap_name, const char *pg_user, const char *system_user, bool case_insensitive)
void escape_json(StringInfo buf, const char *str)
void list_free_deep(List *list)
char * pstrdup(const char *in)
void MemoryContextRegisterResetCallback(MemoryContext context, MemoryContextCallback *cb)
void pfree(void *pointer)
void * palloc0(Size size)
MemoryContext CurrentMemoryContext
ClientConnectionInfo MyClientConnectionInfo
#define PG_OAUTH_VALIDATOR_MAGIC
const OAuthValidatorCallbacks *(* OAuthValidatorModuleInit)(void)
#define foreach_ptr(type, var, lst)
void explicit_bzero(void *buf, size_t len)
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
char * psprintf(const char *fmt,...)
#define PG_SASL_EXCHANGE_FAILURE
#define PG_SASL_EXCHANGE_CONTINUE
#define PG_SASL_EXCHANGE_SUCCESS
void appendStringInfoString(StringInfo str, const char *s)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
MemoryContextCallbackFunction func
ValidatorShutdownCB shutdown_cb
ValidatorValidateCB validate_cb
ValidatorStartupCB startup_cb
void(* get_mechanisms)(Port *port, StringInfo buf)
bool SplitDirectoriesString(char *rawstring, char separator, List **namelist)