DjangoTornadoNginxAuth » Cronologia » Versione 2
Mark Caglienzi, 11-12-2013 19:06
1 | 1 | Christopher R. Gabriel | h1. Django Tornado Nginx Auth |
---|---|---|---|
2 | 2 | Mark Caglienzi | |
3 | Si suppone che si abbia un progetto django nella directory @/home/utente/projects/django/@ e un progetto tornado nella directory @/home/utente/projects/tornado/@. Si vuole configurare nginx in modo che django venga servito all'url http://example.com/ e tornado all'url http://example.com/tornado/, facendo in modo che l'accesso a tornado sia inibito se non si è autenticati a django. |
||
4 | |||
5 | La guida è condotta su un sistema Debian Jessie, al momento in testing (per altre versioni probabilmente andrà adattato qualcosa). |
||
6 | |||
7 | h2. Prerequisiti |
||
8 | |||
9 | Servono (oltre a django e tornado, ovviamente) anche i pacchetti: @devscripts@, @mercurial@, @fakeroot@. |
||
10 | |||
11 | h2. Compilazione di nginx |
||
12 | |||
13 | Esiste "un plugin per nginx":https://github.com/perusio/nginx-auth-request-module (scritto da uno dei core developer di nginx stesso) che nella versione 1.4.x del server (quella attualmente in debian) non è incluso. Quindi bisogna scaricare il plugin e ricompilare nginx. Per comodità si useranno il più possibile i sorgenti e il sistema di build di debian. |
||
14 | |||
15 | <pre> |
||
16 | $ mkdir /home/utente/projects/nginx |
||
17 | $ cd /home/utente/projects/nginx |
||
18 | $ dget http://ftp.de.debian.org/debian/pool/main/n/nginx/nginx_1.4.4-1.dsc |
||
19 | </pre> |
||
20 | |||
21 | Questo per scaricare il pacchetto sorgente di nginx 1.4.4 e averlo automaticamente scompattato. |
||
22 | |||
23 | <pre> |
||
24 | $ cd nginx-1.4.4/debian/modules |
||
25 | $ hg clone http://mdounin.ru/hg/ngx_http_auth_request_module nginx-auth-request |
||
26 | </pre> |
||
27 | |||
28 | A questo punto nella sotto-directory @debian/modules/nginx-auth-request@ c'è il codice del plugin richiesto (preso direttamente dal repository mercurial dove viene sviluppato, dato che il repository su github è meno aggiornato). |
||
29 | |||
30 | <pre> |
||
31 | # apt-get build-dep nginx |
||
32 | </pre> |
||
33 | |||
34 | In questo modo verranno installati i pacchetti necessari a compilare nginx. Ora bisogna modificare il file @debian/rules@ nella sezione riguardante il pacchetto binario @nginx-full@ (solo in questa, nelle altre non è necessario), aggiungendo la riga: |
||
35 | |||
36 | <pre> |
||
37 | --add-module=$(MODULESDIR)/nginx-auth-request \ |
||
38 | </pre> |
||
39 | |||
40 | sotto alle altre direttive @--add-module@, in modo che il file si presenti così: |
||
41 | |||
42 | <pre> |
||
43 | [...] |
||
44 | config.status.full: config.env.full ### In questa sezione... |
||
45 | cd $(BUILDDIR_full) && CFLAGS="$(CFLAGS)" CORE_LINK="$(LDFLAGS)" ./configure \ |
||
46 | --prefix=/usr/share/nginx \ |
||
47 | --conf-path=/etc/nginx/nginx.conf \ |
||
48 | --error-log-path=/var/log/nginx/error.log \ |
||
49 | --http-client-body-temp-path=/var/lib/nginx/body \ |
||
50 | --http-fastcgi-temp-path=/var/lib/nginx/fastcgi \ |
||
51 | --http-log-path=/var/log/nginx/access.log \ |
||
52 | --http-proxy-temp-path=/var/lib/nginx/proxy \ |
||
53 | --http-scgi-temp-path=/var/lib/nginx/scgi \ |
||
54 | --http-uwsgi-temp-path=/var/lib/nginx/uwsgi \ |
||
55 | --lock-path=/var/lock/nginx.lock \ |
||
56 | --pid-path=/run/nginx.pid \ |
||
57 | --with-pcre-jit \ |
||
58 | --with-debug \ |
||
59 | --with-http_addition_module \ |
||
60 | --with-http_dav_module \ |
||
61 | --with-http_geoip_module \ |
||
62 | --with-http_gzip_static_module \ |
||
63 | --with-http_image_filter_module \ |
||
64 | --with-http_realip_module \ |
||
65 | --with-http_stub_status_module \ |
||
66 | --with-http_ssl_module \ |
||
67 | --with-http_sub_module \ |
||
68 | --with-http_xslt_module \ |
||
69 | --with-ipv6 \ |
||
70 | --with-mail \ |
||
71 | --with-mail_ssl_module \ |
||
72 | --add-module=$(MODULESDIR)/nginx-auth-pam \ |
||
73 | --add-module=$(MODULESDIR)/nginx-dav-ext-module \ |
||
74 | --add-module=$(MODULESDIR)/nginx-echo \ |
||
75 | --add-module=$(MODULESDIR)/nginx-upstream-fair \ |
||
76 | --add-module=$(MODULESDIR)/ngx_http_substitutions_filter_module \ |
||
77 | --add-module=$(MODULESDIR)/nginx-auth-request \ ### ...aggiungere questa riga |
||
78 | $(CONFIGURE_OPTS) >$@ |
||
79 | touch $@ |
||
80 | [...] |
||
81 | </pre> |
||
82 | |||
83 | A questo punto bisogna compilare i pacchetti binari: |
||
84 | |||
85 | <pre> |
||
86 | $ cd /home/utente/projects/nginx/nginx-1.4.4 |
||
87 | $ fakeroot debian/rules binary |
||
88 | </pre> |
||
89 | |||
90 | Alla fine della compilazione nella directory @/home/utente/projects/nginx@ saranno presenti i pacchetti binari: |
||
91 | |||
92 | <pre> |
||
93 | nginx_1.4.4-1_all.deb |
||
94 | nginx-common_1.4.4-1_all.deb |
||
95 | nginx-doc_1.4.4-1_all.deb |
||
96 | nginx-extras_1.4.4-1_amd64.deb |
||
97 | nginx-extras-dbg_1.4.4-1_amd64.deb |
||
98 | nginx-full_1.4.4-1_amd64.deb |
||
99 | nginx-full-dbg_1.4.4-1_amd64.deb |
||
100 | nginx-light_1.4.4-1_amd64.deb |
||
101 | nginx-light-dbg_1.4.4-1_amd64.deb |
||
102 | nginx-naxsi_1.4.4-1_amd64.deb |
||
103 | nginx-naxsi-dbg_1.4.4-1_amd64.deb |
||
104 | nginx-naxsi-ui_1.4.4-1_all.deb |
||
105 | </pre> |
||
106 | |||
107 | Si può procedere ad installare i pacchetti necessari direttamente da questa directory: |
||
108 | |||
109 | <pre> |
||
110 | # dpkg -i nginx_1.4.4-1_all.deb nginx-common_1.4.4-1_all.deb nginx-full_1.4.4-1_amd64.deb |
||
111 | </pre> |
||
112 | |||
113 | h2. Avvio delle applicazioni |
||
114 | |||
115 | Dato che la guida si concentra sulla gestione dell'autenticazione tra django e tornado, si assume per semplicità che l'applicazione tornado sia hello-world ("link":http://www.tornadoweb.org/en/stable/#hello-world) e che le due applicazioni siano servite dai server di sviluppo: |
||
116 | |||
117 | <pre> |
||
118 | $ cd /home/utente/projects/django |
||
119 | $ ./manage.py runserver |
||
120 | </pre> |
||
121 | |||
122 | <pre> |
||
123 | $ cd /home/utente/projects/tornado |
||
124 | $ ./hello-world.py |
||
125 | </pre> |
||
126 | |||
127 | In questo modo il server di sviluppo di django risponde a @127.0.0.1:8000@ e tornado a @127.0.0.1:8888@ |
||
128 | |||
129 | h2. Creazione del file di configurazione di nginx |
||
130 | |||
131 | Si crei il file @/etc/nginx/sites-available/django@: |
||
132 | |||
133 | <pre> |
||
134 | upstream tornado { |
||
135 | server 127.0.0.1:8888; |
||
136 | } |
||
137 | |||
138 | server { |
||
139 | listen 80; |
||
140 | root /home/utente/projects/django; |
||
141 | server_name django; |
||
142 | access_log /home/utente/projects/django/access.log; |
||
143 | error_log /home/utente/projects/django/error.log; |
||
144 | location / { |
||
145 | proxy_pass http://127.0.0.1:8000; |
||
146 | } |
||
147 | location /tornado { |
||
148 | auth_request /is_logged_in/; |
||
149 | proxy_pass http://tornado; |
||
150 | } |
||
151 | } |
||
152 | </pre> |
||
153 | |||
154 | e si attivi con: |
||
155 | |||
156 | <pre> |
||
157 | # ln -s /etc/nginx/sites-available/django /etc/nginx/sites-enabled/django |
||
158 | # /etc/init.d/nginx restart |
||
159 | </pre> |
||
160 | |||
161 | In questo modo si dice a nginx che per URL sotto a @/tornado@ deve fare una request a @/is_logged_in/@ e accettare di passare il controllo a tornado solo se riceve una risposta HTTP 200. |
||
162 | |||
163 | Aggiungere la riga |
||
164 | |||
165 | <pre> |
||
166 | 127.0.0.1 django |
||
167 | </pre> |
||
168 | |||
169 | al file @/etc/hosts@. |
||
170 | |||
171 | h2. Modifica delle applicazioni Django e Tornado |
||
172 | |||
173 | L'applicazione hello world di tornado va modificata così: |
||
174 | <pre> |
||
175 | #!/usr/bin/env python |
||
176 | import tornado.ioloop |
||
177 | import tornado.web |
||
178 | |||
179 | class MainHandler(tornado.web.RequestHandler): |
||
180 | def get(self): |
||
181 | self.write("Hello, world") |
||
182 | |||
183 | application = tornado.web.Application([ |
||
184 | # (r"/", MainHandler), |
||
185 | (r'/tornado', MainHandler), |
||
186 | ]) |
||
187 | |||
188 | if __name__ == "__main__": |
||
189 | application.listen(8888) |
||
190 | tornado.ioloop.IOLoop.instance().start() |
||
191 | </pre> |
||
192 | |||
193 | in modo che @MainHandler@ risponda all'URL @/tornado@ anziché all'URL @/@. Nell'applicazione django va aggiunto in @urls.py@: |
||
194 | |||
195 | <pre> |
||
196 | url(r'^is_logged_in/$', 'myproject.views.is_logged_in', name='is_logged_in'), |
||
197 | </pre> |
||
198 | |||
199 | e una view di questo tipo: |
||
200 | |||
201 | <pre> |
||
202 | from django import http |
||
203 | |||
204 | def is_logged_in(request): |
||
205 | if request.user.is_anonymous(): |
||
206 | return http.HttpResponseForbidden("NO") |
||
207 | else: |
||
208 | return http.HttpResponse("OK") |
||
209 | </pre> |
||
210 | |||
211 | che non fa altro che restituire un HTTP 403 in caso l'utente non sia loggato, e un HTTP 200 diversamente. Se un template dell'applicazione django ha un link di questo tipo (o se si tenta di scrivere a mano l'URL): |
||
212 | |||
213 | <pre> |
||
214 | <a href="/tornado" class="btn">Tornado</a> |
||
215 | </pre> |
||
216 | |||
217 | nginx si comporterà così: |
||
218 | |||
219 | * Vede la richiesta a @http://django/tornado@ |
||
220 | * La direttiva @auth_request@ passa il controllo all'URL @http://django/is_logged_in/@ |
||
221 | * Django controlla se l'utente è loggato o meno, e dà una response di tipo 200 o 403 |
||
222 | * Se la risposta è 200, allora nginx prosegue e passa il controllo a @http://127.0.0.1:8888@ dove risponde tornado |
||
223 | * Se la risposta è 403, nginx non prosegue e l'utente si vede impossibilitato a proseguire |
||
224 | |||
225 | h3. Dubbi/problemi |
||
226 | |||
227 | * Compilare un plugin (seppur proveniente da una fonte autorevole, come un core dev di nginx) non mi piace troppo, specialmente se in un pacchetto così fondamentale come il server web/proxy |
||
228 | * Non ho ancora risolto il problema per cui l'utente non loggato vede un errore 403 anziché un più educato redirect alla view di login. Purtroppo il plugin non supporta i redirect, ma soltanto 403/200, quindi perché funzioni la direttiva @auth_request@ non ho potuto usare il decoratore @login_required@ nella view django. |
||
229 | * Il "changelog di nginx":http://nginx.org/en/CHANGES dice che dalla versione 1.5.4 del 27 agosto 2013 il modulo @ngx_http_auth_request_module@ è incluso, quindi ci si può aspettare che anche i futuri pacchetti debian lo includano. |