Skip to content

Commit 7f11db9

Browse files
committed
Add code to set attribute names in the environment
This code allows to specify which attributes in a name are interesting to the application and set them as named environemnt variables. Optionally the whole set of attributes can be exported in a json formatted structure. Signed-off-by: Simo Sorce <simo@redhat.com> Close #62 Close #63
1 parent 472d605 commit 7f11db9

File tree

5 files changed

+362
-3
lines changed

5 files changed

+362
-3
lines changed

README

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,3 +237,30 @@ The recognized mechanism names are: krb5, iakerb, ntlmssp
237237

238238
#### Example
239239
GssapiBasicAuthMech krb5
240+
241+
242+
#### GssapiNameAttributes
243+
244+
Enables the module to source Name Attributes from the client name
245+
(authorization data associated with the established context) and exposes them
246+
as environment variables.
247+
248+
Value format: ENV_VAR_NAME ATTRIBUTE_NAME
249+
250+
This option can be specified multiple times, once for each attribute to expose.
251+
The Special value "json" is used to expose all attributes in a json formatted
252+
string via the special environment variable GSS_NAME_ATTRS_JSON
253+
The environment variable GSS_NAME_ATTR_ERROR is set with the Gssapi returned
254+
error string in case the inquire name function fails to retrieve attributes,
255+
and with the string "0 attributes found", if no attributes are set.
256+
257+
Note: These variables are NOT saved in the session data stored in the cookie so they
258+
are available only on the first authenticated request when GssapiUseSessions is
259+
used.
260+
261+
Note: It is recommended but not required to use only capital letters and underscores
262+
for environment variable names.
263+
264+
#### Example
265+
GssapiNameAttributes json
266+
GssapiNameAttributes RADIUS_NAME urn:ietf:params:gss:radius-attribute_1

src/environ.c

Lines changed: 242 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,243 @@
11
/* Copyright (C) 2015 mod_auth_gssapi authors - See COPYING for (C) terms */
22

33
#include "mod_auth_gssapi.h"
4-
#include "environ.h"
4+
5+
struct name_attr {
6+
gss_buffer_desc name;
7+
int authenticated;
8+
int complete;
9+
gss_buffer_desc value;
10+
gss_buffer_desc display_value;
11+
const char *env_name;
12+
int number;
13+
int more;
14+
};
15+
16+
static bool mag_get_name_attr(request_rec *req,
17+
gss_name_t name, struct name_attr *attr)
18+
{
19+
uint32_t maj, min;
20+
21+
maj = gss_get_name_attribute(&min, name, &attr->name,
22+
&attr->authenticated,
23+
&attr->complete,
24+
&attr->value,
25+
&attr->display_value,
26+
&attr->more);
27+
if (GSS_ERROR(maj)) {
28+
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req,
29+
"gss_get_name_attribute() failed on %.*s%s",
30+
(int)attr->name.length, (char *)attr->name.value,
31+
mag_error(req, "", maj, min));
32+
return false;
33+
}
34+
35+
return true;
36+
}
37+
38+
static void mc_add_name_attribute(struct mag_conn *mc,
39+
const char *name, const char *value)
40+
{
41+
size_t size;
42+
43+
if (mc->na_count % 16 == 0) {
44+
size = sizeof(struct mag_attr) * (mc->na_count + 16);
45+
mc->name_attributes = realloc(mc->name_attributes, size);
46+
if (!mc->name_attributes) apr_pool_abort_get(mc->pool)(ENOMEM);
47+
}
48+
49+
mc->name_attributes[mc->na_count].name = apr_pstrdup(mc->pool, name);
50+
mc->name_attributes[mc->na_count].value = apr_pstrdup(mc->pool, value);
51+
mc->na_count++;
52+
}
53+
54+
static void mag_set_env_name_attr(request_rec *req, struct mag_conn *mc,
55+
struct name_attr *attr)
56+
{
57+
char *value = "";
58+
int len = 0;
59+
60+
/* Prefer a display_value, otherwise fallback to value */
61+
if (attr->display_value.length != 0) {
62+
len = attr->display_value.length;
63+
value = (char *)attr->display_value.value;
64+
} else if (attr->value.length != 0) {
65+
len = apr_base64_encode_len(attr->value.length);
66+
value = apr_pcalloc(req->pool, len);
67+
len = apr_base64_encode(value,
68+
(char *)attr->value.value,
69+
attr->value.length);
70+
}
71+
72+
if (attr->number == 1) {
73+
mc_add_name_attribute(mc,
74+
attr->env_name,
75+
apr_psprintf(req->pool, "%.*s", len, value));
76+
}
77+
if (attr->more != 0 || attr->number > 1) {
78+
mc_add_name_attribute(mc,
79+
apr_psprintf(req->pool, "%s_%d",
80+
attr->env_name, attr->number),
81+
apr_psprintf(req->pool, "%.*s", len, value));
82+
}
83+
if (attr->more == 0 && attr->number > 1) {
84+
mc_add_name_attribute(mc,
85+
apr_psprintf(req->pool, "%s_N", attr->env_name),
86+
apr_psprintf(req->pool, "%d", attr->number - 1));
87+
}
88+
}
89+
90+
static void mag_add_json_name_attr(request_rec *req, bool first,
91+
struct name_attr *attr, char **json)
92+
{
93+
const char *value = "";
94+
int len = 0;
95+
char *b64value = NULL;
96+
int b64len = 0;
97+
const char *vstart = "";
98+
const char *vend = "";
99+
const char *vformat;
100+
101+
if (attr->value.length != 0) {
102+
b64len = apr_base64_encode_len(attr->value.length);
103+
b64value = apr_pcalloc(req->pool, b64len);
104+
b64len = apr_base64_encode(b64value,
105+
(char *)attr->value.value,
106+
attr->value.length);
107+
}
108+
if (attr->display_value.length != 0) {
109+
len = attr->display_value.length;
110+
value = (const char *)attr->display_value.value;
111+
}
112+
if (attr->number == 1) {
113+
*json = apr_psprintf(req->pool,
114+
"%s%s\"%.*s\":{\"authenticated\":%s,"
115+
"\"complete\":%s,"
116+
"\"values\":[",
117+
*json, (first ? "" : ","),
118+
(int)attr->name.length, (char *)attr->name.value,
119+
attr->authenticated ? "true" : "false",
120+
attr->complete ? "true" : "false");
121+
} else {
122+
vstart = ",";
123+
}
124+
125+
if (b64value) {
126+
if (len) {
127+
vformat = "%s%s{\"raw\":\"%s\",\"display\":\"%.*s\"}%s";
128+
} else {
129+
vformat = "%s%s{\"raw\":\"%s\",\"display\":%.*s}%s";
130+
}
131+
} else {
132+
if (len) {
133+
vformat = "%s%s{\"raw\":%s,\"display\":\"%.*s\"}%s";
134+
} else {
135+
vformat = "%s%s{\"raw\":%s,\"display\":%.*s}%s";
136+
}
137+
}
138+
139+
if (attr->more == 0) {
140+
vend = "]}";
141+
}
142+
143+
*json = apr_psprintf(req->pool, vformat, *json,
144+
vstart,
145+
b64value ? b64value : "null",
146+
len ? len : 4, len ? value : "null",
147+
vend);
148+
}
149+
150+
gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
151+
152+
void mag_get_name_attributes(request_rec *req, struct mag_config *cfg,
153+
gss_name_t name, struct mag_conn *mc)
154+
{
155+
uint32_t maj, min;
156+
gss_buffer_set_t attrs = GSS_C_NO_BUFFER_SET;
157+
struct name_attr attr;
158+
char *json = NULL;
159+
char *error;
160+
int count = 0;
161+
int i, j;
162+
163+
maj = gss_inquire_name(&min, name, NULL, NULL, &attrs);
164+
if (GSS_ERROR(maj)) {
165+
error = mag_error(req, "gss_inquire_name() failed", maj, min);
166+
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, req, "%s", error);
167+
apr_table_set(req->subprocess_env, "GSS_NAME_ATTR_ERROR", error);
168+
return;
169+
}
170+
171+
if (!attrs || attrs->count == 0) {
172+
mc_add_name_attribute(mc, "GSS_NAME_ATTR_ERROR", "0 attributes found");
173+
}
174+
175+
if (cfg->name_attributes->output_json) {
176+
177+
if (attrs) count = attrs->count;
178+
179+
json = apr_psprintf(req->pool,
180+
"{\"name\":\"%s\",\"attributes\":{",
181+
mc->gss_name);
182+
} else {
183+
count = cfg->name_attributes->map_count;
184+
}
185+
186+
for (i = 0; i < count; i++) {
187+
188+
memset(&attr, 0, sizeof(struct name_attr));
189+
190+
if (cfg->name_attributes->output_json) {
191+
attr.name = attrs->elements[i];
192+
for (j = 0; j < cfg->name_attributes->map_count; j++) {
193+
if (strncmp(cfg->name_attributes->map[j].attr_name,
194+
attrs->elements[i].value,
195+
attrs->elements[i].length) == 0) {
196+
attr.env_name = cfg->name_attributes->map[j].env_name;
197+
break;
198+
}
199+
}
200+
} else {
201+
attr.name.length = strlen(cfg->name_attributes->map[i].attr_name);
202+
attr.name.value = cfg->name_attributes->map[i].attr_name;
203+
attr.env_name = cfg->name_attributes->map[i].env_name;
204+
}
205+
206+
attr.number = 0;
207+
attr.more = -1;
208+
do {
209+
attr.number++;
210+
attr.value = empty_buffer;
211+
attr.display_value = empty_buffer;
212+
213+
if (!mag_get_name_attr(req, name, &attr)) continue;
214+
215+
if (cfg->name_attributes->output_json) {
216+
mag_add_json_name_attr(req, i == 0, &attr, &json);
217+
}
218+
if (attr.env_name) {
219+
mag_set_env_name_attr(req, mc, &attr);
220+
}
221+
222+
gss_release_buffer(&min, &attr.value);
223+
gss_release_buffer(&min, &attr.display_value);
224+
} while (attr.more != 0);
225+
}
226+
227+
if (cfg->name_attributes->output_json) {
228+
json = apr_psprintf(req->pool, "%s}}", json);
229+
mc_add_name_attribute(mc, "GSS_NAME_ATTRS_JSON", json);
230+
}
231+
}
232+
233+
static void mag_set_name_attributes(request_rec *req, struct mag_conn *mc)
234+
{
235+
for (int i = 0; i < mc->na_count; i++) {
236+
apr_table_set(req->subprocess_env,
237+
mc->name_attributes[i].name,
238+
mc->name_attributes[i].value);
239+
}
240+
}
5241

6242
static void mag_set_KRB5CCANME(request_rec *req, char *ccname)
7243
{
@@ -31,6 +267,11 @@ void mag_set_req_data(request_rec *req,
31267
req->ap_auth_type = apr_pstrdup(req->pool,
32268
mag_str_auth_type(mc->auth_type));
33269
req->user = apr_pstrdup(req->pool, mc->user_name);
270+
271+
if (mc->name_attributes) {
272+
mag_set_name_attributes(req, mc);
273+
}
274+
34275
if (cfg->deleg_ccache_dir && mc->delegated) {
35276
char *ccname;
36277
ccname = mag_gss_name_to_ccache_name(req,

src/environ.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@
33
struct mag_config;
44
struct mag_conn;
55

6+
void mag_get_name_attributes(request_rec *req,
7+
struct mag_config *cfg,
8+
gss_name_t name,
9+
struct mag_conn *mc);
10+
611
void mag_set_req_data(request_rec *req,
712
struct mag_config *cfg,
813
struct mag_conn *mc);

0 commit comments

Comments
 (0)