Progetto

Generale

Profilo

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.