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