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