1 #include <ngx_config.h>
2 #include <ngx_core.h>
3 #include <ngx_http.h>
4 #include "aws_functions.h"
5
6 #define AWS_S3_VARIABLE "s3_auth_token"
7 #define AWS_DATE_VARIABLE "aws_date"
8
9 static void* ngx_http_aws_auth_create_loc_conf(ngx_conf_t *cf);
10 static char* ngx_http_aws_auth_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child);
11 static ngx_int_t ngx_aws_auth_req_init(ngx_conf_t *cf);
12 static char * ngx_http_aws_endpoint(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
13 static char* ngx_http_aws_sign(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
14
15 typedef struct {
16 ngx_str_t access_key;
17 ngx_str_t key_scope;
18 ngx_str_t signing_key;
19 ngx_str_t signing_key_decoded;
20 ngx_str_t endpoint;
21 ngx_str_t bucket_name;
22 ngx_uint_t enabled;
23 } ngx_http_aws_auth_conf_t;
24
25
26 static ngx_command_t ngx_http_aws_auth_commands[] = {
27 { ngx_string("aws_access_key"),
28 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
29 ngx_conf_set_str_slot,
30 NGX_HTTP_LOC_CONF_OFFSET,
31 offsetof(ngx_http_aws_auth_conf_t, access_key),
32 NULL },
33
34 { ngx_string("aws_key_scope"),
35 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
36 ngx_conf_set_str_slot,
37 NGX_HTTP_LOC_CONF_OFFSET,
38 offsetof(ngx_http_aws_auth_conf_t, key_scope),
39 NULL },
40
41 { ngx_string("aws_signing_key"),
42 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
43 ngx_conf_set_str_slot,
44 NGX_HTTP_LOC_CONF_OFFSET,
45 offsetof(ngx_http_aws_auth_conf_t, signing_key),
46 NULL },
47
48 { ngx_string("aws_endpoint"),
49 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
50 ngx_http_aws_endpoint,
51 NGX_HTTP_LOC_CONF_OFFSET,
52 offsetof(ngx_http_aws_auth_conf_t, endpoint),
53 NULL },
54
55 { ngx_string("aws_s3_bucket"),
56 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
57 ngx_conf_set_str_slot,
58 NGX_HTTP_LOC_CONF_OFFSET,
59 offsetof(ngx_http_aws_auth_conf_t, bucket_name),
60 NULL },
61
62 { ngx_string("aws_sign"),
63 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS,
64 ngx_http_aws_sign,
65 0,
66 0,
67 NULL },
68
69 ngx_null_command
70 };
71
72 static ngx_http_module_t ngx_http_aws_auth_module_ctx = {
73 NULL, /* preconfiguration */
74 ngx_aws_auth_req_init, /* postconfiguration */
75
76 NULL, /* create main configuration */
77 NULL, /* init main configuration */
78
79 NULL, /* create server configuration */
80 NULL, /* merge server configuration */
81
82 ngx_http_aws_auth_create_loc_conf, /* create location configuration */
83 ngx_http_aws_auth_merge_loc_conf /* merge location configuration */
84 };
85
86
87 ngx_module_t ngx_http_aws_auth_module = {
88 NGX_MODULE_V1,
89 &ngx_http_aws_auth_module_ctx, /* module context */
90 ngx_http_aws_auth_commands, /* module directives */
91 NGX_HTTP_MODULE, /* module type */
92 NULL, /* init master */
93 NULL, /* init module */
94 NULL, /* init process */
95 NULL, /* init thread */
96 NULL, /* exit thread */
97 NULL, /* exit process */
98 NULL, /* exit master */
99 NGX_MODULE_V1_PADDING
100 };
101
102 static void *
ngx_http_aws_auth_create_loc_conf(ngx_conf_t * cf)103 ngx_http_aws_auth_create_loc_conf(ngx_conf_t *cf)
104 {
105 ngx_http_aws_auth_conf_t *conf;
106
107 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_aws_auth_conf_t));
108 conf->enabled = 0;
109 ngx_str_set(&conf->endpoint, "s3.amazonaws.com");
110 if (conf == NULL) {
111 return NGX_CONF_ERROR;
112 }
113
114 return conf;
115 }
116
117 static char *
ngx_http_aws_auth_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)118 ngx_http_aws_auth_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
119 {
120 ngx_http_aws_auth_conf_t *prev = parent;
121 ngx_http_aws_auth_conf_t *conf = child;
122
123 ngx_conf_merge_str_value(conf->access_key, prev->access_key, "");
124 ngx_conf_merge_str_value(conf->key_scope, prev->key_scope, "");
125 ngx_conf_merge_str_value(conf->signing_key, prev->signing_key, "");
126 ngx_conf_merge_str_value(conf->endpoint, prev->endpoint, "s3.amazonaws.com");
127 ngx_conf_merge_str_value(conf->bucket_name, prev->bucket_name, "");
128
129 if(conf->signing_key_decoded.data == NULL)
130 {
131 conf->signing_key_decoded.data = ngx_pcalloc(cf->pool, 100);
132 if(conf->signing_key_decoded.data == NULL)
133 {
134 return NGX_CONF_ERROR;
135 }
136 }
137
138 if(conf->signing_key.len > 64) {
139 return NGX_CONF_ERROR;
140 } else {
141 ngx_decode_base64(&conf->signing_key_decoded, &conf->signing_key);
142 }
143
144 return NGX_CONF_OK;
145 }
146
147 static ngx_int_t
ngx_http_aws_proxy_sign(ngx_http_request_t * r)148 ngx_http_aws_proxy_sign(ngx_http_request_t *r)
149 {
150 ngx_http_aws_auth_conf_t *conf = ngx_http_get_module_loc_conf(r, ngx_http_aws_auth_module);
151 if(!conf->enabled) {
152 /* return directly if module is not enabled */
153 return NGX_DECLINED;
154 }
155 ngx_table_elt_t *h;
156 header_pair_t *hv;
157
158 if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
159 /* We do not wish to support anything with a body as signing for a body is unimplemented */
160 return NGX_HTTP_NOT_ALLOWED;
161 }
162
163 const ngx_array_t* headers_out = ngx_aws_auth__sign(r->pool, r,
164 &conf->access_key, &conf->signing_key_decoded, &conf->key_scope, &conf->bucket_name, &conf->endpoint);
165
166 ngx_uint_t i;
167 for(i = 0; i < headers_out->nelts; i++)
168 {
169 hv = (header_pair_t*)((u_char *) headers_out->elts + headers_out->size * i);
170 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
171 "header name %s, value %s", hv->key.data, hv->value.data);
172
173 if(ngx_strncmp(hv->key.data, HOST_HEADER.data, hv->key.len) == 0) {
174 /* host header is controlled by proxy pass directive and hence
175 cannot be set by our module */
176 continue;
177 }
178
179 h = ngx_list_push(&r->headers_in.headers);
180 if (h == NULL) {
181 return NGX_ERROR;
182 }
183
184 h->hash = 1;
185 h->key = hv->key;
186 h->lowcase_key = hv->key.data; /* We ensure that header names are already lowercased */
187 h->value = hv->value;
188 }
189 return NGX_OK;
190 }
191
192 static char *
ngx_http_aws_endpoint(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)193 ngx_http_aws_endpoint(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
194 {
195 char *p = conf;
196
197 ngx_str_t *field, *value;
198
199 field = (ngx_str_t *)(p + cmd->offset);
200
201 value = cf->args->elts;
202
203 *field = value[1];
204
205 return NGX_CONF_OK;
206 }
207
208 static char *
ngx_http_aws_sign(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)209 ngx_http_aws_sign(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
210 {
211 /*
212 ngx_http_core_loc_conf_t *clcf;
213
214 clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module);
215 clcf->handler = ngx_http_aws_proxy_sign;
216 */
217 ngx_http_aws_auth_conf_t *mconf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_aws_auth_module);
218 mconf->enabled = 1;
219
220 return NGX_CONF_OK;
221 }
222
223 static ngx_int_t
ngx_aws_auth_req_init(ngx_conf_t * cf)224 ngx_aws_auth_req_init(ngx_conf_t *cf)
225 {
226 ngx_http_handler_pt *h;
227 ngx_http_core_main_conf_t *cmcf;
228
229 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
230
231 h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
232 if (h == NULL) {
233 return NGX_ERROR;
234 }
235
236 *h = ngx_http_aws_proxy_sign;
237
238 return NGX_OK;
239 }
240 /*
241 * vim: ts=4 sw=4 et
242 */
243
244