1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
/*-------------------------------------------------------------------------
*
* validator.c
* Test module for serverside OAuth token validation callbacks
*
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/test/modules/oauth_validator/validator.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "fmgr.h"
#include "libpq/oauth.h"
#include "miscadmin.h"
#include "utils/guc.h"
#include "utils/memutils.h"
PG_MODULE_MAGIC;
static void validator_startup(ValidatorModuleState *state);
static void validator_shutdown(ValidatorModuleState *state);
static bool validate_token(const ValidatorModuleState *state,
const char *token,
const char *role,
ValidatorModuleResult *result);
/* Callback implementations (exercise all three) */
static const OAuthValidatorCallbacks validator_callbacks = {
PG_OAUTH_VALIDATOR_MAGIC,
.startup_cb = validator_startup,
.shutdown_cb = validator_shutdown,
.validate_cb = validate_token
};
/* GUCs */
static char *authn_id = NULL;
static bool authorize_tokens = true;
/*---
* Extension entry point. Sets up GUCs for use by tests:
*
* - oauth_validator.authn_id Sets the user identifier to return during token
* validation. Defaults to the username in the
* startup packet.
*
* - oauth_validator.authorize_tokens
* Sets whether to successfully validate incoming
* tokens. Defaults to true.
*/
void
_PG_init(void)
{
DefineCustomStringVariable("oauth_validator.authn_id",
"Authenticated identity to use for future connections",
NULL,
&authn_id,
NULL,
PGC_SIGHUP,
0,
NULL, NULL, NULL);
DefineCustomBoolVariable("oauth_validator.authorize_tokens",
"Should tokens be marked valid?",
NULL,
&authorize_tokens,
true,
PGC_SIGHUP,
0,
NULL, NULL, NULL);
MarkGUCPrefixReserved("oauth_validator");
}
/*
* Validator module entry point.
*/
const OAuthValidatorCallbacks *
_PG_oauth_validator_module_init(void)
{
return &validator_callbacks;
}
#define PRIVATE_COOKIE ((void *) 13579)
/*
* Startup callback, to set up private data for the validator.
*/
static void
validator_startup(ValidatorModuleState *state)
{
/*
* Make sure the server is correctly setting sversion. (Real modules
* should not do this; it would defeat upgrade compatibility.)
*/
if (state->sversion != PG_VERSION_NUM)
elog(ERROR, "oauth_validator: sversion set to %d", state->sversion);
state->private_data = PRIVATE_COOKIE;
}
/*
* Shutdown callback, to tear down the validator.
*/
static void
validator_shutdown(ValidatorModuleState *state)
{
/* Check to make sure our private state still exists. */
if (state->private_data != PRIVATE_COOKIE)
elog(PANIC, "oauth_validator: private state cookie changed to %p in shutdown",
state->private_data);
}
/*
* Validator implementation. Logs the incoming data and authorizes the token by
* default; the behavior can be modified via the module's GUC settings.
*/
static bool
validate_token(const ValidatorModuleState *state,
const char *token, const char *role,
ValidatorModuleResult *res)
{
/* Check to make sure our private state still exists. */
if (state->private_data != PRIVATE_COOKIE)
elog(ERROR, "oauth_validator: private state cookie changed to %p in validate",
state->private_data);
elog(LOG, "oauth_validator: token=\"%s\", role=\"%s\"", token, role);
elog(LOG, "oauth_validator: issuer=\"%s\", scope=\"%s\"",
MyProcPort->hba->oauth_issuer,
MyProcPort->hba->oauth_scope);
res->authorized = authorize_tokens;
if (authn_id)
res->authn_id = pstrdup(authn_id);
else
res->authn_id = pstrdup(role);
return true;
}
|