Skip to content

cloudfleet/musterroll

Repository files navigation

Musterroll

A lightweight LDAP and OAUTH server for user management

Why?

Musterroll wants to be a simple user management tool to make it easier to self-host services for individuals and small organizations.

As a simple LDAP server with an API

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.

Compatible Applications

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:

As a simple OAUTH server with an API

TBI

Example Usage

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

Configuration

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.

Data Model

User

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
email string

Group

At this time there exists only one group, admins.

User Store

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.

LDAP Server

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 email or [id]@[domain]
mail like email

OAuth Server

TBD

User Management API

The user management API provides the following endpoints:

GET /api/v1/currentUser

Returns the currently logged in user. If not logged in returns 401 Not authenticated.

Example Response:

{

}

GET /api/v1/users/from_alias/:alias

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"
}

GET /api/v1/users

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"
  }
]

GET /api/v1/users/:user_id

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"
}

POST /api/v1/users

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"
}

PUT /api/v1/users/:user_id

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"
}

DELETE /api/v1/users/:user_id

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"
}

PUT /api/v1/users/:user_id/password

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"
}

PUT /api/v1/users/:user_id/is_admin

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"
}

About

A user directory server with LDAP and OAUTH interface

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published