Age Owner Branch data TLA 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 : :
198 dgustafsson@postgres 22 :CBC 86 : 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 *res);
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 : 86 : _PG_init(void)
57 : : {
58 : 86 : 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 : 86 : 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 : 86 : MarkGUCPrefixReserved("oauth_validator");
76 : 86 : }
77 : :
78 : : /*
79 : : * Validator module entry point.
80 : : */
81 : : const OAuthValidatorCallbacks *
82 : 86 : _PG_oauth_validator_module_init(void)
83 : : {
84 : 86 : 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 : 86 : 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 [ - + ]: 86 : if (state->sversion != PG_VERSION_NUM)
198 dgustafsson@postgres 100 [ # # ]:UBC 0 : elog(ERROR, "oauth_validator: sversion set to %d", state->sversion);
101 : :
198 dgustafsson@postgres 102 :CBC 86 : state->private_data = PRIVATE_COOKIE;
103 : 86 : }
104 : :
105 : : /*
106 : : * Shutdown callback, to tear down the validator.
107 : : */
108 : : static void
109 : 86 : validator_shutdown(ValidatorModuleState *state)
110 : : {
111 : : /* Check to make sure our private state still exists. */
112 [ - + ]: 86 : if (state->private_data != PRIVATE_COOKIE)
198 dgustafsson@postgres 113 [ # # ]:UBC 0 : elog(PANIC, "oauth_validator: private state cookie changed to %p in shutdown",
114 : : state->private_data);
198 dgustafsson@postgres 115 :CBC 86 : }
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 : 32 : 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 [ - + ]: 32 : if (state->private_data != PRIVATE_COOKIE)
198 dgustafsson@postgres 128 [ # # ]:UBC 0 : elog(ERROR, "oauth_validator: private state cookie changed to %p in validate",
129 : : state->private_data);
130 : :
198 dgustafsson@postgres 131 [ + - ]:CBC 32 : elog(LOG, "oauth_validator: token=\"%s\", role=\"%s\"", token, role);
132 [ + - ]: 32 : elog(LOG, "oauth_validator: issuer=\"%s\", scope=\"%s\"",
133 : : MyProcPort->hba->oauth_issuer,
134 : : MyProcPort->hba->oauth_scope);
135 : :
136 : 32 : res->authorized = authorize_tokens;
137 [ + + ]: 32 : if (authn_id)
138 : 5 : res->authn_id = pstrdup(authn_id);
139 : : else
140 : 27 : res->authn_id = pstrdup(role);
141 : :
142 : 32 : return true;
143 : : }
|