requests | ||
ungleichotp | ||
ungleichotpclient | ||
ungleichotpserver | ||
.gitignore | ||
README.md | ||
requirements.txt |
ungleichotp
ungleich-otp is a full blown authentication and authorisation service made for micro services.
The basic idea is that every micro service has a (long term) triple constisting of (name, realm, seed) and creates time based tokens.
This basically revamps Kerberos in a simple way into the web area.
ungleichotp has been created and is maintained by ungleich.
Related documentation:
Overview
This repository contains three components:
- ungleichotp-server: the reference implementation of the ungleichotp server
- ungleichotp-client: a sample implementation of an ungleichotp client
Overview client
An application that lets you enter the triple (realm, name, token) and responds with OK / NOTOK.
How to use:
Setup instructions
This is a standard django project and thus can be easily setup using
pip install -r requirements.txt
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
The usual instructions on how to setup an https proxy should be followed.
Realms
Access is granting/denied based on realms. There are two reserved realms, all other realms can be used by the users:
Reserved realms
Conceptually the realms "ungleich-admin" and "ungleich-auth" are reserved for higher priviliged applications.
Usually there is only 1 entry in ungleich-admin that is used to bootstrap and manage ungleich-otp.
All micro services that are trusted to authenticate another micro service should have an entry in the ungleich-auth realm, which allows them to verify a token of somebody else.
| Name | Capabilities | |------------------+--------------------------------------------| | ungleich-admin | authenticate, create, delete, list, update | | ungleich-auth | authenticate | | all other realms | NO ACCESS |
Environment / Configuration (unfinished)
- POSTGRES_USERNAME
- SECRET_KEY -- random (?)
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
Don’t 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:
{
version: "1",
name: "your-name",
realm: "your-realm",
token: "current time based token",
verifyname: "name that wants to be authenticated",
verifyrealm: "realm that wants to be authenticated",
verifytoken: "token that wants to be authenticated",
}
Response JSON object:
Either HTTP 200 with
{
status: "OK",
}
OR return code 403:
- If token for authenticating is wrong, you get
{"detail":"Incorrect authentication credentials."}
- If token that is being verified is wrong, you get
{"detail":"You do not have permission to perform this action."}
Authorize the request
From the ungleichotp-server, you get a validated information that a name on a realm authenticated successfully. The associated permissions ("authorization") is application specific and needs to be decided by 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
- (server) Serialize / input request
- (server) Make seed read only
- (server) Implement registering of new entries
- (server) OTPSerializer: allow to read seed for admin
- (server) Implement deleting entry
- (server) Include verify in ModelSerializer
- (server) Map name+realm == User (?)
- name == name@realm
- password is used for admin login (?)
- seed
- custom auth method
- [n] (server) Try to fake username for django based on name+realm (?)
- No need
- [n] (server) maybe overwrite get_username()
- No need
- (server) Use Custom authentication - needs to have a user!
- (server) Implement creating new "User" by POST / Model based
- [n] (server) Remove hard coded JSON in /verify (no - good enough for the moment)
- (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 manage
- (doc) Add proper documentation
- (server) Add tests for verify
- (server) Add tests for authentication
- (server) move totp constants 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) Read DB from outside (?) (fallback to sqlite)
- (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) extract generic parts from server
- (library) upload to pypi
Changelog
0.6, 2018-11-18
- Reuse TokenSerializer for VerifySerializer logic
0.5, 2018-11-18
- Require authentication on all rest endpoints by token