Skip to content

Commit

Permalink
add NGINX functions for setting claim variables in the request context
Browse files Browse the repository at this point in the history
see OpenIDC/ngx_oauth2_module#7; thanks @@smanolache and @pladen; bump
to 1.6.3dev

Signed-off-by: Hans Zandbelt <[email protected]>
  • Loading branch information
zandbelt committed Jun 19, 2024
1 parent 1c9bbeb commit 6537014
Show file tree
Hide file tree
Showing 7 changed files with 304 additions and 3 deletions.
2 changes: 2 additions & 0 deletions AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ reporting bugs, providing fixes, suggesting useful features or other:
Robert Title <https://github.com/rtitle>
may-day <https://github.com/may-day>
Pavel Anpin <https://github.com/anpin>
smanolache <https://github.com/smanolache>
pladen <https://github.com/pladen>
5 changes: 5 additions & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
06/19/2024
- add NGINX macros/functions for setting claim variables in the request context
see OpenIDC/ngx_oauth2_module#7; thanks @@smanolache and @pladen
- bump to 1.6.3dev
.
06/05/2024
- release 1.6.2

Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
AC_INIT([liboauth2],[1.6.2],[[email protected]])
AC_INIT([liboauth2],[1.6.3dev],[[email protected]])

AM_INIT_AUTOMAKE([foreign no-define subdir-objects])
AC_CONFIG_MACRO_DIR([m4])
Expand Down
33 changes: 33 additions & 0 deletions include/oauth2/nginx.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,4 +140,37 @@ ngx_int_t oauth2_nginx_http_response_set(oauth2_log_t *log,
oauth2_http_response_t *response,
ngx_http_request_t *r);

//

char *oauth2_nginx_str2chr(ngx_pool_t *p, const ngx_str_t *str);

#define OAUTH2_NGINX_CMD_SET_IMPL(module, primitive) \
static ngx_int_t ngx_##module##_##primitive##_variable( \
ngx_http_request_t *r, ngx_http_variable_value_t *v, \
uintptr_t data) \
{ \
return oauth2_nginx_##primitive##_variable( \
ngx_##module##_module, r, v, data); \
} \
\
static char *ngx_##module##_set_##primitive( \
ngx_conf_t *cf, ngx_command_t *cmd, void *conf) \
{ \
return oauth2_nginx_set_##primitive( \
ngx_##module##_module, \
ngx_##module##_##primitive##_variable, cf, cmd, conf); \
}

ngx_int_t oauth2_nginx_claim_variable(ngx_module_t module,
ngx_http_request_t *r,
ngx_http_variable_value_t *v,
uintptr_t data);
char *oauth2_nginx_set_claim(ngx_module_t module,
ngx_http_get_variable_pt handler, ngx_conf_t *cf,
ngx_command_t *cmd, void *conf);

ngx_int_t oauth2_nginx_set_target_variables(ngx_module_t module,
oauth2_nginx_request_context_t *ctx,
json_t *json_token);

#endif /* _OAUTH2_NGINX_H_ */
214 changes: 214 additions & 0 deletions src/server/nginx.c
Original file line number Diff line number Diff line change
Expand Up @@ -344,3 +344,217 @@ ngx_int_t oauth2_nginx_http_response_set(oauth2_log_t *log,

return nrc;
}

typedef struct oauth2_nginx_claim_hash_t {
ngx_hash_keys_arrays_t keys;
ngx_hash_t h;
} oauth2_nginx_claim_hash_t;

static inline ngx_str_t oauth2_nginx_chr2str(ngx_pool_t *p, const char *k)
{
ngx_str_t in = {strlen(k), (u_char *)k};
ngx_str_t out = {in.len, ngx_pstrdup(p, &in)};
return out;
}

char *oauth2_nginx_str2chr(ngx_pool_t *p, const ngx_str_t *str)
{
char *s = ngx_pnalloc(p, str->len + 1);
if (s != NULL) {
memcpy(s, str->data, str->len);
s[str->len] = '\0';
}
return s;
}

static inline char *oauth2_nginx_chr2chr(ngx_pool_t *p, const char *str)
{
ngx_str_t s = {strlen(str), (u_char *)str};
return oauth2_nginx_str2chr(p, &s);
}

ngx_int_t oauth2_nginx_claim_variable(ngx_module_t module,
ngx_http_request_t *r,
ngx_http_variable_value_t *v,
uintptr_t data)
{
oauth2_nginx_claim_hash_t *claims = NULL;
const char *value = NULL;
ngx_str_t key = {strlen((const char *)data), (u_char *)data};

claims =
(oauth2_nginx_claim_hash_t *)ngx_http_get_module_ctx(r, module);

if (claims == NULL) {
v->not_found = 1;
return NGX_OK;
}

value = (const char *)ngx_hash_find(
&claims->h, ngx_hash_key(key.data, key.len), key.data, key.len);

if (value != NULL) {
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"oauth2_nginx_claim_variable: %V=%s", &key,
value);
v->data = (u_char *)value;
v->len = strlen(value);
v->no_cacheable = 1;
v->not_found = 0;
} else {
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"oauth2_nginx_claim_variable: %V=(null)", &key);
v->not_found = 1;
}

return NGX_OK;
}

static const size_t MAX_BUF = 128;

char *oauth2_nginx_set_claim(ngx_module_t module,
ngx_http_get_variable_pt handler, ngx_conf_t *cf,
ngx_command_t *cmd, void *conf)
{
ngx_http_variable_t *v;
char buf[MAX_BUF];
int n = 0;
char *s = NULL;
ngx_str_t *value = cf->args->elts;

if (value[2].len <= 1 || value[2].data[0] != '$') {
n = snprintf(buf, sizeof(buf), "Invalid variable name %.*s",
(int)value[2].len, value[2].data);
ngx_str_t msg = {n, (u_char *)&buf[0]};
s = oauth2_nginx_str2chr(cf->pool, &msg);
return s ? s : NGX_CONF_ERROR;
}

value[2].len--;
value[2].data++;

v = ngx_http_add_variable(cf, &value[2], NGX_HTTP_VAR_CHANGEABLE);
if (!v) {
ngx_str_t msg = ngx_string("ngx_http_add_variable failed");
s = oauth2_nginx_str2chr(cf->pool, &msg);
return s ? s : NGX_CONF_ERROR;
}

v->get_handler = handler;
char *claim = oauth2_nginx_str2chr(cf->pool, &value[1]);
if (!claim) {
ngx_str_t msg = ngx_string("Out of memory");
s = oauth2_nginx_str2chr(cf->pool, &msg);
return s ? s : NGX_CONF_ERROR;
}
v->data = (uintptr_t)claim;

return NGX_CONF_OK;
}

static ngx_int_t ngx_set_target_variable(oauth2_nginx_claim_hash_t *claims,
oauth2_nginx_request_context_t *ctx,
const char *k, const char *v)
{
ngx_str_t key = oauth2_nginx_chr2str(claims->keys.pool, k);
if (key.data == NULL)
return NGX_ERROR;
const char *value = oauth2_nginx_chr2chr(claims->keys.pool, v);
if (value == NULL)
return NGX_ERROR;
return ngx_hash_add_key(&claims->keys, &key, (char *)value,
NGX_HASH_READONLY_KEY);
}

static ngx_int_t ngx_oauth2_init_keys(ngx_pool_t *pool,
oauth2_nginx_claim_hash_t *claims)
{
claims->keys.pool = pool;
claims->keys.temp_pool = pool;
return ngx_hash_keys_array_init(&claims->keys, NGX_HASH_SMALL);
}

static ngx_int_t ngx_oauth2_init_hash(ngx_pool_t *pool,
oauth2_nginx_claim_hash_t *claims)
{
ngx_hash_init_t init;
init.hash = &claims->h;
init.key = ngx_hash_key;
init.max_size = 64;
init.bucket_size = ngx_align(64, ngx_cacheline_size);
init.name = "claims";
init.pool = pool;
init.temp_pool = pool;
return ngx_hash_init(&init, claims->keys.keys.elts,
claims->keys.keys.nelts);
}

ngx_int_t oauth2_nginx_set_target_variables(ngx_module_t module,
oauth2_nginx_request_context_t *ctx,
json_t *json_token)
{
void *iter = NULL;
const char *key = NULL, *val = NULL;
json_t *value = NULL;
oauth2_nginx_claim_hash_t *claims = NULL;
int rc = NGX_OK;

claims = (oauth2_nginx_claim_hash_t *)ngx_http_get_module_ctx(ctx->r,
module);

if (claims == NULL) {

claims = ngx_palloc(ctx->r->pool, sizeof(*claims));

if (claims == NULL) {
oauth2_error(ctx->log, "error allocating claims hash");
return NGX_ERROR;
}

rc = ngx_oauth2_init_keys(ctx->r->pool, claims);

if (rc != NGX_OK) {
oauth2_error(ctx->log,
"error %d initializing hash keys", rc);
return rc;
}

ngx_http_set_ctx(ctx->r, claims, module);
}

iter = json_object_iter(json_token);
while (iter) {

key = json_object_iter_key(iter);
value = json_object_iter_value(iter);

if (json_is_string(value)) {
rc = ngx_set_target_variable(claims, ctx, key,
json_string_value(value));
} else {
val = oauth2_json_encode(ctx->log, value,
JSON_ENCODE_ANY);
rc = ngx_set_target_variable(claims, ctx, key, val);
oauth2_mem_free((char *)val);
}

if (rc != NGX_OK) {
oauth2_error(
ctx->log,
"error %d setting value of key %s in claims hash",
rc, key);
return rc;
}

iter = json_object_iter_next(json_token, iter);
}

rc = ngx_oauth2_init_hash(ctx->r->pool, claims);

if (rc != NGX_OK) {
oauth2_error(ctx->log, "error %d initializing claims hash", rc);
return rc;
}

return NGX_OK;
}
3 changes: 1 addition & 2 deletions test/check_cache.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,8 +205,7 @@ START_TEST(test_cache_redis)
char *rv = NULL;

//&password=foobared
rv = oauth2_cfg_set_cache(_log, NULL, "redis",
"name=redis");
rv = oauth2_cfg_set_cache(_log, NULL, "redis", "name=redis");
ck_assert_ptr_eq(rv, NULL);
c = oauth2_cache_obtain(_log, "redis");
ck_assert_ptr_ne(c, NULL);
Expand Down
48 changes: 48 additions & 0 deletions test/server_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ void *ngx_palloc(ngx_pool_t *pool, size_t size)
return p;
}

void *ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
void *p = (void *)oauth2_mem_alloc(size);
return p;
}

ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p)
{
oauth2_mem_free(p);
Expand Down Expand Up @@ -200,4 +206,46 @@ ngx_uint_t ngx_hash_strlow(u_char *dst, u_char *src, size_t n)
return 0;
}

ngx_uint_t ngx_cacheline_size = 64;

ngx_uint_t ngx_hash_key(u_char *data, size_t len)
{
return (ngx_uint_t)(*data);
}

u_char *ngx_pstrdup(ngx_pool_t *pool, ngx_str_t *src)
{
u_char *dst = ngx_pnalloc(pool, src->len);
memcpy(dst, src->data, src->len);
return dst;
}

ngx_int_t ngx_hash_init(ngx_hash_init_t *hinit, ngx_hash_key_t *names,
ngx_uint_t nelts)
{
return 0;
}

ngx_int_t ngx_hash_keys_array_init(ngx_hash_keys_arrays_t *ha, ngx_uint_t type)
{
return 0;
}

ngx_int_t ngx_hash_add_key(ngx_hash_keys_arrays_t *ha, ngx_str_t *key,
void *value, ngx_uint_t flags)
{
return 0;
}

void *ngx_hash_find(ngx_hash_t *hash, ngx_uint_t key, u_char *name, size_t len)
{
return NULL;
}

ngx_http_variable_t *ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name,
ngx_uint_t flags)
{
return NULL;
}

#endif

0 comments on commit 6537014

Please sign in to comment.