Phase in ungleichotp
This commit is contained in:
parent
963585806a
commit
2e228f3a0d
3 changed files with 74 additions and 17 deletions
19
README.md
19
README.md
|
@ -220,6 +220,13 @@ name on a realm authenticated successfully. The associated permissions
|
||||||
your application.
|
your application.
|
||||||
|
|
||||||
|
|
||||||
|
## Limitations ##
|
||||||
|
|
||||||
|
* Name, Realm and seed are hard coded to 128 bytes length. This can be
|
||||||
|
changed, if necessary.
|
||||||
|
* Only python3 support for ungleichotp
|
||||||
|
|
||||||
|
|
||||||
## TODOs
|
## TODOs
|
||||||
|
|
||||||
- [x] (server) Serialize / input request
|
- [x] (server) Serialize / input request
|
||||||
|
@ -240,22 +247,24 @@ your application.
|
||||||
- [x] (server) Use Custom authentication - needs to have a user!
|
- [x] (server) Use Custom authentication - needs to have a user!
|
||||||
- [x] (server) Implement creating new "User" by POST / Model based
|
- [x] (server) Implement creating new "User" by POST / Model based
|
||||||
- [n] (server) Remove hard coded JSON in /verify (no - good enough for the moment)
|
- [n] (server) Remove hard coded JSON in /verify (no - good enough for the moment)
|
||||||
|
- [x] (server) Fully rename server from ungleichotp to ungleichotpserver
|
||||||
- [ ] (security) Ensure that only the right realms can verify
|
- [ ] (security) Ensure that only the right realms can verify
|
||||||
- [ ] (security) Ensure that only the right realms can manage
|
- [ ] (security) Ensure that only the right realms can manage
|
||||||
|
- [ ] (doc) Add proper documentation
|
||||||
- [ ] (server) Add tests for verify
|
- [ ] (server) Add tests for verify
|
||||||
- [ ] (server) Add tests for authentication
|
- [ ] (server) Add tests for authentication
|
||||||
- [ ] (doc) Add proper documentation
|
|
||||||
- [ ] (server) move totp constants into settings
|
- [ ] (server) move totp constants into settings
|
||||||
- [ ] (server) move field lengths into settings
|
- [ ] (server) move field lengths into settings
|
||||||
|
- [ ] (server) Document how admin vs. rest works
|
||||||
- [ ] (server, client) Make settings adjustable by environment - k8s/docker compatible
|
- [ ] (server, client) Make settings adjustable by environment - k8s/docker compatible
|
||||||
- [ ] (server, client) Read DB from outside (?) (fallback to sqlite)
|
- [ ] (server, client) Read DB from outside (?) (fallback to sqlite)
|
||||||
|
- [x] (client) Establish auth using urllib
|
||||||
|
- [ ] (client) Bootstrap Django + DRF (including an object for CRUD)
|
||||||
|
- [ ] (client) Add custom authentication / remote auth
|
||||||
|
- [ ] (client) Show case: any realm vs. specific realm
|
||||||
- [ ] (library) Write a "client library" that can use ungleichotp
|
- [ ] (library) Write a "client library" that can use ungleichotp
|
||||||
- [ ] (library) extract generic parts from server
|
- [ ] (library) extract generic parts from server
|
||||||
- [ ] (library) upload to pypi
|
- [ ] (library) upload to pypi
|
||||||
- [ ] (client) Bootstrap Django + DRF (including an object for CRUD)
|
|
||||||
- [ ] (client) Add custom authentication / remote auth
|
|
||||||
- [ ] (server) Document how admin vs. rest works
|
|
||||||
- [ ] (server) Fully rename server from ungleichotp to ungleichotpserver
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,64 @@
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from rest_framework import authentication
|
from rest_framework import authentication, exceptions, serializers
|
||||||
from rest_framework import exceptions
|
|
||||||
|
|
||||||
class ExampleAuthentication(authentication.BaseAuthentication):
|
import urllib.request
|
||||||
|
import pyotp
|
||||||
|
import json
|
||||||
|
|
||||||
|
# For parsing
|
||||||
|
class TokenSerializer(serializers.Serializer):
|
||||||
|
name = serializers.CharField(max_length=128)
|
||||||
|
token = serializers.CharField(max_length=128)
|
||||||
|
realm = serializers.CharField(max_length=128)
|
||||||
|
|
||||||
|
token_name = 'token'
|
||||||
|
name_name = 'name'
|
||||||
|
realm_name = 'realm'
|
||||||
|
|
||||||
|
def __init__(self, name, realm, seed, serverurl, *args, **kwargs):
|
||||||
|
self.name = name
|
||||||
|
self.realm = realm
|
||||||
|
self.seed = seed
|
||||||
|
self.serverurl = serverurl
|
||||||
|
|
||||||
|
super(serializers.Serializer, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
to_send = {}
|
||||||
|
|
||||||
|
# Client credentials to be verified
|
||||||
|
to_send['verifytoken'] = self.validated_data.get(self.token_name)
|
||||||
|
to_send['verifyname'] = self.validated_data.get(self.name_name)
|
||||||
|
to_send['verifyrealm'] = self.validated_data.get(self.real_name)
|
||||||
|
|
||||||
|
# Our credentials
|
||||||
|
to_send['token'] = pyotp.TOTP(self.seed)
|
||||||
|
to_send['name'] = self.name
|
||||||
|
to_send['realm'] = self.realm
|
||||||
|
|
||||||
|
data = json.dumps(to_send).encode("utf-8")
|
||||||
|
|
||||||
|
req = urllib.request.Request(url=serverurl,
|
||||||
|
data=data,
|
||||||
|
headers={'Content-Type': 'application/json'},
|
||||||
|
method='POST')
|
||||||
|
|
||||||
|
f = urllib.request.urlopen(req)
|
||||||
|
|
||||||
|
if not f.status == 200:
|
||||||
|
raise exceptions.AuthenticationFailed()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
class OTPAuthentication(authentication.BaseAuthentication):
|
||||||
def authenticate(self, request):
|
def authenticate(self, request):
|
||||||
username = request.META.get('X_USERNAME')
|
serializer = TokenSerializer(data=request.data)
|
||||||
if not username:
|
|
||||||
return None
|
|
||||||
|
|
||||||
try:
|
if serializer.is_valid():
|
||||||
user = User.objects.get(username=username)
|
print("trying to save... {}".format(serializer))
|
||||||
except User.DoesNotExist:
|
user, token = serializer.save()
|
||||||
raise exceptions.AuthenticationFailed('No such user')
|
else:
|
||||||
|
raise exceptions.AuthenticationFailed()
|
||||||
|
|
||||||
return (user, None)
|
return (user, token)
|
||||||
|
|
|
@ -29,7 +29,7 @@ class TokenSerializer(serializers.Serializer):
|
||||||
name_in = self.validated_data.get(self.name_name)
|
name_in = self.validated_data.get(self.name_name)
|
||||||
realm_in = self.validated_data.get(self.realm_name)
|
realm_in = self.validated_data.get(self.realm_name)
|
||||||
|
|
||||||
# print("auth: {} {} {} ({} {} {} -- {})".format(token_in, name_in, realm_in, self.token_name, self.name_name, self.realm_name, self.validated_data))
|
print("auth: {} {} {} ({} {} {} -- {})".format(token_in, name_in, realm_in, self.token_name, self.name_name, self.realm_name, self.validated_data))
|
||||||
|
|
||||||
# 1. Verify that the connection might authenticate
|
# 1. Verify that the connection might authenticate
|
||||||
try:
|
try:
|
||||||
|
|
Loading…
Reference in a new issue