This commit is contained in:
Nico Schottelius 2018-12-24 20:46:54 +01:00
parent 45394fa59c
commit 8636d3f81a
2 changed files with 41 additions and 127 deletions

157
README.md
View file

@ -16,47 +16,52 @@ Related documentation:
* [RFC6238, TOTP](https://tools.ietf.org/html/rfc6238) * [RFC6238, TOTP](https://tools.ietf.org/html/rfc6238)
* [RFC4120, Kerberos](https://tools.ietf.org/html/rfc4120) * [RFC4120, Kerberos](https://tools.ietf.org/html/rfc4120)
## Overview ## Overview ##
This repository contains three components: This repository contains...
* ungleichotp-server: the reference implementation of the ungleichotp server * ungleichotpserver: the reference implementation of the ungleichotp server
* ungleichotp-client: a sample implementation of an ungleichotp client * ungleichotpclient.py: a sample implementation of an ungleichotp client
### Overview client ### ## Verifying a token using ungleichotpclient.py ##
An application that lets you enter the triple (realm, name, token) and Assuming you want to verify
responds with OK / NOTOK. (name=ipv6only, realm=ungleich-intern, token=498593) is a
valid triple and you do have credentials to access ungleich-otp
(name=info@ungleich.ch, realm=ungleich-admin, seed=PZKBPTHDGSLZBKIZ),
then the following call will verify the token:
How to use: ```
UNGLEICHOTPNAME=info@ungleich.ch \
UNGLEICHOTPREALM=ungleich-admin \
UNGLEICHOTPSEED=PZKBPTHDGSLZBKIZ \
UNGLEICHOTPSERVER=http://localhost:8000/ungleichotp/verify/ \
python ungleichotpclient.py -n -r ungleich --token 498593
```
You can also veriy using a seed:
```
UNGLEICHOTPNAME=info@ungleich.ch \
UNGLEICHOTPREALM=ungleich-admin \
UNGLEICHOTPSEED=PZKBPTHDGSLZBKIZ \
UNGLEICHOTPSERVER=http://localhost:8000/ungleichotp/verify/ \
python ungleichotpclient.py -n -r ungleich --seed CEKXVG3235PO2HDW
```
The client requires pyotp.
## Server Setup instructions ##
## Setup instructions ##
This is a standard django project and thus can be easily setup using This is a standard django project and thus can be easily setup using
``` ```
pip install -r requirements.txt pip install -r requirements.txt
``` python manage.py createsuperuser
To bootstrap the application, you need your very first trusted seed to
access the application. You can generate it using
```
to be filled in
```
After that, you can run the application using
```
python manage.py runserver python manage.py runserver
``` ```
The usual instructions on how to setup an https proxy should be followed.
## Realms ## ## Realms ##
@ -84,113 +89,15 @@ them to verify a token of somebody else.
## Environment / Configuration (unfinished) ## Verify using http POST ##
- POSTGRES_USERNAME Post a JSON object to the server at /ungleichotp/verify/ that
- SECRET_KEY -- random (?) contains the following elements:
## Random notes / stuff (unfinished)
django.db.backends.postgresql
django.contrib.admin
```
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydatabase',
'USER': 'mydatabaseuser',
'PASSWORD': 'mypassword',
'HOST': '127.0.0.1',
'PORT': '5432',
}
}
```
Custom auth
```
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('X_USERNAME')
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return (user, None)
```
Custom user
Dont forget to point AUTH_USER_MODEL to it. Do this before creating any migrations or running manage.py migrate for the first time.
### To document
* Login via username password interactively
* Login via name/realm/token rest
## The library (ungleichotp)
## The server (ungleichotp-server)
## The sample client (ungleichotp-client)
The included client application is a Django application that makes use
of an ungleichotp-server to authenticate requests.
### Usage
* Ensure that the ungleichotp-server is running and reachable
## Integrating ungleichotp
### In Django
### In other frameworks
In general, you will need to implement the following into your app for
resources that need to have an authenticated user:
#### Retrieve name, realm and token from the request
This is application specific. In the sample Django rest framework, we
use JSON to retrieve this values:
```
{
"name": "info@ungleich.ch",
"token": "947732",
"realm": "ungleich-admin",
"otherdata": "..."
}
```
#### Send name, realm and token from the request to the ungleichotp-server
Post a JSON object to /ungleichotp/verify that contains the following
elements:
Request JSON object: Request JSON object:
``` ```
{ {
version: "1",
name: "your-name", name: "your-name",
realm: "your-realm", realm: "your-realm",
token: "current time based token", token: "current time based token",
@ -223,7 +130,7 @@ OR return code 403:
{"detail":"You do not have permission to perform this action."} {"detail":"You do not have permission to perform this action."}
``` ```
#### Authorize the request ## Authorize the request ##
From the ungleichotp-server, you get a validated information that a From the ungleichotp-server, you get a validated information that a
name on a realm authenticated successfully. The associated permissions name on a realm authenticated successfully. The associated permissions

View file

@ -50,7 +50,10 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser(description='ungleichotp-client') parser = argparse.ArgumentParser(description='ungleichotp-client')
parser.add_argument('-n', '--name', help="Name (for verification)", required=True) parser.add_argument('-n', '--name', help="Name (for verification)", required=True)
parser.add_argument('-r', '--realm', help="Realm (for verification)", required=True) parser.add_argument('-r', '--realm', help="Realm (for verification)", required=True)
parser.add_argument('-t', '--token', help="Token (for verification)", required=True)
g = parser.add_mutually_exclusive_group(required=True)
g.add_argument('--token', help="Token (for verification)")
g.add_argument('--seed', help="Seed (for verification)")
args = parser.parse_args(sys.argv[1:]) args = parser.parse_args(sys.argv[1:])
@ -66,9 +69,13 @@ if __name__ == '__main__':
os.environ['UNGLEICHOTPSERVER']) os.environ['UNGLEICHOTPSERVER'])
if args.seed:
token = pyotp.TOTP(args.seed).now()
else:
token = args.token
try: try:
if client.verify(args.name, args.realm, args.token) == True: if client.verify(args.name, args.realm, token) == True:
print("Verify ok") print("Verify ok")
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
print("Failed to verify: {}".format(e)) print("Failed to verify: {}".format(e))