Go to file
Valentin Kolb 294fc8ac3d
Build and Push Docker image / build-and-push (push) Successful in 3m4s Details
fix(messages): send all email for a notifications sequentially to avoid to many connections bugs
2024-06-20 19:44:17 +02:00
.gitea/workflows ci(cicd): Update pipeline 2024-03-27 17:58:49 +01:00
html feat(messages): added email notifications 2024-06-11 23:12:17 +02:00
ldapApi feat(app): chnaged users table 2024-05-14 14:18:20 +02:00
ldapSync feat(messages): added email notifications 2024-06-11 23:12:17 +02:00
logger added plugins 2023-10-26 22:34:59 +02:00
main fix(messages): send all email for a notifications sequentially to avoid to many connections bugs 2024-06-20 19:44:17 +02:00
messages fix(messages): send all email for a notifications sequentially to avoid to many connections bugs 2024-06-20 19:44:17 +02:00
qrApi feat(qrApi): Got newest version of piglig/go-qr lib 2024-04-23 08:29:49 +02:00
.dockerignore feat: qr-code api, major refactor, objectGUID as user id and group id 2024-03-27 15:36:45 +01:00
.gitignore feat: qr-code api, major refactor, objectGUID as user id and group id 2024-03-27 15:36:45 +01:00
Dockerfile fix(docker): fixed go version in Dockerfile 2024-06-11 23:17:20 +02:00
Readme.md feat(qrApi): data now passed as query string 2024-03-27 19:43:54 +01:00
docker-compose.yml ci(cicd): Update pipeline 2024-03-27 17:58:49 +01:00
go.mod feat(messages): added email notifications 2024-06-11 23:12:17 +02:00
go.sum feat(messages): added email notifications 2024-06-11 23:12:17 +02:00

Readme.md

StuVe IT Tools Backend

Übersicht

Als Backend für die StuVe IT Tools wird Pocketbase verwendet. Pocketbase ist ein self-hosted Backend-as-a-Service, der auf SQLite basiert.

Was ist Pocketbase?

Implementiert ist Pocketbase in Golang und kann dort auch einfach als Library eingebunden werden und so erweitert werden. Dies wurde in diesem Projekt auch gemacht, um die Authentifizierung um eine LDAP Authentifizierung zu erweitern.

Aus diesem Grund handelt es sich bei diesem Projekt nicht um einen Fork von Pocketbase, sondern um eine Library, die Pocketbase erweitert.

Pocketbase selbst bietet folgende Features:

  • Datenbank
    • Als Datenbank verwendet Pocketbase SQLite
  • Authentifizierung
    • Pocketbase bietet sogenannte "Auth-Collections" an, die eine Authentifizierung über E-Mail und Passwort ermöglichen.
    • Es ist allerdings möglich dieses Mechanismus zu erweitern was in diesem Projekt auch gemacht wurde. (siehe unten)
  • File Storage
    • Pocketbase bietet einen File Storage an, der allerdings nur Dateien bis 5B unterstützt.
    • Achtung: Per Default sind alle Dateien öffentlich zugänglich.
  • E-Mail Versand (limitiert aber in Golang erweiterbar)
    • Pocketbase sendet per Default nur System E-Mails, zb Passwort vergessen.
    • Über Golang ist es allerdings möglich den E-Mailversand zu erweitern. Dies ist in Planung.
  • Realtime Events (Websockets)
    • Pocketbase bietet einen Realtime Event Service an, der über Websockets funktioniert. Dabei können auf alle Datenbank Events (Insert, Update, Delete) reagiert werden.
  • JavaScript SDK
    • Pocketbase bietet ein JavaScript SDK an, das alle Features von Pocketbase unterstützt.

Admin UI

Pocketbase bietet eine Admin UI an, die unter https://<pocketbase-url>/_/ erreichbar ist. Der Login hierzu ist im SysPass unter Pocketbase zu finden.

In der Admin UI können Tabellen erstellt, bearbeitet und gelöscht werden. Außerdem können die API Rules bearbeitet werden, die festlegen, welche Funktionen für die einzelnen Tabellen und User erlaubt sind.

Entwickeln

git clone https://git.stuve.uni-ulm.de/stuve-it/stuve-it-backend.git
cd stuve-it-backend
go run main/main.go serve # --debug=0 for no debug output

Installation

Das Projekt kann mittels Docker installiert werden. Durch die Gitlab CI/CD Pipeline wird bei jedem Push auf main ein neues Docker Image erstellt. Dieses muss dann nur noch auf dem Server deployt werden.

Projekt Struktur

Die einzelnen custom go Packages sind weiter unten beschrieben.

├── Dockefile           # Dockerfile für die Entwicklung
├── .dockerignore       # Dateien die nicht in den Docker Container kopiert werden sollen
├── .gitignore          # Dateien die nicht in Git gepusht werden sollen
├── go.mod              # Go Module Datei (Go's Package Manager)
├── main                # Main Package (App Entry Point)
│   └── main.go         #   Main Funktion
├── logger              # Custom Logger Package
│   └── main.go         #   Logger Funktionen
├── ldapSync            # LDAP Sync Package
│   ├── main.go         #   LDAP Sync Entry Point
│   ├── db.go           #   Datenbank Funktionen (Insert Users, Groups, ...)
│   ├── models.go       #   Structs für LDAP User und Group
│   ├── tables.go       #   Erstellt die benötigten Tabellen in der Datenbank (Users, Groups, Logs)
│   └── ldapSync.go     #   Sync Funktionen (Sync Users, Groups, ...)
├── ldapApi             # LDAP API Package
│   └── main.go         #   Api Route
└── qrApi               # QR API Package
    └── main.go         #   Api Route

Custom Packages

Damit Pocketbase mit der StuVe IT Tools Infrastruktur funktioniert, wurden einige Packages erstellt, die Pocketbase erweitern.

Logger

Das Logger Package ist ein custom Logger, der die Log-Nachrichten farblich in die Konsole schreibt. Diese Package ist sehr minimal gehalten und bietet nur die Funktionen Success, Info und Error an.

Beispiel

package main

import "git.stuve.uni-ulm.de/stuve-it/stuve-it-backend/logger"

func main() {
	logger.LogInfoF("Info Message")
	logger.LogErrorF("Warn Message")
	logger.LogErrorF("Error Message")
}

QR API

Das QR API Package ist ein einfaches Package, das eine API Route zum Generieren von QR-Codes in SVG anbietet.

API Route

Das Package bietet die Route GET /api/qr/v1 an, welche die folgenden Parameter als query string entgegennimmt:

Parameter Datentyp Beschreibung
data string Der Text, der im QR-Code codiert werden soll (required)
ecc string-enum Der Error Correction Level des QR-Codes (L, M - default, Q, H)
scale int Der Scale des QR-Codes (default 1)
border int Der Border des QR-Codes (default 1), eine Border Uni ist die Größe von einem QR-Code 'pixel'
color hex-string Die Farbe des QR-Codes (default #000000)
colorBackground hex-string Die Hintergrundfarbe des QR-Codes (default #FFFFFF)

Beispiel

curl -X GET https://it.stuve.uni-ulm.de/api/qr/v1?data=stuve.uni-ulm.de

LDAP API

Im LDAP API Package sind zwei API Routen implementiert:

  • LDAP Login: POST /api/ldap/login
  • LDAP Search: GET /api/ldap/search

LDAP Login

Dieses Package implementiert eine LDAP Authentifizierung, die Pocketbase um eine LDAP Authentifizierung erweitert.

Das Package bietet die Route POST /api/ldap/login an, welche die folgenden Parameter als json entgegennimmt:

Parameter Datentyp Beschreibung
username string Der Benutzername des LDAP Users (cn) (required)
password string Das Passwort des LDAP Users (required)
Konfiguration

Das Package benötigt folgende ENV Variablen:

  • LDAP_URL: LDAP Server URL (e.g. ldap://ldap.stuve.uni-ulm.de)
Mechanismus

Das Passwort wird mit dem LDAP Server abgeglichen und nach einer erfolgreichen Authentifizierung ein Token und das ldap_user Modell zurückgegeben. Die memberOf Beziehungen werden dabei automatisch geladen. Das Passwort wird nicht in der Datenbank gespeichert.

Diese Response ist identisch mit der standard Pocketbase Authentifizierung (z.B. AuthWithPassword).

Beispiel
curl -X POST https://it.stuve.uni-ulm.de/api/ldap/login -d '{"username": "vorname.nachname", "password": "*******"}'

Dieses Package implementiert eine LDAP Suche, die Pocketbase um eine LDAP Suche erweitert. Damit kann per HTTP Request die LDAP Datenbank durchsucht werden.

Das Package bietet die Route GET /api/ldap/search an, welche die folgenden Parameter als json entgegennimmt:

Parameter Datentyp Beschreibung
baseDN string Die Base DN, in der gesucht werden soll (required)
filter string Der Filter, nach dem gesucht werden soll (required)
attributes []string Die Attribute, die zurückgegeben werden sollen, bei einem leeren Array werden alle Attribute zurückgegeben.
Konfiguration

Das Package benötigt folgende ENV Variablen:

  • LDAP_URL: LDAP Server URL (e.g. ldap://ldap.stuve.uni-ulm.de)
  • LDAP_BIND_DN: LDAP Bind DN (zum Lesen der LDAP Datenbank, admin user)
  • LDAP_ADMIN_GROUP_DN: LDAP Admin Group DN (Gruppe, die Admin Rechte hat)
Mechanismus

Die Route führt eine LDAP Suche durch und gibt die gefundenen LDAP Objekte zurück. Dabei wird die Suche mit dem LDAP_BIND_DN durchgeführt.

Es wird überprüft, ob der User der das GET Request schickt in der LDAP_ADMIN_GROUP_DN Gruppe ist.

Beispiel
curl -X GET https://it.stuve.uni-ulm.de/api/ldap/search -d '{"baseDN": "ou=useraccounts,ou=user,dc=stuve,dc=uni-ulm,dc=de", "filter": "(cn=vorname.nachname)"}'

Als return wir ein JSON Objekt nach folgendem Schema zurückgegeben:

{
  "Entries": [
    {
      "DN": "CN=vorname.nachname,OU=UserAccounts,OU=User,DC=stuve,DC=uni-ulm,DC=de",
      "Attributes": [
        {
          "Name": "cn",
          "Values": [
            "vorname.nachname"
          ],
          "ByteValues": [
            "xxxxxxxxxxxxxxx"
          ]
        }
      ]
    }
  ],
  "Referrals": [],
  "Controls": []
}

Json Schemata:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "properties": {
    "Entries": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "DN": {
            "type": "string"
          },
          "Attributes": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "Name": {
                  "type": "string"
                },
                "Values": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "ByteValues": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              },
              "required": ["Name", "Values", "ByteValues"]
            }
          }
        },
        "required": ["DN", "Attributes"]
      }
    },
    "Referrals": {
      "type": "array",
      "items": {}
    },
    "Controls": {
      "type": "array",
      "items": {}
    }
  },
  "required": ["Entries", "Referrals", "Controls"]
}

LDAP Sync

Dieses Package ist das umfangreichste Package und synchronisiert die LDAP Datenbank mit der Pocketbase Datenbank.

Dabei werden alle LDAP User und Gruppen in die Pocketbase Datenbank kopiert.

Dieses Package erfordert, dass alle Gruppen und User das Attribut objectGUID haben. Dies ist in der Regel bei Windows ADs der Fall.

LDAP Attribute

Die folgenden LDAP Attribute werden in der Pocketbase Datenbank gespeichert.

User
Attribut Pocketbase Name Beschreibung
objectGUID id Eindeutige ID des Users (nur die ersten 15 Zeichen werden genutzt
givenName givenName Vorname des Users
sn sn Nachname des Users
mail email E-Mail des Users
memberOf memberOf (in Pocketbase eine SQL Relation) Gruppenzugehörigkeit des Users
accountExpires accountExpires (in Pocketbase UTC) Account Ablaufdatum
dn dn Distinguished Name des Users
cn cn & username Common Name des Users
Group
Attribut Pocketbase Name Beschreibung
objectGUID id Eindeutige ID der Gruppe (nur die ersten 15 Zeichen werden genutzt
cn cn Common Name der Gruppe
dn dn Distinguished Name der Gruppe
description description Beschreibung der Gruppe
memberOf memberOf (in Pocketbase eine SQL Relation) Gruppenzugehörigkeit der Gruppe

Konfiguration

Das Package benötigt folgende ENV Variablen:

  • LDAP_URL: LDAP Server URL (e.g. ldap://ldap.stuve.uni-ulm.de)
  • LDAP_BIND_DN: LDAP Bind DN (zum Lesen der LDAP Datenbank, admin user)
  • LDAP_BIND_PASSWORD: LDAP Bind Password (das Passwort des admin users)
  • LDAP_USER_BASE_DN: LDAP User Base DN (hier werden alle User gesucht, e.g. ou=useraccounts,ou=user,dc=stuve,dc=uni-ulm,dc=de)
  • LDAP_USER_FILTER: LDAP User Filter (e.g. (|(objectCategory=person)(objectClass=user)))
  • LDAP_ADMIN_GROUP_DN: LDAP Admin Group DN (Gruppe, die Admin Rechte hat)
  • LDAP_GROUP_BASE_DN: LDAP Group Base DN (hier werden alle Gruppen gesucht, e.g. ou=groups,ou=user,dc=stuve,dc=uni-ulm,dc=de)
  • LDAP_GROUP_FILTER: LDAP Group Filter (e.g. (objectClass=group))
  • LDAP_SUNC_SCHEDULE: LDAP Sync Schedule (e.g. */1 * * * * für minütliches Syncen)
    (siehe Cron)

Tabellen

Das Package erstellt folgende Tabellen in der Pocketbase Datenbank:

  • ldap_users: Alle LDAP User (auth-Collection)
  • ldap_groups: Alle LDAP Gruppen
  • ldap_sync_logs: Alle LDAP Sync Logs (wann wurde was synchronisiert)

Die Tabellen werden automatisch erstellt, wenn das Programm gestartet wird und sie noch nicht existieren.

Sync

Das Package synchronisiert die LDAP Datenbank mit der Pocketbase Datenbank.

Dabei werden alle LDAP User und Gruppen in die Pocketbase Datenbank kopiert. Es werden memberOf ldap Attribute verwendet, um die Gruppenzugehörigkeit zu bestimmen und in SQL Relationen umzuwandeln.

Beim ersten synchronisieren kann es sein, dass eine memberOf Gruppe noch nicht existiert. In diesem Fall wird die Beziehung erst beim nächsten Sync erstellt. Falls eine memberOf Gruppe nicht gefunden wird, wird dies in der Konsole geloggt.

Für jede Synchronisation wird ein Log-in der ldap_sync_logs Tabelle erstellt.

Sowohl für die ldap_users als auch für die ldap_groups Tabelle wird unter den API Rules das bearbeiten und löschen deaktiviert, da diese Tabellen nur synchronisiert werden und nicht manuell bearbeitet werden sollen. Dadruch können sie nur über das LDAP Sync Package (und die Admin UI) bearbeitet werden.

User Sync

Damit man sich später auch als Nutzer anmelden kann, werden die User in einer auth Collection gespeichert. Allerdings werden natürlich nicht die LDAP Passwörter synchronisiert.

Aus diesem Grund muss auch jede Auth-Methode unter Options im Admin UI für diese Collection deaktiviert werden (Username, E-Mail, OAuth2).

Mehr dazu unter dem LDAP Login Package.

DB Util

In der db.go Datei sind alle Datenbank Funktionen implementiert. Hier gibt es Methoden um User oder Groups zu finden, die dabei automatisch die Beziehungen zu anderen Tabellen laden (memberOf).