Klaus Demo nginx / 94e9aaa
new ngx_http_secure_link_module with secure_link, secure_link_md5, and secure_link_expires Igor Sysoev 11 years ago
5 changed file(s) with 277 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
99
1010 static u_char *ngx_sprintf_num(u_char *buf, u_char *last, uint64_t ui64,
1111 u_char zero, ngx_uint_t hexadecimal, ngx_uint_t width);
12 static ngx_int_t ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src,
13 const u_char *basis);
1214
1315
1416 void
10941096 ngx_int_t
10951097 ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
10961098 {
1097 size_t len;
1098 u_char *d, *s;
10991099 static u_char basis64[] = {
11001100 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
11011101 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
11161116 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
11171117 };
11181118
1119 return ngx_decode_base64_internal(dst, src, basis64);
1120 }
1121
1122
1123 ngx_int_t
1124 ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src)
1125 {
1126 static u_char basis64[] = {
1127 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1128 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1129 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77,
1130 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,
1131 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
1132 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 63,
1133 77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
1134 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,
1135
1136 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1137 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1138 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1139 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1140 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1141 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1142 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,
1143 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77
1144 };
1145
1146 return ngx_decode_base64_internal(dst, src, basis64);
1147 }
1148
1149
1150 static ngx_int_t
1151 ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
1152 {
1153 size_t len;
1154 u_char *d, *s;
1155
11191156 for (len = 0; len < src->len; len++) {
11201157 if (src->data[len] == '=') {
11211158 break;
11221159 }
11231160
1124 if (basis64[src->data[len]] == 77) {
1161 if (basis[src->data[len]] == 77) {
11251162 return NGX_ERROR;
11261163 }
11271164 }
11341171 d = dst->data;
11351172
11361173 while (len > 3) {
1137 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
1138 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
1139 *d++ = (u_char) (basis64[s[2]] << 6 | basis64[s[3]]);
1174 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
1175 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
1176 *d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);
11401177
11411178 s += 4;
11421179 len -= 4;
11431180 }
11441181
11451182 if (len > 1) {
1146 *d++ = (u_char) (basis64[s[0]] << 2 | basis64[s[1]] >> 4);
1183 *d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);
11471184 }
11481185
11491186 if (len > 2) {
1150 *d++ = (u_char) (basis64[s[1]] << 4 | basis64[s[2]] >> 2);
1187 *d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);
11511188 }
11521189
11531190 dst->len = d - dst->data;
177177
178178 void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src);
179179 ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src);
180 ngx_int_t ngx_decode_base64url(ngx_str_t *dst, ngx_str_t *src);
180181
181182 uint32_t ngx_utf8_decode(u_char **p, size_t n);
182183 size_t ngx_utf8_length(u_char *p, size_t n);
1010
1111
1212 typedef struct {
13 ngx_str_t secret;
13 ngx_http_complex_value_t *variable;
14 ngx_http_complex_value_t *md5;
15 ngx_str_t secret;
16 ngx_flag_t expires;
1417 } ngx_http_secure_link_conf_t;
1518
1619
20 typedef struct {
21 ngx_str_t expires;
22 } ngx_http_secure_link_ctx_t;
23
24
25 static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
26 ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
27 uintptr_t data);
28 static ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
29 ngx_http_variable_value_t *v, uintptr_t data);
1730 static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
1831 static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
1932 void *child);
2134
2235
2336 static ngx_command_t ngx_http_secure_link_commands[] = {
37
38 { ngx_string("secure_link"),
39 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
40 ngx_http_set_comlex_value_slot,
41 NGX_HTTP_LOC_CONF_OFFSET,
42 offsetof(ngx_http_secure_link_conf_t, variable),
43 NULL },
44
45 { ngx_string("secure_link_md5"),
46 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
47 ngx_http_set_comlex_value_slot,
48 NGX_HTTP_LOC_CONF_OFFSET,
49 offsetof(ngx_http_secure_link_conf_t, md5),
50 NULL },
51
52 { ngx_string("secure_link_expires"),
53 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
54 ngx_conf_set_flag_slot,
55 NGX_HTTP_LOC_CONF_OFFSET,
56 offsetof(ngx_http_secure_link_conf_t, expires),
57 NULL },
2458
2559 { ngx_string("secure_link_secret"),
2660 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
6498 };
6599
66100
67 static ngx_str_t ngx_http_secure_link = ngx_string("secure_link");
101 static ngx_str_t ngx_http_secure_link_name = ngx_string("secure_link");
102 static ngx_str_t ngx_http_secure_link_expires_name =
103 ngx_string("secure_link_expires");
68104
69105
70106 static ngx_int_t
71107 ngx_http_secure_link_variable(ngx_http_request_t *r,
72 ngx_http_variable_value_t *v, uintptr_t data)
73 {
74 u_char *p, *start, *end, *last;
75 size_t len;
76 ngx_int_t n;
77 ngx_uint_t i;
78 ngx_md5_t md5;
108 ngx_http_variable_value_t *v, uintptr_t data)
109 {
110 u_char *p, *last;
111 ngx_str_t val, hash;
112 time_t expires;
113 ngx_md5_t md5;
114 ngx_http_secure_link_ctx_t *ctx;
79115 ngx_http_secure_link_conf_t *conf;
80 u_char hash[16];
116 u_char hash_buf[16], md5_buf[16];
81117
82118 conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
83119
84 if (conf->secret.len == 0) {
85 goto not_found;
86 }
120 if (conf->secret.len) {
121 return ngx_http_secure_link_old_variable(r, conf, v, data);
122 }
123
124 if (conf->variable == NULL || conf->md5 == NULL) {
125 goto not_found;
126 }
127
128 if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
129 return NGX_ERROR;
130 }
131
132 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
133 "secure link: \"%V\"", &val);
134
135 last = val.data + val.len;
136
137 p = ngx_strlchr(val.data, last, ',');
138 expires = 0;
139
140 if (p) {
141 val.len = p++ - val.data;
142
143 if (conf->expires) {
144 expires = ngx_atotm(p, last - p);
145 if (expires <= 0) {
146 goto not_found;
147 }
148
149 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
150 if (ctx == NULL) {
151 return NGX_ERROR;
152 }
153
154 ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
155
156 ctx->expires.len = last - p;
157 ctx->expires.data = p;
158 }
159 }
160
161 if (val.len > 24) {
162 goto not_found;
163 }
164
165 hash.len = 16;
166 hash.data = hash_buf;
167
168 if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
169 goto not_found;
170 }
171
172 if (hash.len != 16) {
173 goto not_found;
174 }
175
176 if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
177 return NGX_ERROR;
178 }
179
180 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
181 "secure link md5: \"%V\"", &val);
182
183 ngx_md5_init(&md5);
184 ngx_md5_update(&md5, val.data, val.len);
185 ngx_md5_final(md5_buf, &md5);
186
187 if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
188 goto not_found;
189 }
190
191 v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
192 v->len = 1;
193 v->valid = 1;
194 v->no_cacheable = 0;
195 v->not_found = 0;
196
197 return NGX_OK;
198
199 not_found:
200
201 v->not_found = 1;
202
203 return NGX_OK;
204 }
205
206
207 static ngx_int_t
208 ngx_http_secure_link_old_variable(ngx_http_request_t *r,
209 ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
210 uintptr_t data)
211 {
212 u_char *p, *start, *end, *last;
213 size_t len;
214 ngx_int_t n;
215 ngx_uint_t i;
216 ngx_md5_t md5;
217 u_char hash[16];
87218
88219 p = &r->unparsed_uri.data[1];
89220 last = r->unparsed_uri.data + r->unparsed_uri.len;
144275 }
145276
146277
278 static ngx_int_t
279 ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
280 ngx_http_variable_value_t *v, uintptr_t data)
281 {
282 ngx_http_secure_link_ctx_t *ctx;
283
284 ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
285
286 if (ctx) {
287 v->len = ctx->expires.len;
288 v->valid = 1;
289 v->no_cacheable = 0;
290 v->not_found = 0;
291 v->data = ctx->expires.data;
292
293 } else {
294 v->not_found = 1;
295 }
296
297 return NGX_OK;
298 }
299
300
147301 static void *
148302 ngx_http_secure_link_create_conf(ngx_conf_t *cf)
149303 {
157311 /*
158312 * set by ngx_pcalloc():
159313 *
160 * conf->secret = { 0, NULL }
314 * conf->variable = NULL;
315 * conf->md5 = NULL;
316 * conf->secret = { 0, NULL };
161317 */
318
319 conf->expires = NGX_CONF_UNSET;
162320
163321 return conf;
164322 }
172330
173331 ngx_conf_merge_str_value(conf->secret, prev->secret, "");
174332
333 if (conf->variable == NULL) {
334 conf->variable = prev->variable;
335 }
336
337 if (conf->md5 == NULL) {
338 conf->md5 = prev->md5;
339 }
340
341 ngx_conf_merge_value(conf->expires, prev->expires, 0);
342
175343 return NGX_CONF_OK;
176344 }
177345
181349 {
182350 ngx_http_variable_t *var;
183351
184 var = ngx_http_add_variable(cf, &ngx_http_secure_link, NGX_HTTP_VAR_NOHASH);
352 var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
185353 if (var == NULL) {
186354 return NGX_ERROR;
187355 }
188356
189357 var->get_handler = ngx_http_secure_link_variable;
190358
191 return NGX_OK;
192 }
359 var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
360 if (var == NULL) {
361 return NGX_ERROR;
362 }
363
364 var->get_handler = ngx_http_secure_link_expires_variable;
365
366 return NGX_OK;
367 }
210210 }
211211
212212
213 char *
214 ngx_http_set_comlex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
215 {
216 char *p = conf;
217
218 ngx_str_t *value;
219 ngx_http_complex_value_t **cv;
220 ngx_http_compile_complex_value_t ccv;
221
222 cv = (ngx_http_complex_value_t **) (p + cmd->offset);
223
224 if (*cv != NULL) {
225 return "duplicate";
226 }
227
228 *cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
229 if (*cv == NULL) {
230 return NGX_CONF_ERROR;
231 }
232
233 value = cf->args->elts;
234
235 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
236
237 ccv.cf = cf;
238 ccv.value = &value[1];
239 ccv.complex_value = *cv;
240
241 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
242 return NGX_CONF_ERROR;
243 }
244
245 return NGX_CONF_OK;
246 }
247
248
213249 ngx_int_t
214250 ngx_http_test_predicates(ngx_http_request_t *r, ngx_array_t *predicates)
215251 {
206206 ngx_int_t ngx_http_complex_value(ngx_http_request_t *r,
207207 ngx_http_complex_value_t *val, ngx_str_t *value);
208208 ngx_int_t ngx_http_compile_complex_value(ngx_http_compile_complex_value_t *ccv);
209 char * ngx_http_set_comlex_value_slot(ngx_conf_t *cf, ngx_command_t *cmd,
210 void *conf);
211
209212
210213 ngx_int_t ngx_http_test_predicates(ngx_http_request_t *r,
211214 ngx_array_t *predicates);