A lightweight LDAP and OAUTH server for user management
Musterroll wants to be a simple user management tool to make it easier to self-host services for individuals and small organizations.
LDAP is a widely supported user directory format. However for most use cases the management of a full LDAP server is an overkill that is reflected in overcomplicated user interfaces.
Musterroll exposes the users in a virtual LDAP directory while providing an optional REST API and simple UI to manage them.
Musterroll will never support non user management related aspects of LDAP.
While Musterroll should work with any service that can authenticate against an LDAP directory, some expect non-standard behaviour that other LDAP servers provide. If you run into such a case, please open an issue and we will look into it.
However the following applications have been tested and run well with Musterroll as an LDAP server:
TBI
Typically Musterroll will be deployed as a Docker service.
An exemplary docker-compose file would look like this
---
version: '2'
services:
musterroll:
hostname: musterroll
image: cloudfleet/musterroll
restart: always
volumes:
- "./data:/home/node/app/data"
environment:
USER_STORAGE_PATH: "./data/"
DOMAIN: "example.com"
LDAP_ENABLED: "true"
AUTH_ENABLED: "true"
API_ENABLED: "true"
env_file:
- secrets.env # set SESSION_SECRET there
labels:
- "traefik.port=80"
- "traefik.enable=true"
- "traefik.frontend.rule=Host:example.com"
traefik:
hostname: traefik
image: traefik
restart: always
command:
- "--defaultentrypoints=http,https"
- "--entryPoints=Name:http Address::80 Redirect.EntryPoint:https"
- "--entryPoints=Name:https Address::443 TLS"
- "--docker.exposedByDefault=false"
- "--acme.email=security@example.com"
- "--acme.entryPoint=https"
- "--acme.storage=/acme/acme.json"
- "--acme.tlsChallenge=true"
- "--acme.onHostRule=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./acme:/acme
Variable | Default | Description |
---|---|---|
USER_STORAGE_PATH | ./data/ |
|
DOMAIN | user.example.com |
The root domain. Is used to create the Root DN for LDAP and to autogenerate email adresses if none are present |
DEBUG | false |
TBD |
LDAP_ENABLED | If the variable is present, LDAP server will be enabled | |
LDAP_PORT | 389 |
The port the ldap server should listen on |
AUTH_ENABLED | If the variable is present, login by http is enabled. Prerequisite for API_ENABLED and OAUTH_ENABLED to take effect |
|
API_ENABLED | If the variable is present, the REST API for user management is enabled | |
OAUTH_ENABLED | If the variable is present, the OAUTH server is enabled (not implemented yet) | |
API_PORT | 80 |
The port the http server listens on |
SESSION_SECRET | A string randomly generated at server start | Secret to encrypt cookie data. If not given every server restart invalidates all cookies and logins. |
A user in musterroll has the following properties:
Property | Type | Description |
---|---|---|
id | string | The unique username. Will be used to autopopulate the email field if no explicit email is given. |
uuid | string | Autogenerated, needed for Nextcloud LDAP plugin |
firstname | string | |
lastname | string | |
aliases | list of string | |
isAdmin | boolean | |
passwordHash | string | |
string |
At this time there exists only one group, admins.
At this time only storing users as JSON file is implemented. As soon as there is a second implementation, the user store will be configurable.
The LDAP server exposes the users in a virtual LDAP tree.
The root DN of this tree consists of the elements of the DOMAIN
configuration setting as dc
elements. Eg. the default users.example.com
translates into dc=users, dc=example, dc=com
.
The users are in a subtree under ou=users, [root DN]
, eg. ou=users, dc=users, dc=example, dc=com
.
The user FQDNs are cn=[username], [users subtree DN]
, eg. cn=doublemalt, ou=users, dc=users, dc=example, dc=com
Every user is a inetOrgPerson
with the following attributes:
LDAP Attribute Name | Mapping |
---|---|
cn | id |
uuid | uuid |
givenName | firstname |
sn | lastname |
email or [id]@[domain] | |
like email |
TBD
The user management API provides the following endpoints:
Returns the currently logged in user. If not logged in returns 401 Not authenticated
.
Example Response:
{
}
Returns the user that has the alias
. If not logged in returns 401 Not authenticated
. If no user uses the alias returns 404 Not found
.
Example Response:
{
"id":"admin",
"uuid": "09d182d8-175e-11e9-afb9-47cedb30a11c",
"aliases":[],
"firstname":"John",
"lastname":"Doe",
"isAdmin":true,
"email":"admin@example.com"
}
Returns a list of all users. If not logged in returns 401 Not authenticated
. If logged in but not admin returns 403 Unauthorized
.
Example Response:
[
{
"id":"admin",
"uuid": "09d182d8-175e-11e9-afb9-47cedb30a11c",
"aliases":[],
"firstname":"John",
"lastname":"Doe",
"isAdmin":true,
"email":"admin@example.com"
}
]
Returns the user identified by user_id
. If not logged in returns 401 Not authenticated
. If logged in but not admin or logged in as the user with user_id
returns 403 Unauthorized
.
Example Response:
{
"id":"admin",
"uuid": "09d182d8-175e-11e9-afb9-47cedb30a11c",
"aliases":[],
"firstname":"John",
"lastname":"Doe",
"isAdmin":true,
"email":"admin@example.com"
}
Creates a new user. If not logged in returns 401 Not authenticated
. If logged in but not admin returns 403 Unauthorized
.
Example Payload:
{
"id":"jack",
"firstname":"Jack",
"lastname":"Doe"
}
Example Response:
{
"id":"jack",
"uuid": "7144b534-175e-11e9-820c-c373deae43d3",
"aliases":[],
"firstname":"Jack",
"lastname":"Doe",
"isAdmin":false,
"email":"jack@example.com"
}
Updates a user. If not logged in returns 401 Not authenticated
. If logged in but not admin or logged in as the user with user_id
returns 403 Unauthorized
.
Example Payload:
{
"email":"jack.doe@example.com",
}
Example Response:
{
"id":"jack",
"uuid": "7144b534-175e-11e9-820c-c373deae43d3",
"aliases":[],
"firstname":"Jack",
"lastname":"Doe",
"isAdmin":false,
"email":"jack.doe@example.com"
}
Deletes a user. If not logged in returns 401 Not authenticated
. If logged in but not admin returns 403 Unauthorized
.
Example Response:
{
"id":"jack",
"uuid": "7144b534-175e-11e9-820c-c373deae43d3",
"aliases":[],
"firstname":"Jack",
"lastname":"Doe",
"isAdmin":false,
"email":"jack@example.com"
}
Sets password for a user. If not logged in returns 401 Not authenticated
. If logged in but not admin or logged in as the user with user_id
returns 403 Unauthorized
.
Example Payload:
{
"password": "supersecurerandompassword"
}
Example Response:
{
"success": "true"
}
Sets admin rights for a user. If not logged in returns 401 Not authenticated
. If logged in but not admin returns 403 Unauthorized
.
Example Payload:
{
"is_admin": "true"
}
Example Response:
{
"success": "true"
}