| [dbb39a2] | 1 | from django.contrib.auth.models import User |
|---|
| 2 | import socket |
|---|
| 3 | import settings |
|---|
| 4 | |
|---|
| 5 | class SocketAuthBackend(): |
|---|
| [734ef4f] | 6 | """ |
|---|
| 7 | SocketAuthBackend provides a simple way to authenticate with another process. |
|---|
| 8 | |
|---|
| 9 | The protocol is simple: |
|---|
| 10 | * Open a connection to a socket. |
|---|
| 11 | * On the first line, pass the name of the operation |
|---|
| 12 | * Then, on successive lines, pass additional arguments, one per line |
|---|
| 13 | * Close the write half of the socket |
|---|
| 14 | * The authentication server sends back a reply, one tuple element |
|---|
| 15 | per line |
|---|
| 16 | |
|---|
| 17 | Queries include: |
|---|
| 18 | * AUTHENTICATE(username, password) => boolean |
|---|
| 19 | * FINGER(username) => (first name, last name, email, ) |
|---|
| 20 | """ |
|---|
| [dbb39a2] | 21 | def authenticate(self, username, password, ): |
|---|
| [e1ae8b3] | 22 | (result,) = query(1, "AUTHENTICATE", username, password, ) |
|---|
| [dbb39a2] | 23 | print result |
|---|
| 24 | if result == 'true': |
|---|
| 25 | try: |
|---|
| 26 | user = User.objects.get(username=username) |
|---|
| 27 | if len(user.groups.filter(name='local-auth-only')) > 0: |
|---|
| 28 | if user.check_password(password): |
|---|
| 29 | return user |
|---|
| 30 | else: |
|---|
| 31 | return None |
|---|
| 32 | else: |
|---|
| 33 | return user |
|---|
| 34 | except User.DoesNotExist: |
|---|
| 35 | user = User(username=username, password='SocketAuth') |
|---|
| 36 | user.is_staff = False |
|---|
| 37 | user.is_superuser = False |
|---|
| 38 | # Is there a race condition here? Yes. |
|---|
| 39 | # Should I do more error-checking? Yes. |
|---|
| 40 | # Do I care? No. |
|---|
| [e1ae8b3] | 41 | (first, last, email,) = query(3, 'FINGER', username) |
|---|
| [dbb39a2] | 42 | user.first_name = first |
|---|
| 43 | user.last_name = last |
|---|
| 44 | user.email = email |
|---|
| 45 | user.save() |
|---|
| 46 | return user |
|---|
| 47 | return None |
|---|
| 48 | |
|---|
| 49 | def get_user(self, user_id): |
|---|
| 50 | try: |
|---|
| 51 | return User.objects.get(pk=user_id) |
|---|
| 52 | except User.DoesNotExist: |
|---|
| 53 | return None |
|---|
| 54 | |
|---|
| [e1ae8b3] | 55 | def query(length, *args): |
|---|
| [dbb39a2] | 56 | conn = socket.socket(socket.AF_UNIX) |
|---|
| 57 | conn.connect(settings.AUTH_SOCK) |
|---|
| 58 | conn.send('\n'.join(args)) |
|---|
| 59 | conn.shutdown(socket.SHUT_WR) |
|---|
| [e1ae8b3] | 60 | result = conn.makefile().read().split('\n') |
|---|
| 61 | if(len(result)==length+1 and result[-1] == ''): |
|---|
| 62 | result = result[:-1] |
|---|
| 63 | if len(result) != length: |
|---|
| 64 | raise ValueError("Got return value of length %d to query '%s'; needed length %d" % (len(result), args[0], length, )) |
|---|
| [dbb39a2] | 65 | conn.close() |
|---|
| 66 | return result |
|---|