1
|
6
|
import functools
|
2
|
|
|
3
|
6
|
from channels.handler import AsgiRequest
|
4
|
6
|
from rest_framework.exceptions import AuthenticationFailed
|
5
|
6
|
from rest_framework.settings import api_settings
|
6
|
6
|
from django.conf import settings
|
7
|
|
|
8
|
|
#print(api_settings.DEFAULT_AUTHENTICATION_CLASSES)
|
9
|
|
#authenticators = [auth() for auth in api_settings.DEFAULT_AUTHENTICATION_CLASSES]
|
10
|
|
|
11
|
|
|
12
|
6
|
def rest_auth(func):
|
13
|
|
"""
|
14
|
|
Wraps a HTTP or WebSocket connect consumer (or any consumer of messages
|
15
|
|
that provides a "cookies" or "get" attribute) to provide a "http_session"
|
16
|
|
attribute that behaves like request.session; that is, it's hung off of
|
17
|
|
a per-user session key that is saved in a cookie or passed as the
|
18
|
|
"session_key" GET parameter.
|
19
|
|
|
20
|
|
It won't automatically create and set a session cookie for users who
|
21
|
|
don't have one - that's what SessionMiddleware is for, this is a simpler
|
22
|
|
read-only version for more low-level code.
|
23
|
|
|
24
|
|
If a message does not have a session we can inflate, the "session" attribute
|
25
|
|
will be None, rather than an empty session you can write to.
|
26
|
|
|
27
|
|
Does not allow a new session to be set; that must be done via a view. This
|
28
|
|
is only an accessor for any existing session.
|
29
|
|
"""
|
30
|
6
|
@functools.wraps(func)
|
31
|
|
def inner(message, *args, **kwargs):
|
32
|
|
# Make sure there's NOT a http_session already
|
33
|
0
|
try:
|
34
|
|
# We want to parse the WebSocket (or similar HTTP-lite) message
|
35
|
|
# to get cookies and GET, but we need to add in a few things that
|
36
|
|
# might not have been there.
|
37
|
0
|
if "method" not in message.content:
|
38
|
0
|
message.content['method'] = "FAKE"
|
39
|
0
|
request = AsgiRequest(message)
|
40
|
|
|
41
|
0
|
except Exception as e:
|
42
|
0
|
raise ValueError("Cannot parse HTTP message - are you sure this is a HTTP consumer? %s" % e)
|
43
|
|
# Make sure there's a session key
|
44
|
0
|
user = None
|
45
|
0
|
auth = None
|
46
|
0
|
auth_token = request.GET.get("token", None)
|
47
|
0
|
print('NEW TOKEN : {}'.format(auth_token))
|
48
|
0
|
if auth_token:
|
49
|
|
# comptatibility with rest framework
|
50
|
0
|
request._request = {}
|
51
|
0
|
request.META["HTTP_AUTHORIZATION"] = "Bearer {}".format(auth_token)
|
52
|
0
|
authenticators = [auth() for auth in api_settings.DEFAULT_AUTHENTICATION_CLASSES]
|
53
|
0
|
print('Try Auth with {}'.format(request.META['HTTP_AUTHORIZATION']))
|
54
|
0
|
for authenticator in authenticators:
|
55
|
0
|
try:
|
56
|
0
|
user_auth_tuple = authenticator.authenticate(request)
|
57
|
0
|
except AuthenticationFailed:
|
58
|
0
|
pass
|
59
|
|
|
60
|
0
|
if user_auth_tuple is not None:
|
61
|
0
|
message._authenticator = authenticator
|
62
|
0
|
user, auth = user_auth_tuple
|
63
|
0
|
break
|
64
|
0
|
message.user, message.auth = user, auth
|
65
|
|
# Make sure there's a session key
|
66
|
|
# Run the consumer
|
67
|
0
|
result = func(message, *args, **kwargs)
|
68
|
0
|
return result
|
69
|
6
|
return inner
|
70
|
|
|
71
|
|
|
72
|
6
|
def rest_token_user(func):
|
73
|
|
"""
|
74
|
|
saf Wraps a HTTP or WebSocket consumer (or any consumer of messages
|
75
|
|
that provides a "COOKIES" attribute) to provide both a "session"
|
76
|
|
attribute and a "user" attibute, like AuthMiddleware does.
|
77
|
|
|
78
|
|
This runs http_session() to get a session to hook auth off of.
|
79
|
|
If the user does not have a session cookie set, both "session"
|
80
|
|
and "user" will be None.
|
81
|
|
"""
|
82
|
0
|
@rest_auth
|
83
|
0
|
@functools.wraps(func)
|
84
|
|
def inner(message, *args, **kwargs):
|
85
|
|
# If we didn't get a session, then we don't get a user
|
86
|
0
|
if not hasattr(message, "auth"):
|
87
|
0
|
raise ValueError("Did not see a http session to get auth from")
|
88
|
0
|
return func(message, *args, **kwargs)
|
89
|
0
|
return inner
|
90
|
|
|
91
|
|
|
92
|
6
|
class RestTokenConsumerMixin(object):
|
93
|
6
|
rest_user = False
|
94
|
|
|
95
|
6
|
def get_handler(self, message, **kwargs):
|
96
|
0
|
handler = super(RestTokenConsumerMixin, self).get_handler(message, **kwargs)
|
97
|
0
|
if self.rest_user:
|
98
|
0
|
handler = rest_token_user(handler)
|
99
|
0
|
return handler
|
100
|
|
|
101
|
6
|
def connect(self, message, **kwargs):
|
102
|
0
|
if self.rest_user and not self.message.user:
|
103
|
0
|
self.close()
|
104
|
0
|
return message
|