Administrationshandbuch
Hinweise, Tipps und Best Practices für die Administration von ProjectForge
- 1. Einführung
- 2. ProjectForge einrichten
- 3. Konfiguration
- 3.1. Basisverzeichnis (Home-Verzeichnis der Anwendung)
- 3.2. Konfigurationsdatei application.properties
- 3.3. Funktionen abschalten
- 3.4. Anpassungen
- 3.5. Konfigurationseinstellungen (Weboberfläche)
- 3.6. TTF-Schriften für die PDF-Render-Engine verwenden
- 3.7. HTML-formatierte E-Mail-Vorlagen
- 3.8. E-Mails versenden
- 3.9. Fehler-Digest für den Support
- 3.10. System-Dashboard und Log-Viewer
- 3.11. Telefonieren und SMS mit ProjectForge
- 3.12. Nummernkreise von Kunden, Projekten und Kostenträgern
- 3.13. Nomenklatur der Gruppen
- 3.14. Betriebswirtschaftliche Auswertung / BWA
- 3.15. Sicherheitskonfiguration
- 3.16. LDAP
- 3.17. OAuth2-/OIDC-Authentifizierung
- 3.18. Synchronisation mit einem Identity Provider (IdP)
- 3.19. Fehlerbehebung
- 4. Wartung
- 5. Plugins
1. Einführung
Dieses Dokument beschreibt die Administration von ProjectForge®: Konfiguration, Sicherheit, Benutzerverzeichnisse, Backups und Wartung. Die Installation von ProjectForge (Docker oder JAR, Einrichtungsassistent, Reverse Proxy) ist zuvor in Installation beschrieben.
Alle hier genannten Einstellungen gehören, sofern nicht anders angegeben, in die Datei projectforge.properties im
Home-Verzeichnis von ProjectForge (vom Einrichtungsassistenten angelegt). Die Standardwerte mit Kommentaren sind in
application.properties
aufgeführt. Nach einer Änderung dieser Datei muss ProjectForge neu gestartet werden.
2. ProjectForge einrichten
2.1. Datenbank
Der Einrichtungsassistent schreibt die Datenbankeinstellungen, daher müssen sie in der Regel nicht angepasst werden.
ProjectForge verwendet den Connection-Pool von Spring Boot (HikariCP); die Standardwerte von spring.datasource.hikari.*
stehen in application.properties.
1
2
3
4
5
6
7
8
9
10
11
# Eingebettete HSQLDB (Standard, für Tests und kleine Installationen):
spring.datasource.url=jdbc:hsqldb:file:${projectforge.base.dir}/database/projectforge;shutdown=true
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.datasource.username=sa
spring.datasource.password=
# PostgreSQL (empfohlen für den produktiven Einsatz):
#spring.datasource.url=jdbc:postgresql://localhost:5432/projectforge
#spring.datasource.driver-class-name=org.postgresql.Driver
#spring.datasource.username=projectforge
#spring.datasource.password=<your-password>
Das Schema wird bei jedem Start automatisch von Flyway angelegt und migriert.
2.2. Initialisierung, erste Anmeldung und Einrichtungsdialog
Nach dem ersten Start zeigt ProjectForge® die Einrichtungsseite. Dort wird das Ziel gewählt (leere Datenbank für ein Produktivsystem oder ein Testsystem mit Beispieldaten) und Benutzername sowie Passwort des Administrators festgelegt. Alle weiteren Einstellungen wie Zeitzone und E-Mail-Adressen lassen sich später unter Administration → Konfiguration ändern. Details stehen in Installation – The setup page.
2.3. SSL / Https
Es empfiehlt sich, ProjectForge auf einem lokalen http-Port zu betreiben und https über einen Reverse Proxy wie NGINX abzuwickeln, siehe Installation – Secure http connection.
Für Testzwecke lässt sich folgende Konfiguration verwenden:
2.3.1. Selbstsigniertes Zertifikat
Ein selbstsigniertes Zertifikat erzeugen: keytool -genkeypair -alias selfsigned -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 365
2.3.2. Die Datei ~/ProjectForge/projectforge.properties konfigurieren
1
2
3
4
5
6
# An alle Interfaces binden oder an localhost
server.address=0.0.0.0
server.port=8443
server.ssl.key-store=file:/home/projectforge/keystore.p12
server.ssl.key-store-password=<password of your certificate>
server.ssl.key-store-type=PKCS12
2.3.3. Dem selbstsignierten Zertifikat vertrauen
-
Exportieren:
keytool -exportcert -alias selfsigned -keystore keystore.p12 -storetype PKCS12 -file selfsigned.crt -rfc -
In den Zertifikatsspeicher des Systems oder des Browsers importieren und als vertrauenswürdig markieren.
2.4. PostgreSQL
2.4.1. Datenbank einrichten
Erforderlich ist PostgreSQL 13 oder neuer: Eine Datenbankmigration (Flyway V8.0.24) führt
CREATE EXTENSION IF NOT EXISTS pg_trgm für die Trigramm-Indizes der Änderungshistorien-Suche aus. Seit PostgreSQL 13
ist pg_trgm eine vertrauenswürdige (trusted) Extension, daher genügt es, wenn der Datenbankbenutzer von ProjectForge
das Recht CREATE auf der Datenbank hat (z. B. als deren Eigentümer, siehe unten). Andernfalls muss ein
Datenbankadministrator die Extension einmalig vorab anlegen:
psql -U postgres -d projectforge -c "CREATE EXTENSION IF NOT EXISTS pg_trgm;".
Die Dateien des Dateispeichers liegen in einem eigenen Schema pf_files, das ebenfalls von Flyway angelegt wird (der
Datenbankbenutzer braucht also auch das Recht, Schemata anzulegen, das der Eigentümer der Datenbank hat), siehe
Backup.
-
Benutzer anlegen (z. B. als Admin-Benutzer):
createuser -U postgres -P projectforge -
Datenbank anlegen:
createdb -U postgres -E UTF-8 -O projectforge projectforge -
Einen vorhandenen Benutzer und eine vorhandene Datenbank löscht man mit:
dropdb projectforgeunddropuser projectforge -
Um eine bestehende Datenbank weiterzuverwenden, wird ein Dump eingespielt, siehe Backup wiederherstellen.
Empfohlene Einstellungen in postgresql.conf (max_connections muss größer sein als der Connection-Pool von
ProjectForge, spring.datasource.hikari.maximum-pool-size, Standard 100). Nutzt das JCR ebenfalls noch PostgreSQL
(oak.datasource.url gesetzt), kommen durch dessen eigenen Pool bis zu 10 weitere Verbindungen hinzu
(oak.datasource.hikari.maximum-pool-size):
max_connections = 120 statement_timeout = 300000 # 300s lock_timeout = 300000 # 300s
3. Konfiguration
3.1. Basisverzeichnis (Home-Verzeichnis der Anwendung)
ProjectForge® benötigt ein Home-Verzeichnis, standardmäßig ${user.home}/ProjectForge (/ProjectForge innerhalb von
Docker). Es wird im Einrichtungsassistenten gewählt; wie ProjectForge es findet, steht in
Installation. Folgende Dateien und Verzeichnisse werden
angelegt, falls sie noch nicht existieren:
projectforge.properties, config.xml |
Konfigurationsdateien, vom Einrichtungsassistenten geschrieben. |
|---|---|
|
Die eingebettete Datenbank (HSQLDB), sofern verwendet. |
|
Die Suchindizes (Lucene). Sind sie beschädigt, ProjectForge stoppen, den Inhalt dieses Verzeichnisses löschen und die Indizes über Administration → System → Reindex neu aufbauen. |
|
Die Logdateien, z. B. |
|
Eigene Ressourcen, die die mitgelieferten überschreiben: |
|
Standardverzeichnis für Backups. |
|
Die Dateien der Datentransfer-Bereiche (Plugin Datentransfer). |
|
Das frühere Dokumenten-Repository (JCR), nur bei noch nicht migrierten Installationen, siehe Dateien aus dem JCR übernehmen. |
|
Arbeitsverzeichnis für temporäre Dateien. |
3.2. Konfigurationsdatei application.properties
ProjectForge® ist eine Spring-Boot-Anwendung, daher lassen sich alle
common application properties
in projectforge.properties verwenden. Alle ProjectForge-spezifischen Optionen mit ihren Standardwerten stehen in
application.properties.
3.3. Funktionen abschalten
Funktionen von ProjectForge lassen sich in projectforge.properties abschalten (wirksam nach einem Neustart). Eine
abgeschaltete Funktion hat keinen Menüeintrag, und ihre Seiten und REST-Dienste antworten mit 404, für alle.
# Allowlist: all (Standard) oder eine kommagetrennte Liste.
projectforge.features.enabled=all
# Denylist, gewinnt gegen die Allowlist.
projectforge.features.disabled=TIMESHEET_LIST,HR
Es gibt eine Funktion je Menüeintrag. Ihre Id ist die des Menüeintrags (ADDRESS_LIST, TIMESHEET_LIST,
FEEDBACK, MY_ACCOUNT, …, siehe MenuItemDefId), die des Menüeintrags eines Plugins (toDo,
DataTransferPersonalBox) oder die eines Plugins (datatransfer, marketing). Eine Hauptgruppe des Menüs
(COMMON, FIBU, HR, MISC, …) oder ein Plugin steht für alle seine Einträge. Nicht aktivierte Plugins sind
ebenfalls abgeschaltet, samt ihrer REST-Dienste. Unbekannte Ids werden beim Start als Warnung protokolliert.
Das ist kein Berechtigungssystem, die Zugriffsprüfungen der Funktionen bleiben, wie sie sind. Einige Dienste
bleiben auch bei abgeschalteter Funktion erreichbar, weil andere Seiten sie brauchen: die Suchen der Eingabefelder
(etwa nach Benutzern oder Aufgaben), das Abonnieren von Kalendern und der Kern der Anwendung (Anmeldung, Menü,
Einstellungen, Benachrichtigungen, Anhänge der übrigen Funktionen). Auch die Schnittstellen außerhalb der Seiten und
REST-Dienste werden nicht abgeschaltet: CardDAV (/carddav), der Export von Kalendern (/export/ProjectForge.ics)
und die SMS-Schnittstelle (/export/sms).
Die Sichtbarkeit von Menüs (projectforge.menu.visibility.*) ist etwas anderes: Sie blendet Menüeinträge nur für
Gruppen von Benutzern aus, die Funktionen bleiben erreichbar.
3.4. Anpassungen
3.4.1. Logo und Titel in PDF-Ausgaben
Unter Administration → Konfiguration wird der Name der Organisation eingetragen, der z. B. als Überschrift der PDF-Ausgaben dient.
Logos werden in projectforge.properties konfiguriert. Die Dateien müssen in resources/images des
Home-Verzeichnisses liegen (oder als absolute Pfade angegeben werden):
1
2
3
4
5
6
# Logo der Web-App:
projectforge.logoFile=logo.png
# Optionale Variante für den Dark Mode:
projectforge.logoFileDark=logo-dark.png
# Logo in Exporten:
projectforge.export.logoFile=logo-export.png
3.4.2. i18n-Übersetzungen anpassen
In ProjectForge lässt sich jeder Übersetzungstext der Benutzeroberfläche anpassen oder überschreiben. Das ist nützlich, um die Begriffe an die Bedürfnisse der eigenen Organisation anzupassen.
So werden Übersetzungen angepasst:
-
Eine oder mehrere Properties-Dateien im Verzeichnis
~/ProjectForge/resourcesanlegen:-
CustomerI18nResources.properties- für Standard-/englische Übersetzungen -
CustomerI18nResources_de.properties- für deutsche Übersetzungen -
CustomerI18nResources_en.properties- für englische Übersetzungen (explizit)
-
-
Eigene Schlüssel-Wert-Paare eintragen, um bestehende Übersetzungen zu überschreiben oder neue hinzuzufügen:
1 2 3 4
# Beispiel: bestehende Übersetzung überschreiben menu.addressList=Contacts # Beispiel: eigene Übersetzung hinzufügen myorganization.custom.greeting=Welcome to Acme Corp
-
ProjectForge neu starten, damit die Änderungen wirksam werden.
Die eigenen Übersetzungen haben Vorrang vor den in ProjectForge enthaltenen Standardübersetzungen.
Die verfügbaren i18n-Schlüssel, die sich überschreiben lassen, finden sich hier:
-
Übersetzungen der Hauptanwendung: I18nResources.properties
-
Übersetzungen der Plugins: im GitHub-Repository nach Dateien
*I18nResources.propertiesin den Plugin-Verzeichnissen suchen, z. B.:-
plugins/org.projectforge.plugins.banking/src/main/resources/BankingI18nResources.properties -
plugins/org.projectforge.plugins.skillmatrix/src/main/resources/SkillMatrixI18nResources.properties -
sowie weitere plugin-spezifische Übersetzungsdateien
-
3.5. Konfigurationseinstellungen (Weboberfläche)
Unter Administration → Konfiguration lassen sich weitere Parameter von ProjectForge® einstellen, etwa die Standardzeitzone, die Ländervorwahl oder die Kostenträgerrechnung. Jeder Parameter ist dort erläutert.
Administration → System bietet unter anderem: config.xml neu einlesen und exportieren, die 2FA-Konfiguration
exportieren, den Suchindex neu aufbauen und die Systemintegrität prüfen.
3.6. TTF-Schriften für die PDF-Render-Engine verwenden
Als interne Render-Engine für PDF-Ausgaben dient Apache FOP. Zusätzliche Schriften werden in resources/fonts des
Home-Verzeichnisses abgelegt (oder in dem mit projectforge.fontsDirectory konfigurierten Verzeichnis). Details zu
Schriften stehen in der FOP-Dokumentation.
3.7. HTML-formatierte E-Mail-Vorlagen
ProjectForge erzeugt E-Mails (z. B. Benachrichtigungen) mit Groovy-Vorlagen. Die mitgelieferten Vorlagen liegen in
den Quellen unter
projectforge-business/src/main/resources/mail.
Um eine Vorlage anzupassen, wird sie unter demselben relativen Pfad in das Ressourcenverzeichnis des
Home-Verzeichnisses kopiert, z. B. ~/ProjectForge/resources/mail/orderChangeNotification.html, und dort bearbeitet.
ProjectForge sucht zuerst dort und greift auf die mitgelieferte Vorlage zurück, wenn die Datei nicht existiert.
Die Vorlagen werden mit der Sprache (Locale) des empfangenden Benutzers internationalisiert.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<html>
#INCLUDE{mail/mailHead.html}
<body>
#INCLUDE{mail/mailOpening.html}
<br />
Hier kann Inhalt platziert werden (für internationalisierte E-Mails i18n-Schlüssel verwenden).
...
<br />
<%= pf.getString("link") %>: <a href="${requestUrl}">${requestUrl}</a>
<br />
Ein Beispiel für dynamische Daten (hier wird eine Liste von Positionen ausgegeben):
<table>
<% for (position in order.positions) { %>
<tr>
<th><%= pf.getString("title") %></th>
<td>${position.title}</td>
...
</tr>
<% } %>
</table>
#INCLUDE{mail/mailHistoryTable.html}
#INCLUDE{mail/mailClosing.html}
#INCLUDE{mail/mailFooter.html}
</body>
</html>
3.8. E-Mails versenden
ProjectForge versendet Benachrichtigungen, Mails zum Zurücksetzen des Passworts, 2FA-Codes und den Fehler-Digest per SMTP:
1
2
3
4
5
6
7
8
9
mail.session.pfmailsession.emailEnabled=true
mail.session.pfmailsession.standardEmailSender=projectforge@acme.com
# Plain, StartTLS oder SSL:
mail.session.pfmailsession.encryption=StartTLS
mail.session.pfmailsession.smtp.host=mail.acme.com
mail.session.pfmailsession.smtp.port=587
mail.session.pfmailsession.smtp.auth=true
mail.session.pfmailsession.smtp.user=projectforge
mail.session.pfmailsession.smtp.password=<password>
3.9. Fehler-Digest für den Support
Ist eine Support-Adresse konfiguriert (projectforge.support.mail) und der Mailversand eingerichtet, sammelt
ProjectForge die Fehler eines Zeitraums und schickt sie pro Intervall als eine Digest-Mail an diese Adresse. Für einen
Zeitraum ohne Fehler wird nichts versendet. Der Digest sammelt:
-
unerwartete Fehler in Anfragen angemeldeter Benutzer (keine Bedienfehler wie Validierungs- oder Zugriffsfehler),
-
geloggte Fehler (Level ERROR),
-
nicht erreichbare externe Systeme (LDAP, IdP, Gateway, SMS-/Telefondienste, SMTP, …), erkannt an Verbindungsfehlern und Timeouts, auch aus Warnungen,
-
Synchronisationsläufe, die seit dem letzten Digest fehlgeschlagen, abgebrochen oder in einen Timeout gelaufen sind.
Gleiche Fehler (die sich nur in IDs, Zahlen oder zitierten Werten wie einem Benutzernamen unterscheiden) werden zusammengefasst. Gruppiert eine neue Version sie gröber, werden die zuvor erfassten Probleme kurz nach dem Start zusammengeführt (Anzahlen summiert, der Status der Administration bleibt erhalten, wenn er übereinstimmt, sonst neu). Die Mail listet zuerst neue Probleme, Regressionen (Probleme, die nach ihrer Behebung erneut aufgetreten sind) und Spitzen (deutlich häufiger als in den letzten 7 Tagen), danach die 30 häufigsten bekannten Probleme nach Schweregrad (nicht erreichbare externe Systeme zuerst). Jedes Problem verlinkt auf das System-Dashboard (Administration), wo es bestätigt, als behoben markiert, ignoriert oder stummgeschaltet werden kann; ignorierte und stummgeschaltete Probleme werden nur gezählt. Die angehängte Textdatei enthält pro Gruppe bis zu fünf einzelne Vorkommen mit Benutzer, Anfrage und Stacktrace.
Für eine Analyse oder Klassifizierung mit einer KI (oder einem anderen Werkzeug) hängt der Digest zusätzlich alles als
JSON-Datei an (format: projectforge-log-analysis), und das System-Dashboard lädt alle Probleme seines aktuellen
Filters im selben Format herunter (Als JSON herunterladen), mit Beispielmeldung, Stacktrace und den Vorkommen der
letzten 30 Tage. Die Datei erklärt ihre Felder und Werte selbst (guide) und kann daher unverändert weitergegeben
werden. Sie enthält keine Benutzernamen, Meldungen und Anfragen sind aber so wie geloggt enthalten und können
personenbezogene Daten enthalten: Das ist vor der Weitergabe an einen externen Dienst zu prüfen.
Ein neues Sicherheits- oder Datenproblem (oder eines, das nach seiner Behebung erneut aufgetreten ist) wartet nicht auf das Ende des Intervalls: Es löst den Digest vorzeitig aus, sobald es seinen Schwellwert erreicht, höchstens jedoch alle 5 Minuten.
Jedes Problem geht an die Empfänger seiner Zielgruppe: Entwicklung (Bugs, Datenprobleme), Administration (externe
Systeme, Konfiguration, Synchronisationsläufe) oder Sicherheit. Hat eine Zielgruppe keine eigenen Empfänger, erhält
projectforge.support.mail ihren Digest.
Datei: projectforge.properties:
projectforge.support.mail=support@acme.com # Wie oft der Digest höchstens versendet wird, z. B. 15m, 1h, 1d. 0 deaktiviert den Digest. Standard: 1h projectforge.support.errorDigest.interval=1h # Optional, kommagetrennt, Standard: projectforge.support.mail projectforge.support.errorDigest.recipients.developer=dev@acme.com projectforge.support.errorDigest.recipients.admin=ops@acme.com projectforge.support.errorDigest.recipients.security=security@acme.com
3.10. System-Dashboard und Log-Viewer
Administratoren finden das System-Dashboard im Menü Administration. Es zeigt die für den Fehler-Digest gesammelten
Probleme (siehe oben) und die Läufe der geplanten Jobs und bietet einen Log-Viewer zum Durchsuchen der Logdateien,
einschließlich des Kontexts eines Logeintrags. Die Zählerstände werden in der Datenbank gespeichert
(projectforge.support.logAggregation. und projectforge.scheduler.stats. in application.properties, bereinigt
durch den täglichen Datenschutz-Job).
3.11. Telefonieren und SMS mit ProjectForge
3.11.1. Telefonieren
Ist es konfiguriert, können Benutzer Anrufe direkt starten, indem sie auf eine Telefonnummer einer Adresse klicken oder auf der Seite Direktwahl einen Namen oder eine Telefonnummer eingeben. Die Anrufe werden über Sipgate aufgebaut:
1
2
3
4
5
6
projectforge.sipgate.baseUri=<base uri of the Sipgate REST API>
projectforge.sipgate.tokenId=<token id>
projectforge.sipgate.token=<token>
# Gerät für Anrufe, falls der Benutzer keine eigenen Sipgate-Geräte konfiguriert hat (z. B. "p2"):
projectforge.sipgate.defaultDevice=
projectforge.sipgate.basePhoneNumber=
Abbildung 1: |
Ein Anruf lässt sich einfach durch einen Klick auf eine Telefonnummer einer Adresse starten oder durch Eingabe eines Namens oder einer Nummer in das Nummernfeld. |
Nicht vergessen: Die Standard-Ländervorwahl wird unter Administration → Konfiguration eingestellt.
3.11.2. SMS
Ist ein SMS-Gateway konfiguriert, können Benutzer Textnachrichten versenden, indem sie auf das SMS-Symbol einer
Adresse klicken oder einen Namen bzw. eine Mobilfunknummer eingeben. ProjectForge ruft das Gateway per http auf;
#number und #message werden durch die Eingaben des Benutzers ersetzt. Die Textnachrichten dienen, sofern
konfiguriert, auch als zweiter Faktor (2FA).
1
2
3
4
5
6
7
projectforge.sms.url=https://smsgateway.acme.com/api.php
# GET (Standard) oder POST:
projectforge.sms.httpMethod=GET
projectforge.sms.httpParameters={username:'projectforge',text:'#message',to:'#number'}
# Muster der Gateway-Antwort:
projectforge.sms.returnCodePattern.success=^OK.*
projectforge.sms.returnCodePattern.error=^Error.*
Abbildung 2: |
Textnachrichten lassen sich einfach durch einen Klick auf das SMS-Symbol einer Adresse versenden oder durch Eingabe eines Namens oder einer Mobilfunknummer. |
Alle Optionen stehen in application.properties (projectforge.sms.*).
3.11.3. Rufnummernsuche
Über den Dienst zur Rufnummernsuche kann eine Telefonanlage (z. B. Asterisk) den Anrufer eingehender Anrufe ermitteln:
projectforge.acme.com/rsPublic/phoneLookup?nr=<number>&key=<key>. Falsche Schlüssel werden wie
fehlgeschlagene Anmeldungen verzögert.
Der Dienst ist deaktiviert, solange kein Schlüssel konfiguriert ist (Standard: leer). Zum Aktivieren wird ein eigener,
langer, zufälliger geheimer Schlüssel in projectforge.properties gesetzt (z. B. erzeugt mit openssl rand -hex 32):
1
projectforge.phoneLookupKey=<your-random-secret>
3.12. Nummernkreise von Kunden, Projekten und Kostenträgern
Kunden und Projekte haben eigene Nummern, jedes Projekt eine systemweit eindeutige Projektnummer. Nummernkreise legen
fest, welche Kunden- und Projektnummern zusammengehören und wie die Kostenträger (Kost2) eines Projekts aus seiner
Nummer abgeleitet werden. Sie werden in projectforge.properties konfiguriert (projectforge.fibu.number-ranges.*).
Wird keine Kostenträgerrechnung genutzt oder werden keine Kost2 von Projekten benötigt, ist keine Konfiguration nötig:
Kunden- und Projektnummern sind dann frei.
3.12.1. Welche Nummernkreise gelten
Beim Start loggt ProjectForge, welche Nummernkreise gelten (Number ranges: mode …):
| Modus | Gilt, wenn |
|---|---|
|
Mindestens ein Nummernkreis konfiguriert ist. Es gelten nur die konfigurierten Nummernkreise. |
|
Kein Nummernkreis konfiguriert ist, aber Kost2 von Projekten in den früher fest eingebauten Nummernkreisen
existieren: 4 für interne Projekte ( |
|
Sonst (z. B. bei einer neuen Installation). Kunden- und Projektnummern sind frei, Projekte erhalten keine Kost2. Kost2 ohne Projekt lassen sich weiterhin anlegen. |
Erhält eine Installation im Modus LEGACY ihren ersten konfigurierten Nummernkreis, gelten nur noch die
konfigurierten Nummernkreise. Dann müssen auch die früheren Nummernkreise 4 und 5 konfiguriert werden (siehe Beispiel
unten).
|
3.12.2. Einstellungen
Jeder Nummernkreis ist ein Listeneintrag projectforge.fibu.number-ranges.ranges[n].<property>:
| Eigenschaft | Standard | Beschreibung |
|---|---|---|
|
Erste Ziffer (1-9) der Projekt- und Kost2-Nummern dieses Nummernkreises, eindeutig über alle Nummernkreise. |
|
|
Anzeigename, z. B. |
|
|
Kleinste und größte Kundennummer dieses Nummernkreises; beide oder keine angeben. Ein
Nummernkreis ohne Kunden ist für Projekte ohne Kunden gedacht (z. B. interne Projekte); sein |
|
|
2 |
Anzahl der Stellen der Projektnummer je Kunde (1-5) bzw. des gesamten Nummernkreises bei einem Nummernkreis ohne Kunden. |
|
|
Segmente der 8-stelligen Kost2 für Anzeige und Eingabe, z. B. |
Globale Einstellungen:
| Eigenschaft | Standard | Beschreibung |
|---|---|---|
|
|
Bei |
|
|
Segmente der Kost2, deren erste Ziffer zu keinem Nummernkreis gehört (Kost2 ohne Projekt). |
3.12.3. Projekt- und Kost2-Nummern
Ein Projekt eines Nummernkreises erhält eine 6-stellige Projektnummer, seine Kost2 sind diese Nummer gefolgt von der 2-stelligen Kost2-Art:
project number = prefix * 100000 + (customer mod 10^(5 - project-digits)) * 10^project-digits + project project number = prefix * 100000 + project (range without customers) Kost2 = project number * 100 + Kost2 type
Die Kundennummer selbst ist Teil der Projektnummer: ihre letzten 5 - project-digits Stellen, unabhängig von
customer-min. Beispiel: Nummernkreis 1 mit den Kunden 10000-19999 (oder 10001-19999), 1 Projektstelle und den
Segmenten 1,4,1,2. Projekt 3 des Kunden 10007 hat die Projektnummer 100073 (angezeigt als 1.0007.3), seine Kost2 der
Art 02 ist 1.0007.3.02. Kunde 123 des Nummernkreises 5 (Kunden 0-999, 2 Projektstellen) erhält 5.123.xx.
Alle Kunden eines Nummernkreises müssen daher die Stellen vor diesen letzten Stellen gemeinsam haben: Ein Nummernkreis mit 2 Projektstellen umfasst höchstens die 1000 Kunden eines Blocks wie 0-999 (100 Projekte je Kunde), einer mit 1 Projektstelle höchstens die 10000 Kunden eines Blocks wie 10000-19999.
Datei: projectforge.properties:
# Früherer Nummernkreis 4: interne Projekte 4.###.##.##
projectforge.fibu.number-ranges.ranges[0].prefix=4
projectforge.fibu.number-ranges.ranges[0].name=Intern
projectforge.fibu.number-ranges.ranges[0].project-digits=5
# Früherer Nummernkreis 5: Kunden 0-999 mit jeweils bis zu 100 Projekten, 5.###.##.##
projectforge.fibu.number-ranges.ranges[1].prefix=5
projectforge.fibu.number-ranges.ranges[1].customer-min=0
projectforge.fibu.number-ranges.ranges[1].customer-max=999
projectforge.fibu.number-ranges.ranges[1].project-digits=2
# Kunden 10000-19999 mit jeweils bis zu 10 Projekten, 1.####.#.##
projectforge.fibu.number-ranges.ranges[2].prefix=1
projectforge.fibu.number-ranges.ranges[2].customer-min=10000
projectforge.fibu.number-ranges.ranges[2].customer-max=19999
projectforge.fibu.number-ranges.ranges[2].project-digits=1
projectforge.fibu.number-ranges.ranges[2].segments=1,4,1,2
# Optional: Kundennummern außerhalb dieser Nummernkreise ablehnen
projectforge.fibu.number-ranges.allow-free-numbers=false
3.12.4. Hinweise
-
Eine inkonsistente Konfiguration (Präfix doppelt vergeben, überlappende Kundennummern, zu viele Kunden für die Projektstellen, ungültige Segmente) bricht den Start mit einer Meldung ab, die den Nummernkreis nennt.
-
Neuen Kunden und Projekten wird die nächste freie Nummer ihres Nummernkreises vorgeschlagen.
-
Ein Projekt, dessen Kunde zu keinem Nummernkreis gehört, erhält eine freie Projektnummer, die nicht im Projektnummernbereich eines Nummernkreises liegen darf (z. B. 100000-199999 für Präfix 1). Solche Projekte und Projekte im Modus
FREEkönnen keine Kost2 erhalten. -
Kost2 ohne Projekt dürfen nicht mit dem Präfix eines Nummernkreises beginnen: Die Kost2 eines Nummernkreises sind die seiner Projekte.
-
Gespeicherte Projekt- und Kost2-Nummern werden nicht umnummeriert, wenn ein Nummernkreis später geändert wird. Bestehende Kost2 bleiben gültig, auch wenn ihr Nummernkreis nicht mehr konfiguriert ist; neue Nummernkreise (Kundennummern und Projektstellen) sollten trotzdem vor ihrer Verwendung geplant werden.
-
Fakturierungsquote (
projectforge.invoicing-quota.): Die Muster beziehen sich auf die Kost2-Nummern in der Segmentierung ihres Nummernkreises (z. B.1.für1.#..). Mitprojectforge.invoicing-quota.billed-by-invoiced-kost2-types=truezählt die auf Kost2 von Kundenprojekten mit einer fakturierten Kost2-Art gebuchte Zeit als abgerechnet, unabhängig von den Ziffern.
3.13. Nomenklatur der Gruppen
Der Konfigurationsparameter Nomenklatur der Gruppen (groupNomenclature, Kategorie Finanzen) beschreibt, wie
Gruppen benannt werden. Er ist eine Beschreibung, keine Regel: Projekt- und Strukturelement-Assistent schlagen die
Namen neuer Gruppen danach vor, und die Beschreibung wird am Namen einer Gruppe und in den Assistenten angezeigt;
geprüft wird kein Name.
-
Beschreibung: Rich Text, der die Konvention erläutert.
-
Muster des Basisnamens der Gruppen eines Projekts, mit den Platzhaltern
{customer.identifier},{customer.name},{customer.number},{project.identifier},{project.name}und{project.number}. Ein leerer Kurzbezeichner wird durch den Namen ersetzt. Leer: der Name des Projekts. -
Endungen der Gruppen für Management, Team und Externe, mit Bindestrich angehängt. Leer: die Vorgabe des Assistenten (
pm, keine,extern). -
Groß-/Kleinschreibung des ganzen vorgeschlagenen Namens: unverändert, klein oder groß.
Beispiel: Muster {customer.identifier}-{project.identifier}, Endungen pm und extern, Kleinschreibung ergeben
acme-portal-pm, acme-portal und acme-portal-extern. Der Strukturelement-Assistent nimmt das Muster, wenn das
gewählte Element zu einem Projekt gehört, sonst den Titel des Elements.
3.14. Betriebswirtschaftliche Auswertung / BWA
Wer mit Buchungssätzen (DATEV) arbeitet, möchte vermutlich auch betriebswirtschaftliche Auswertungen (BWA) nutzen.
Sie werden in config.xml konfiguriert (Element businessAssessment). Die betriebswirtschaftlichen Auswertungen von
DATEV bestehen aus Zeilen. Jede Zeile hat eine Zeilennummer (no) und einen Titel (für die Anzeige). Der
accountRange legt fest, welche DATEV-Konten zur Zeile gehören. Ein Buchungssatz wird dabei der ersten passenden
Zeile zugeordnet.
Ist die Priorität einer Zeile nicht hoch, wird die Zeile in der Kurzform der betriebswirtschaftlichen Auswertung
nicht angezeigt. Der Wert definiert berechnete Zeilenbeträge (siehe das Beispiel in der vom Einrichtungsassistenten
angelegten config.xml).
3.15. Sicherheitskonfiguration
3.15.1. Sichere Passwörter
Passwörter werden nie im Klartext gespeichert: Jedes Passwort wird zusammen mit einem zufälligen Salt pro Benutzer und einem Pepper (siehe unten) gehasht. Die Mindestlänge von Passwörtern wird unter Administration → Konfiguration eingestellt.
3.15.2. Schutz vor Brute-Force-Angriffen
Schlägt eine Anmeldung fehl (über die Anmeldeseite oder einen REST-Dienst), wird für den Benutzernamen und für die
IP-Adresse des Clients eine Strafzeit gesetzt. Mit jeder weiteren fehlgeschlagenen Anmeldung wächst die Strafzeit,
und während der Strafzeit wird kein neuer Versuch angenommen. Die Strafzeit für IP-Adressen wächst deutlich langsamer,
damit viele Benutzer hinter demselben NAT nicht ausgesperrt werden. Details stehen im Quellcode (LoginProtection).
Die IP-Adresse des Clients wird nur bei Anfragen von einem vertrauenswürdigen Proxy aus X-Forwarded-For übernommen
(projectforge.security.trustedProxies, Standard: localhost und die privaten Netze).
3.15.3. Gesalzene Passwörter mit Pepper
Ein Pepper-String wird in projectforge.properties konfiguriert; der Einrichtungsassistent erzeugt einen zufälligen.
Vor dem Hashen eines Passworts wird der Pepper mit dem Salt und dem Passwort verkettet, sodass ein Datenbank-Dump allein
für einen Brute-Force-Angriff nicht ausreicht.
1
projectforge.security.passwordPepper=*******SECRET********
Dieser Wert muss sicher aufbewahrt werden: Geht der Pepper verloren oder wird er geändert, kann sich kein Benutzer mehr
anmelden, dessen Passwort mit dem früheren Pepper gehasht wurde. Dasselbe gilt für
projectforge.security.authenticationTokenEncryptionKey, mit dem die Authentifizierungs-Tokens der Benutzer
verschlüsselt werden (eine Änderung macht nur die Tokens ungültig, nicht die Passwörter).
3.15.4. 2FA (Zwei-Faktor-Authentifizierung)
2FA (Zwei-Faktor-Authentifizierung) wird unterstützt durch:
-
Authenticator-Apps (TOTP, RFC 6238), z. B. Google oder Microsoft Authenticator,
-
WebAuthn/FIDO2 (Sicherheitsschlüssel wie YubiKey),
-
per E-Mail oder Textnachricht (SMS, sofern konfiguriert) gesendete Codes.
Jeder Benutzer richtet seine zweiten Faktoren unter Mein Zugang ein.
Für welche URLs ein zweiter Faktor erforderlich ist und wie lange eine erfolgreiche 2FA gültig bleibt, wird über Kürzel für vordefinierte Mengen von URI-Matchern und/oder eigene reguläre Ausdrücke festgelegt. Ein Webfilter prüft bei jeder Anfrage, ob eine 2FA erforderlich ist und ob die letzte erfolgreiche 2FA der aktuellen Session älter als die festgelegte Gültigkeitsdauer ist. Der Zeitpunkt einer erfolgreichen 2FA wird sowohl in der Session des Benutzers als auch in seiner Angemeldet-bleiben-Session gespeichert.
Empfohlene Beispielkonfiguration:
Datei: projectforge.properties:
1
2
3
4
5
6
7
8
9
10
11
projectforge.2fa.expiryPeriod.minutes1=
projectforge.2fa.expiryPeriod.minutes10=PASSWORD
projectforge.2fa.expiryPeriod.hours1=ADMIN_WRITE;MY_ACCOUNT
projectforge.2fa.expiryPeriod.hours8=ADMIN;SCRIPT_WRITE;FINANCE_WRITE;ORGA_WRITE;HR_WRITE
projectforge.2fa.expiryPeriod.days30=HR;FINANCE;ORGA;SCRIPT
projectforge.2fa.expiryPeriod.days90=
# Anzahl der Tage, nach denen eine 2FA erforderlich ist, wenn "angemeldet bleiben" genutzt wird. Ohne "angemeldet
# bleiben" und wenn gesetzt, ist nach jeder Anmeldung eine 2FA erforderlich.
projectforge.2fa.loginExpiryDays=30
# Optional: keine E-Mail als zweiter Faktor für Mitglieder dieser Gruppen (kommagetrennt):
projectforge.2fa.disableMail2FAForGroups=PF_Admin
Regeln
-
Ein Ausdruck, der mit
/beginnt, ist ein absoluter Pfad der URI und wird als Präfix verglichen:/rs/user→^/rs/user.*, es passt also jede URI, die mit/rs/userbeginnt. -
Leere Einträge bedeuten: kein zweiter Faktor.
-
Reguläre Ausdrücke und Kürzel werden durch
;getrennt. -
Unterstützte Kürzel sind
ALL,ADMIN,ADMIN_WRITE,FINANCE,FINANCE_WRITE,HR,HR_WRITE,ORGA,ORGA_WRITE,SCRIPT,SCRIPT_WRITE,MY_ACCOUNTundPASSWORD; jedes umfasst eine Reihe regulärer Ausdrücke. -
Mit
WRITE:<entity-name>lassen sich nur die schreibenden Aufrufe einer Entität (REST-Aufrufe) angeben. Das Lesen von Entitäten bzw. die Detailansicht ist davon nicht betroffen. Für alle Aktivitäten einer Entität wird stattdessen/rs/<entity-name>verwendet. -
Eigene Ausdrücke sind ebenfalls möglich, z. B.:
ADMIN;/rs/report;WRITE:user -
Passt eine URI zu mehreren Zeiträumen, gilt der kürzeste.
-
Das frühere Wicket-Frontend (
/wa/…) gibt es nicht mehr; seine URLs werden nur noch in das neue Frontend umgeleitet, Ausdrücke mit/wa/schützen also nichts mehr. Sie sind durch die/rs/…-Pfade der Entitäten zu ersetzen.
Zur Überprüfung der Konfiguration dient Administration → System → Export 2FA configuration.
3.16. LDAP
3.16.1. Voraussetzungen
Das LDAP muss die folgenden zusätzlichen Schemata unterstützen (Beispiel aus der slapd.conf von OpenLDAP):
1
2
include /etc/openldap/schema/cosine.schema
include /etc/openldap/schema/inetorgperson.schema
3.16.2. Konfiguration
Die Einstellung groupBase wird nur im Master-Modus benötigt. Der managerUser wird im einfachen Slave-Modus nicht benötigt. Weitere Informationen folgen unten.
Datei: projectforge.properties:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
...
projectforge.ldap.server=
projectforge.ldap.baseDN=
projectforge.ldap.managerUser=
projectforge.ldap.managerPassword=
projectforge.ldap.port=
projectforge.ldap.sslCertificateFile=
projectforge.ldap.groupBase=
projectforge.ldap.userBase=
projectforge.ldap.authentication=
projectforge.ldap.posixAccountsDefaultGidNumber=
projectforge.ldap.sambaAccountsSIDPrefix=
projectforge.ldap.sambaAccountsPrimaryGroupSID=
...
3.16.3. Lokale (Admin-)Benutzer
Zunächst als Administrator mit der Option „Angemeldet bleiben“ der Anmeldeseite anmelden (noch ohne konfiguriertes LDAP). Dann ProjectForge mit konfiguriertem LDAP neu starten und denselben Browser verwenden: Die Anmeldung sollte bestehen bleiben. Jetzt jeden Benutzer bearbeiten, der gegen ProjectForge (statt gegen LDAP) authentifiziert werden soll, die Option Lokale:r Benutzer:in aktivieren und speichern. Danach können sich die lokalen Benutzer ohne LDAP-Zugangsdaten anmelden. Das ist besonders für Administratoren von ProjectForge nützlich.
3.16.4. LDAP über SSL
openssl s_client -showcerts -connect ldap.acme.priv:636 > ldap.pem Die Zeilen
von -----BEGIN CERTIFICATE----- bis einschließlich -----END CERTIFICATE-----
in eine Datei namens ldap.cert. kopieren. Anschließend lässt sich die Zertifikatsdatei
in projectforge.properties konfigurieren oder das Zertifikat in den Java-Keystore
importieren. Die erste Variante ist unabhängig von der Java-Version
und wird bevorzugt empfohlen.
3.16.5. ProjectForge als LDAP-Master
Der LDAP-Master-Modus ist der am besten getestete LDAP-Modus von ProjectForge und wird von uns produktiv eingesetzt. In diesem Modus benötigt ProjectForge einen LDAP-Benutzer mit Schreibzugriff auf Gruppen und Benutzer. Die Benutzer von ProjectForge werden ins LDAP synchronisiert. Bei Konflikten zwischen LDAP und ProjectForge gelten die Einstellungen von ProjectForge. Die Konfiguration dieses Modus ist einfach:
Datei: projectforge.properties:
1
2
3
...
projectforge.login.handlerClass=LdapMasterLoginHandler
...
-
Dieser LDAP-Login-Handler hat Lese- und Schreibzugriff auf den LDAP-Server und ist Master der Benutzer- und Gruppendaten. Alle Änderungen an Benutzern und Gruppen in ProjectForge werden durchgeschrieben.
-
Änderungen auf dem LDAP-Server werden ignoriert und können von ProjectForge überschrieben werden.
-
Passwörter
Nach jeder erfolgreichen Anmeldung bei ProjectForge (über die Anmeldeseite) versucht ProjectForge, den Benutzer mit den angegebenen Zugangsdaten (Benutzername/Passwort) am LDAP zu authentifizieren. Schlägt die LDAP-Authentifizierung fehl, setzt ProjectForge das Passwort auf das aktuelle Passwort des Benutzers (auf der Anmeldeseite eingegeben). Ändert der Benutzer sein Passwort (Passwort ändern), wird das LDAP-Passwort entsprechend geändert. Im LDAP-Master-Modus kann der Benutzer außerdem sein „WLAN/Samba-Passwort“ ändern (WLAN/Samba Passwort ändern). Das dort eingegebene Passwort wird in das LDAP-Attribut „sambaNTPassword“ geschrieben. -
Deaktivierte Benutzer
Deaktivierte Benutzer werden in eine Unter-Userbase namens „deactivated“ verschoben. Die E-Mail-Adresse wird ungültig gemacht und das Passwort gelöscht. Gelöschte und deaktivierte Benutzer werden aus allen LDAP-Gruppen entfernt. Nach der Reaktivierung wird das Passwort wieder gesetzt, sobald sich der Benutzer das nächste Mal über die Anmeldeseite anmeldet. -
Gelöschte Benutzer
Gelöschte Benutzer werden nicht synchronisiert und, falls vorhanden, im LDAP entfernt. -
Neue Benutzer
Neue Benutzer (auf der Benutzer-Bearbeitungsseite von ProjectForge angelegt) werden zunächst ohne Passwort, aber mit „WLAN/Samba-Passwort“ direkt im LDAP-System angelegt. Solche Benutzer müssen sich zuerst bei ProjectForge anmelden, sonst ist ihr LDAP-Passwort nicht gesetzt (eine Anmeldung an anderen Systemen, die an das LDAP angebunden sind, ist bis zur ersten Anmeldung bei ProjectForge nicht möglich). -
Felder im LDAP ändern
ProjectForge ändert nur unterstützte Felder bekannter LDAP-Benutzer. Werden im LDAP Felder von Benutzern/Gruppen geändert, die ProjectForge bekannt sind, überschreibt ProjectForge sie beim nächsten Synchronisationslauf. Änderungen an anderen Feldern von LDAP-Benutzern lässt ProjectForge unangetastet. -
Synchronisation
Nach jeder Änderung eines Benutzers oder einer Gruppe in ProjectForge wird die Synchronisation für alle LDAP-Benutzer und -Gruppen gestartet. Ohne Änderungen erfolgt die Synchronisation etwa stündlich, aber nur, wenn in ProjectForge Benutzeraktivität erkannt wird. Eine Synchronisation lässt sich durch einen Neustart von ProjectForge erzwingen. -
Gruppen und zugeordnete Benutzer
Benutzer werden alsuniqueMember-Einträge in die LDAP-Gruppen aufgenommen, wenn sie auch in ProjectForge derselben ProjectForge-Gruppe zugeordnet sind.
LDAP-Einträge
Die Abbildungen 3 und 4 zeigen im Detail, wie ProjectForge LDAP-Felder und Objektklassen speichert und erwartet.
Abbildung 3: |
ProjectForge verwendet für Benutzer die in dieser Abbildung
gezeigten Felder und Objektklassen. Die Objektklasse |
Abbildung 4: |
ProjectForge verwendet für Gruppen die in dieser Abbildung
gezeigten Felder und Objektklassen. Das Feld |
POSIX-Accounts verwalten
ProjectForge unterstützt die Verwaltung von POSIX-Accounts mit den
Daten uidNumber, gidNumber, homeDirectory, und loginShell.
Die POSIX-Account-Daten lassen sich auf der Benutzer-Bearbeitungsseite pflegen, nachdem
projectforge.properties wie im obigen Beispiel konfiguriert wurde.
Weitere Informationen stehen in den Tooltips:
Abbildung 5: |
ProjectForge kann im LDAP-Master-Modus POSIX-Accounts im LDAP verwalten. |
-
Nach einem Klick auf den Button
createneben dem Feld UID-Nummer befüllt ProjectForge alle POSIX-Account-Felder vor:-
Die UID-Nummer wird die nächste freie Nummer (ProjectForge sucht die höchste vergebene UID und erhöht sie um eins). Wird keine solche Nummer gefunden, wird 1.000 angenommen.
-
Die GID-Nummer wird mit
projectforge.ldap.posixAccountsDefaultGidNumberausprojectforge.propertiesvorbelegt. -
Das Home-Verzeichnis ist das Präfix
/home/gefolgt vom Benutzernamen, z. B./home/jdoe(nicht konfigurierbar). -
Die Login-Shell wird mit
/bin/bashvorbelegt (nicht konfigurierbar).Nicht vergessen, den Benutzer zu speichern. Nach einer Änderung dieser POSIX-Account-Felder werden die LDAP-Einträge sofort aktualisiert.
-
-
ProjectForge belegt eine neue UID-Nummer automatisch vor (siehe oben).
-
ProjectForge stellt sicher, dass keine UID-Nummer doppelt vergeben wird.
-
Ein LDAP-Eintrag erhält die
object-classposixAccountnur, wenn für diesen Benutzer in ProjectForge POSIX-Account-Daten angelegt wurden.
3.16.6. Samba-Accounts verwalten
Datei: projectforge.properties:
1
2
3
4
...
projectforge.ldap.sambaAccountsSIDPrefix=
projectforge.ldap.sambaAccountsPrimaryGroupSID=
...
Abbildung 6: |
ProjectForge kann im LDAP-Master-Modus POSIX- und Samba-Accounts verwalten. |
-
Nach einem Klick auf den Button
createneben dem Feld UID-Nummer befüllt ProjectForge alle SAMBA-Account-Felder vor:-
Die UID-Nummer wird die nächste freie Nummer (ProjectForge sucht die höchste vergebene UID und erhöht sie um eins). Wird keine solche Nummer gefunden, wird 1.000 angenommen.
-
Die GID-Nummer wird mit der in
projectforge.propertieskonfigurierten defaultSambaPrimaryGroupSID vorbelegt. -
Parallele Nutzung mit POSIX, die empfohlen wird:
Den Button 'create' neben der UID des POSIX-Accounts anklicken; das Suffix der SAMBASID ist dann dieselbe UID. ProjectForge versucht zuerst, für SAMBA dieselbe UID wie für POSIX zu verwenden, sofern kein Konflikt besteht.Nicht vergessen, den Benutzer zu speichern. Nach einer Änderung dieser Samba-Account-Felder werden die LDAP-Einträge sofort aktualisiert.
-
-
Ein LDAP-Eintrag erhält die
object-classsambaSamAccountnur, wenn für diesen Benutzer in ProjectForge Samba-Account-Daten angelegt wurden.
3.16.7. ProjectForge als LDAP-Client
Dieser LDAP-Login-Handler arbeitet als LDAP-Slave, d. h. auf das LDAP wird
nur lesend zugegriffen. Es gibt 3 Modi:
simple, users und users-groups. Die Konfiguration
dieses Modus ist einfach:
Datei: projectforge.properties:
1
2
3
...
projectforge.login.handlerClass=LdapSlaveLoginHandler
...
Einfacher Modus
Der einfache Modus gilt, wenn in projectforge.properties kein LDAP-managerUser
angegeben ist.
-
Einfach bedeutet, dass nur Benutzername und Passwort geprüft werden; alle anderen Benutzereinstellungen wie zugeordnete Gruppen, Name usw. werden von ProjectForge verwaltet.
-
Für den Zugriff auf Benutzer oder Gruppen des LDAP ist kein LDAP-Benutzer nötig; nur Login-Name und Passwort des Benutzers werden durch einen Authentifizierungsversuch geprüft!
-
Wird ein Benutzer im LDAP deaktiviert, kann er unbegrenzt mit ProjectForge weiterarbeiten, solange er die Funktion „Angemeldet bleiben“ nutzt! (Ist das nicht akzeptabel, stattdessen den normalen Benutzermodus verwenden.)
-
Für lokale Benutzer werden alle LDAP-Einstellungen ignoriert.
Benutzermodus
Der normale Benutzermodus gilt, wenn in projectforge.properties ein LDAP-managerUser
angegeben ist.
-
Normal bedeutet, dass Benutzername und Passwort geprüft und alle anderen Benutzereinstellungen wie der Name usw. über einen angegebenen LDAP-Manager-Benutzer gelesen werden.
-
Wird ein Benutzer im LDAP gelöscht, wird er auch in der Datenbank von ProjectForge als gelöscht markiert. Nach der Synchronisation ist keine Anmeldung mehr möglich (auch „Angemeldet bleiben“ schlägt für gelöschte Benutzer fehl).
-
Für lokale Benutzer werden alle LDAP-Einstellungen ignoriert.
-
Alle bekannten LDAP-Benutzerfelder werden synchronisiert (Vorname, Nachname, E-Mail usw.).
Benutzer-Gruppen-Modus
Dieser Modus ist noch nicht implementiert, stattdessen wird der Benutzermodus verwendet.
3.16.8. ProjectForge ohne LDAP
ProjectForge lässt sich auch ohne LDAP betreiben (Standard).
Datei: projectforge.properties:
1
2
3
...
projectforge.login.handlerClass=LoginDefaultHandler
...
3.17. OAuth2-/OIDC-Authentifizierung
ProjectForge unterstützt die Authentifizierung über einen externen OAuth2-/OIDC-Provider.
Benutzer melden sich beim Identity Provider an (z. B. Authentik, Keycloak) und werden zurück zu ProjectForge
geleitet. Der Benutzer muss in ProjectForge bereits existieren (zugeordnet über idpExternalId oder den
Benutzernamen).
3.17.1. Konfiguration
Folgende OAuth2-/OIDC-Client-Konfiguration wird in projectforge.properties ergänzt:
spring.security.oauth2.client.registration.authentik.client-id=${AUTHENTIK_CLIENT_ID}
spring.security.oauth2.client.registration.authentik.client-secret=${AUTHENTIK_CLIENT_SECRET}
spring.security.oauth2.client.registration.authentik.scope=openid,profile,email
spring.security.oauth2.client.registration.authentik.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.authentik.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.provider.authentik.issuer-uri=${AUTHENTIK_ISSUER_URI}
Die Registrierungs-ID muss authentik lauten, auch bei anderen Providern wie Keycloak: ProjectForge aktiviert seine
OAuth2-Anmeldung nur, wenn spring.security.oauth2.client.registration.authentik.client-id gesetzt ist. Für Keycloak
genügt es, die Issuer-URI des Realms (z. B. auth.acme.com/realms/acme.com) und den Client von ProjectForge
anzugeben. Die beim Provider zu registrierende Redirect-URI lautet
<your-projectforge-domain>/login/oauth2/code/authentik.
Die Anmeldeseite von ProjectForge hat keinen Button für den Identity Provider: Benutzer starten die Anmeldung über
<your-projectforge-domain>/oauth2/authorization/authentik (z. B. als Link oder Lesezeichen oder aus dem
Anwendungs-Dashboard des Identity Providers).
3.17.2. Benutzerzuordnung
Nach einer erfolgreichen OAuth2-Anmeldung ermittelt ProjectForge das lokale Benutzerkonto wie folgt:
-
Der OIDC-Claim
subwird mit dem FeldidpExternalIdder ProjectForge-Benutzer verglichen. -
Gibt es keinen Treffer, wird ersatzweise der Claim
preferred_usernamemit dem ProjectForge-Benutzernamen verglichen. -
Gibt es weiterhin keinen Treffer, wird die Anmeldung abgelehnt.
Deaktivierte Benutzer werden unabhängig von einer gültigen OAuth2-Session immer abgelehnt.
3.17.3. Externer Gateway-Modus
ProjectForge kann als reduzierte, öffentlich erreichbare Instanz laufen, die ausschließlich über OAuth2/OIDC authentifiziert. In diesem Modus stehen nur folgende Dienste zur Verfügung:
-
CardDAV (Adressbuch-Synchronisation)
-
CalDAV / ICS-Abonnements (Kalenderexport)
-
DataTransfer (Bereiche für den Dateiaustausch)
Aktiviert wird er mit dem Spring-Profil external-gateway:
--spring.profiles.active=external-gateway
Minimale Gateway-Konfiguration
Die projectforge.properties der Gateway-Instanz benötigt den Gateway-Modus und die Datenbankverbindung.
Alle anderen Gateway-Einstellungen (CardDAV, die abgeschalteten Funktionen, siehe Funktionen abschalten) liefert
das Profil external-gateway automatisch. Auch ohne das Profil schaltet der Gateway-Modus alle Funktionen außer
dem Datentransfer ab.
Die OAuth2-/OIDC-Konfiguration wird nur für die DataTransfer-Oberfläche benötigt: CardDAV und CalDAV/ICS authentifizieren über Tokens und funktionieren ohne sie. Ist der OAuth2-Client nicht konfiguriert, startet das Gateway ohne Anmeldemöglichkeit.
ProjectForge fügt die projectforge.properties des Home-Verzeichnisses als --spring.config.additional-location
hinzu, die Spring mit höchster Priorität lädt. Sie überschreibt daher das Profil external-gateway; diese Datei
sollte sich deshalb auf die folgenden Einstellungen beschränken, statt Standardwerte des Profils zu wiederholen.
|
# Öffentliche URL des Gateways, einschließlich Port, falls er direkt veröffentlicht wird.
# Das ist die {baseUrl} der unten stehenden OAuth2-Redirect-URI.
projectforge.domain=https://gateway.example.com
# Gateway-Modus
projectforge.gateway.enabled=true
projectforge.gateway.sync.secret=<shared-secret>
# PostgreSQL (Host/Zugangsdaten an die eigene Umgebung anpassen)
spring.datasource.url=jdbc:postgresql://postgres:5432/projectforge
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=projectforge
spring.datasource.password=<your-password>
# Erforderlich: Die von der Hauptinstanz übertragenen DAV- und Kalender-Tokens werden verschlüsselt gespeichert.
projectforge.security.authenticationTokenEncryptionKey=<your-key>
# OAuth2/OIDC (nur für die DataTransfer-Oberfläche erforderlich)
spring.security.oauth2.client.registration.authentik.client-id=${AUTHENTIK_CLIENT_ID}
spring.security.oauth2.client.registration.authentik.client-secret=${AUTHENTIK_CLIENT_SECRET}
spring.security.oauth2.client.registration.authentik.scope=openid,profile,email
spring.security.oauth2.client.registration.authentik.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.authentik.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.provider.authentik.issuer-uri=${AUTHENTIK_ISSUER_URI}
Zum Testen mit HSQLDB (ohne externe Datenbank) wird der PostgreSQL-Block ersetzt:
spring.datasource.url=jdbc:hsqldb:file:${projectforge.base.dir}/database/projectforge;shutdown=true
spring.datasource.driver-class-name=org.hsqldb.jdbc.JDBCDriver
spring.datasource.username=sa
spring.datasource.password=
Die interne ProjectForge-Instanz synchronisiert die Benutzerdaten über das gemeinsame Secret zum Gateway.
Push-Konfiguration der Hauptinstanz
Die (interne) Hauptinstanz von ProjectForge muss so konfiguriert sein, dass sie Benutzer-, Gruppen-, Adress- und
Kalenderdaten an das Gateway überträgt. Dazu wird in der projectforge.properties der Hauptinstanz Folgendes ergänzt:
projectforge.gateway.push.enabled=true
projectforge.gateway.push.url=https://gateway.example.com/api/gateway/sync
projectforge.gateway.push.secret=<shared-secret>
projectforge.gateway.push.syncIntervalMs=900000
| Eigenschaft | Beschreibung |
|---|---|
|
Aktiviert die periodische Übertragung an die Gateway-Instanz |
|
Basis-URL des Sync-API-Endpunkts des Gateways |
|
Gemeinsames Secret (muss mit |
|
Intervall zwischen den Übertragungen in Millisekunden (Standard: 900000 = 15 Minuten) |
|
Verzögerung der ersten Übertragung nach dem Start in Millisekunden (Standard: 120000 = 2 Minuten) |
|
URL des Gateways für Browser (externe Links von Datentransferbereichen), nur falls abweichend von |
Der Push-Dienst überträgt Benutzer, Gruppen, Adressbücher und zwischengespeicherte ICS-Kalenderdaten an das Gateway.
Alle Anfragen werden über den HTTP-Header X-Gateway-Secret authentifiziert.
Datentransferbereiche mit externem Download oder Upload werden auf der Hauptinstanz administriert und mit jeder
Synchronisation auf das Gateway übertragen. Ihr externer Link zeigt auf das Gateway, Externe und die internen
Berechtigten arbeiten dort mit den Dateien; auf dem Gateway sind diese Bereiche schreibgeschützt und behalten die IDs
der Hauptinstanz. Das Gateway hat nur diese Bereiche, es legt selbst keine an (auch keine persönlichen Boxen). Wird der externe
Zugriff auf der Hauptinstanz abgeschaltet oder der Bereich gelöscht, verschwindet er vom Gateway. Das Gateway
verschickt die Benachrichtigungen dieser Bereiche an ihre Beobachter (z. B. bei einem externen Upload) und braucht
dafür eine Mailserver-Konfiguration; dazu überträgt der Push die E-Mail-Adressen dieser Beobachter, und nur ihre. Mit
projectforge.datatransfer.externalAccess.localAllowed=true läuft der externe Zugriff stattdessen auf der Hauptinstanz
(es wird nichts übertragen), mit false kann er gar nicht aktiviert werden.
3.18. Synchronisation mit einem Identity Provider (IdP)
ProjectForge kann als Master für Benutzer- und Gruppendaten dienen und sie in einem externen Identity Provider bereitstellen. Das ist unabhängig von der oben beschriebenen OAuth2-Anmeldung und betrifft die Verwaltung des Lebenszyklus von Benutzern und Gruppen. Derzeit werden Keycloak und Authentik unterstützt.
3.18.1. Konfiguration
# Provider: "keycloak" (Standard) oder "authentik"
projectforge.idp.provider=keycloak
projectforge.login.handlerClass=IdpMasterLoginHandler
# Optional: Passwörter bei erfolgreicher Anmeldung zum IdP synchronisieren
projectforge.idp.syncPasswords=false
3.18.2. Keycloak einrichten
Realm und Client
-
Einen Realm anlegen (z. B.
acme.com) -
Die Sprachen global aktivieren:
de,en -
Einen Client
projectforgeanlegen (confidential, Service-Account aktiviert) -
Das Client-Secret notieren
projectforge.keycloak.serverUrl=https://auth.acme.com
projectforge.keycloak.realm=acme.com
projectforge.keycloak.clientId=projectforge
projectforge.keycloak.clientSecret=<secret>
projectforge.keycloak.pageSize=100
Benutzerattribute
Im Keycloak-Realm werden folgende benutzerdefinierte Benutzerattribute angelegt:
| Attribut | Min. Länge | Max. Länge | Hinweise |
|---|---|---|---|
|
0 |
100 |
|
|
0 |
255 |
|
|
Optionen: |
||
|
0 |
— |
Wird automatisch validiert ( |
|
0 |
255 |
|
|
0 |
255 |
|
|
0 |
255 |
|
|
0 |
255 |
WLAN-Passwort (Samba-NT-Hash) |
Die Mindestlänge des Benutzernamen-Validators wird auf 2 gesetzt (Keycloak-Standard ist 3; reduziert für kurze
Benutzernamen wie jo).
| Benutzer dürfen ihre eigenen Attribute (Name, Vorname usw.) in Keycloak nicht bearbeiten können. |
3.18.3. Authentik einrichten
-
Eine neue Rolle anlegen (z. B.
projectforge-sync) mit den Berechtigungen: Group (add, change, delete, view), User (add, change, delete, view, add/remove user to group) -
In Admin einen Sync-Benutzer mit dieser Rolle anlegen
-
Ein API-Token erzeugen: Admin → Directory → Tokens and App passwords → Create
projectforge.authentik.serverUrl=https://authentik.acme.com
projectforge.authentik.apiToken=<api-token>
projectforge.authentik.pageSize=100
Authentik speichert benutzerdefinierte Attribute als JSON-Objekt an Benutzern/Gruppen – eine Vorkonfiguration von Attributschemata ist nicht nötig.
3.18.4. Attributzuordnungen
Hier wird festgelegt, welche ProjectForge-Felder in welche Benutzer-/Gruppenattribute des IdP synchronisiert werden:
projectforge.idp.userAttributes.jiraUsername=jiraUsername
projectforge.idp.userAttributes.mobilePhone=mobilePhone
projectforge.idp.userAttributes.gender=gender
projectforge.idp.userAttributes.locale=locale
projectforge.idp.userAttributes.organization=organization
projectforge.idp.userAttributes.description=description
projectforge.idp.userAttributes.nickname=nickname
projectforge.idp.groupAttributes.description=description
projectforge.idp.groupAttributes.organization=organization
3.18.5. Synchronisation des WLAN-Passworts (optional)
projectforge.idp.wlanPasswordAttribute=sambaNTPassword
3.18.6. Login-Handler
| Handler | Beschreibung |
|---|---|
|
Kein externer IdP (Standard) |
|
ProjectForge ist Master; Benutzer/Gruppen werden übertragen PF → IdP |
|
IdP ist Master; Benutzer/Gruppen werden abgerufen IdP → PF |
3.19. Fehlerbehebung
3.19.1. NullPointerException auf Seiten mit Diagrammen unter Linux
Treten beim Aufruf von Seiten mit Diagrammen (z. B. im Menü Projektmanagement → Meine Statistiken) Exceptions auf:
Caused by: java.lang.NullPointerException
at java.desktop/sun.awt.FontConfiguration.getVersion(FontConfiguration.java:1262)
dann ist vermutlich das Linux-Paket fontconfig nicht installiert. In diesem Fall das Paket installieren und ProjectForge neu starten.
4. Wartung
4.1. Aktualisieren
Das Aktualisieren ist einfach: Datenbank sichern, ProjectForge stoppen und die neue Version starten (neue JAR-Datei
oder docker pull micromata/projectforge und den Container neu erzeugen). Datenbankschema und Daten werden beim ersten
Start automatisch migriert (Flyway). Die wenigen Änderungen, die Aufmerksamkeit erfordern, stehen im
Migration guide.
4.2. Datenbank neu indizieren
Der Suchindex wird jede Nacht neu aufgebaut (siehe Scheduler). Er lässt sich auch manuell unter Administration → System → Reindex starten, z. B. nach dem Wiederherstellen eines Backups.
4.3. Analysewerkzeuge
Die Logdateien liegen in logs des Home-Verzeichnisses; Administratoren können sie außerdem mit dem Log-Viewer des
System-Dashboards durchsuchen. Für die Analyse eines hängenden oder langsamen Servers sind die JDK-Werkzeuge
hilfreich:
1
2
3
jps -l # Listet die Java-Prozesse und ihre PIDs.
jstack <pid> # Thread-Dump, z. B. um blockierte Threads zu finden.
jcmd <pid> GC.heap_info
Unter Docker werden sie im Container ausgeführt (docker exec -it projectforge bash); enthält das JRE-Image nicht alle
JDK-Werkzeuge, schreibt kill -3 <pid> einen Thread-Dump in die Ausgabe des Containers (docker logs projectforge).
4.4. Backup
Alle Datensätze von ProjectForge® werden in der zugrunde liegenden Datenbank (z. B. PostgreSQL) gespeichert. Es empfiehlt sich, ein Unix-Cron-Skript einzurichten, das regelmäßig ein Backup der Datenbank erstellt (siehe Backup-Skript).
4.4.1. Eingebettete Datenbank (HSQLDB)
Mit der eingebetteten Datenbank liegt alles im Home-Verzeichnis von ProjectForge: die Datenbank (database), die
Konfigurationsdateien, die eigenen resources, die Datentransfer-Dateien (datatransfer) und, falls noch verwendet,
das JCR (jcr). Die Dateien des Dateispeichers sind Teil der eingebetteten Datenbank. Für ein Backup ProjectForge
stoppen und das gesamte Home-Verzeichnis kopieren (z. B. tar czf projectforge-home_2026-10-06.tar.gz -C $HOME ProjectForge);
logs und hibernateSearch können ausgelassen werden. Zum Wiederherstellen ProjectForge stoppen, das
Home-Verzeichnis durch die Kopie ersetzen und ProjectForge wieder starten (den Suchindex neu aufbauen, falls
hibernateSearch ausgelassen wurde).
Sind die Datentransfer-Dateien verschlüsselt, darf der Schlüssel nicht Teil dieses Backups sein, siehe Verschlüsselung der Datentransfer-Dateien.
4.4.2. PostgreSQL-Dumps
Die Dateien des neuen Dateispeichers (Anhänge von Verträgen, Aufträgen, Rechnungen usw., siehe Dateien aus dem JCR übernehmen) liegen im eigenen Schema pf_files. Dieses Schema kann groß werden, daher werden zwei Dumps erstellt:
-
Der Haupt-Dump ohne die Dateien:
pg_dump -N pf_files …(schließt das Schemapf_filesaus). -
Der Dump nur der Dateien:
pg_dump -n pf_files -Fc …(Custom-Format, mitpg_restore -jparallel wiederherstellbar).
Beide Dumps sind voneinander unabhängig: Zwischen pf_files und den übrigen Tabellen gibt es keine Fremdschlüssel. Abweichungen nach dem Einspielen von Dumps verschiedener Tage melden die Integritätsprüfungen, die nachts laufen
(projectforge.cron.sanityChecks) und bei Bedarf über Administration → System → Check system integrity gestartet werden.
Datentransfer-Dateien (<home>/datatransfer) sind in keinem Backup enthalten: Ihre Metadaten liegen in pf_files, der Inhalt aber im Dateisystem, und er ist kurzlebig.
4.5. Backup wiederherstellen
4.5.1. Datenbank
1
2
gunzip projectforge_2026-10-06_02-00.sql.gz
psql -q -f projectforge_2026-10-06_02-00.sql -U postgres projectforge > log.txt 2>&1
Anschließend die Dateien wiederherstellen (Schema pf_files, der Haupt-Dump enthält es nicht):
1
pg_restore -U postgres -d projectforge -j 4 projectforge_files_2026-10-06_02-00.dump
Beide Dumps werden vor dem Start von ProjectForge eingespielt: Der Haupt-Dump enthält die Flyway-Historie, daher legt Flyway das Schema pf_files nicht erneut an. Existiert das Schema in der Zieldatenbank bereits, wird es zuvor gelöscht (DROP SCHEMA pf_files CASCADE;) oder pg_restore --clean --if-exists verwendet. Nach dem Wiederherstellen die Integritätsprüfungen über Administration → System → Check system integrity ausführen.
Zum Löschen und Neuanlegen einer Datenbank siehe PostgreSQL. Anschließend nicht vergessen, den Suchindex neu aufzubauen (Administration → System → Reindex)!
Hinweis
Sollen Produktivdaten in einem Testsystem verwendet werden, zuerst die E-Mail-Adressen der Benutzer in der Testdatenbank ändern (z. B. auf die eigene), damit niemand Benachrichtigungen aus dem Testsystem erhält. Außerdem ist der Datenschutz zu beachten.
4.5.2. JCR-Repository
Nur relevant für Installationen, die noch das JCR verwenden (projectforge.files.store=jcr), siehe Dateien aus dem JCR übernehmen.
Das JCR-Repository enthält die hochgeladenen Dateien (Verträge, Aufträge usw.). Seine nächtlichen Backups werden in das Backup-Verzeichnis geschrieben.
Wie ein JCR-Backup wiederhergestellt wird, steht in der Datei backupReadme.txt innerhalb der Backup-ZIP-Datei.
Bei einem beschädigten JCR-Repository oder für ein vollständiges Backup hilft ebenfalls backupReadme.txt. Die Readme liegt auch hier: github.com/micromata/projectforge/blob/develop/projectforge-jcr/src/main/resources/backupReadme.txt.
4.5.3. Dateien aus dem JCR übernehmen
Das JCR (Apache Oak) wird durch einen neuen Dateispeicher ersetzt: Die Dateien werden in der Datenbank gespeichert (Schema pf_files), die Datentransfer-Dateien im Dateisystem (<home>/datatransfer). Der Speicher wird in projectforge.properties gewählt:
# jcr: alle Dateien bleiben im JCR (wie bisher).
# db: alle Dateien werden im neuen Dateispeicher abgelegt.
projectforge.files.store=db
Ohne Konfiguration wird db für neue Installationen und jcr für Installationen mit bestehendem JCR verwendet (es sei denn, der neue Dateispeicher enthält bereits Dateien des Datenbankspeichers, dann db). Für eine bestehende Installation ändert sich also nichts, bis auf db umgestellt wird.
Nach dem Umstellen auf db und einem Neustart kopiert ProjectForge alle Dateien des JCR im Hintergrund. Jede Datei wird anhand von Größe und SHA-256-Prüfsumme verifiziert. Das Ergebnis wird in <home>/jcr-migration-report.txt geschrieben; die Migration wird bei jedem Start ausgeführt, bis ein Lauf ohne Fehler abgeschlossen ist. Sie lässt sich auch manuell auf der Systemseite starten (Karte „Dokumenten-Repository (JCR)“).
-
Alle Dateien werden kopiert, das JCR behält sie. Daher ist ein Zurückschalten auf
jcroder ein Rollback auf das vorherige Release möglich; nach einem Rollback fehlen nur die unterdbhochgeladenen Dateien. -
Datentransfer-Dateien belegen bis zu ihrem Ablauf doppelt Speicherplatz (JCR und
<home>/datatransfer). Gelöschte Dateien werden in beiden Speichern gelöscht. -
Sollen die Datentransfer-Dateien verschlüsselt werden, muss der Schlüssel vor dem Umstellen auf
dbkonfiguriert werden, siehe Verschlüsselung der Datentransfer-Dateien. Die Kopien im JCR bleiben unverschlüsselt, bis sie ablaufen oder das JCR entfernt wird. -
Das nächtliche JCR-Backup läuft in beiden Modi weiter, solange das JCR existiert. Mit
dbsind die Dateien Teil des Datei-Dumps (Schemapf_files, siehe Backup-Skript), Datentransfer-Dateien werden nicht gesichert.
Vor dem Update auf ein Release ohne JCR entweder auf db umstellen und eine erfolgreiche Migration abwarten oder
unmittelbar vor dem Update ein frisches JCR-Backup-ZIP erzeugen (Systemseite, Karte „Dokumenten-Repository (JCR)“,
JCR-Backup-ZIP erzeugen): Das nächste Release importiert die Dokumente aus diesem ZIP in die Datenbank. Das ZIP
enthält keine Datentransfer-Dateien.
4.6. Automatisches Backup
4.6.1. Backup-Skript
Auf dem ProjectForge®-Server (oder dem Datenbankserver) wird als Benutzer projectforge ein Crontab-Eintrag eingerichtet, der folgendes Skript startet:
Datei: pforgebackup.sh:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/bash
PGSQL_DIR=/usr/bin
BACKUPDIR=/home/projectforge/backup
BASENAME=projectforge
TIMESTAMP=`date '+%Y-%m-%d_%H-%M'`
echo Starting backup of ProjectForge ...
# Haupt-Dump: alle Daten außer den Dateien (Schema pf_files).
BACKUPFILE=$BACKUPDIR/${BASENAME}_${TIMESTAMP}.sql
# Dump nur der Dateien (Schema pf_files, Anhänge von Verträgen, Aufträgen, Rechnungen usw.).
FILES_BACKUPFILE=$BACKUPDIR/${BASENAME}_files_${TIMESTAMP}.dump
echo Using filenames $BACKUPFILE and $FILES_BACKUPFILE ...
echo Exporting data ...
$PGSQL_DIR/pg_dump -U projectforge -N pf_files -f $BACKUPFILE || { echo "Error: export of data failed."; exit 1; }
echo Zipping backupfile ...
gzip $BACKUPFILE
echo Exporting files ...
# Custom-Format; -Z 0: Der Inhalt ist bereits komprimiert (oder nicht komprimierbar).
$PGSQL_DIR/pg_dump -U projectforge -n pf_files -Fc -Z 0 -f $FILES_BACKUPFILE || { echo "Error: export of files failed."; exit 1; }
# Für ein Remote-Backup per scp:
#scp $BACKUPFILE.gz $FILES_BACKUPFILE <user>@backup.mydomain:backup/
# Das Löschen der täglichen Backups übernimmt ProjectForge (projectforge.cron.purgeBackupDir, siehe unten). Monatliche
# Backups werden dauerhaft aufbewahrt, da sie für finanzielle Jahresvergleiche benötigt werden.
echo Backup of ProjectForge finished.
ProjectForge bereinigt die täglichen Backups (wöchentliche und monatliche bleiben erhalten), wenn das Backup-Verzeichnis in projectforge.properties konfiguriert ist:
projectforge.cron.purgeBackupDir=/home/projectforge/backup
# Optional: kommagetrennte Präfixe der Backup-Serien. Ohne Angabe werden alle Dateien verarbeitet, die ein Datum enthalten.
# Jede Serie (Text vor dem Datum, hier projectforge_ und projectforge_files_) wird für sich bereinigt.
#projectforge.cron.purgeBackupFilesPrefix=projectforge_
Der Datei-Dump projectforge_files_… ist eine eigene Serie und wird daher wie der Haupt-Dump bereinigt (auch mit dem Präfix projectforge_, da er damit beginnt).
Damit pg_dump ohne Passwortabfrage läuft, wird das Skript als Unix-Benutzer projectforge ausgeführt und
folgende Zeile in pg_hba.conf ergänzt (Peer-Authentifizierung: Der Unix-Benutzername muss dem Datenbankbenutzernamen
entsprechen):
Datei: pg_hba.conf:
1
local projectforge projectforge peer
Alternativ wird das Passwort in ~/.pgpass des Benutzers abgelegt, der das Skript ausführt (chmod 600 ~/.pgpass):
localhost:5432:projectforge:projectforge:<password> (dann -h localhost zu den pg_dump-Aufrufen hinzufügen).
4.6.2. Crontab-Eintrag hinzufügen
Folgender Eintrag wird in die Unix-Crontab aufgenommen:
1
2
# täglich um 2:00 Uhr ausführen
0 2 * * * /home/projectforge/bin/pforgebackup.sh
4.6.3. Remote-Backup
Für ein Remote-Backup per scp wird eine Schlüssel-Authentifizierung benötigt:
-
Schlüssel erzeugen (mit leerem Passwort): ssh-keygen
-
Den öffentlichen Schlüssel, z. B.
identity.pub, auf den Backup-Server kopieren. -
Diesen Schlüssel auf dem Backup-Server zu den autorisierten Schlüsseln hinzufügen.
4.6.4. Remote-Backup abholen
Aus Sicherheitsgründen lassen sich die Backup-Dateien auch per Cronjob vom ProjectForge®-Server abholen, der z. B. eine Stunde später startet:
Datei: pforgePollBackup.sh:
#!/bin/bash SERVER=projectforge.mydomain DIR=/home/projectforge/backup REMOTE_DIR=backup REMOTE_USER=projectforge # Z. B. -e "ssh -p <port>" ergänzen, falls ssh nicht den Standardport verwendet. rsync -avz -C $REMOTE_USER@$SERVER:$REMOTE_DIR $DIR
In diesem Fall wird der SSH-Schlüssel auf dem Backup-Server erzeugt und auf dem ProjectForge®-Server zu den autorisierten Schlüsseln hinzugefügt. Auf dem Backup-Server wird folgender Crontab-Eintrag ergänzt:
1
2
# täglich um 3:00 Uhr ausführen
0 3 * * * /home/projectforge/bin/pforgePollBackup.sh
4.7. Monitoring
ProjectForge lässt sich mit einem Monitoring-Werkzeug (z. B. Nagios) über den öffentlichen Systemstatus überwachen,
z. B. projectforge.acme.com/rsPublic/systemStatus. Er antwortet mit einem kleinen JSON-Objekt, sobald der
Webserver läuft. Ohne Anmeldung sind Version und Build-Datum nur Platzhalter (<version>, <date>), für das
Monitoring sind also nur der Anwendungsname (appname) und der Startzustand nützlich: setupRedirectUrl ist gesetzt,
solange die Einrichtung nicht abgeschlossen ist.
Probleme zur Laufzeit (Fehler, nicht erreichbare externe Systeme, fehlgeschlagene Scheduler-Läufe) meldet der Fehler-Digest für den Support, und das System-Dashboard zeigt sie an.
4.8. Scheduler
4.8.1. Suchindex der Datenbank
Der Suchindex wird jede Nacht vom nächtlichen Job neu aufgebaut (projectforge.cron.nightly, Standard 2:30). ProjectForge
läuft mit der Zeitzone UTC (unabhängig von der Zeitzone des Servers), daher sind die Cron-Ausdrücke von
projectforge.cron.* in UTC angegeben. Fehler werden geloggt und sind damit Teil des Fehler-Digests. Die Läufe aller
geplanten Jobs werden im System-Dashboard aufgelistet.
4.9. ProjectForge deinstallieren
Die JAR-Datei (bzw. den Docker-Container und das Image) und das Home-Verzeichnis von ProjectForge löschen. Wo das Home-Verzeichnis liegt, zeigt im Zweifel die Logausgabe beim Start: ProjectForge loggt das verwendete Home-Verzeichnis. Bei PostgreSQL wird auch die Datenbank gelöscht (siehe PostgreSQL).
Hinweis
Achtung: Wird das Home-Verzeichnis gelöscht, werden auch alle Daten der eingebetteten Datenbank gelöscht!
4.10. Sicherheitsverbesserungen
4.10.1. Fail2ban
Fehlgeschlagene Anmeldungen werden als Warnungen geloggt, einschließlich der IP-Adresse des Clients (<user>@<ip>
vor dem Loggernamen):
… WARN @192.0.2.10 … LoginDefaultHandler : User login failed: jdoe/**
Ein Ausgangspunkt für einen fail2ban-Filter (bitte mit fail2ban-regex gegen die eigene Logdatei
logs/ProjectForge.log prüfen):
[Definition]
failregex = @<HOST>\s.*LoginDefaultHandler\s*: User login failed:
5. Plugins
Einige Funktionen sind eingebaute Plugins, die nicht automatisch aktiviert sind. Sie werden von einem Administrator
unter Administration → Plugins aktiviert (oder über projectforge.plugins.ensure-active in
projectforge.properties). Nach dem (De-)Aktivieren eines Plugins muss ProjectForge neu gestartet werden, siehe auch
Installation – Activation of built-in plugins.
5.1. Datentransfer
Bereiche für den Datentransfer zum Austausch (großer) Dateien zwischen Benutzern, Gruppen und auch externen Benutzern.
Für die meisten Installationen empfohlen. Die Dateien werden in datatransfer des Home-Verzeichnisses gespeichert und
laufen automatisch ab.
5.1.1. Verschlüsselung der Datentransfer-Dateien
Mit dem neuen Dateispeicher (projectforge.files.store=db, siehe Dateien aus dem JCR übernehmen) werden die
Datentransfer-Dateien komprimiert gespeichert (sofern sie nicht schon durch ihr Format komprimiert sind, z. B. zip, pdf,
Videos) und, wenn ein Schlüssel konfiguriert ist, verschlüsselt (AES-256). Kopien des Home-Verzeichnisses (z. B.
Backups) enthalten sie damit nicht im Klartext:
# Ein langer Zufallswert, z. B. erzeugt mit: openssl rand -base64 32
projectforge.files.fileSystemEncryptionKey=...
-
Den Schlüssel getrennt von den Backups des Home-Verzeichnisses aufbewahren, sonst enthalten diese den Schlüssel mit. Statt in
projectforge.propertieslässt sich der Schlüssel auch als UmgebungsvariablePROJECTFORGE_FILES_FILESYSTEMENCRYPTIONKEYangeben. -
Eine Kopie des Schlüssels an einem sicheren Ort aufbewahren: Geht er verloren oder wird er geändert, lassen sich die verschlüsselten Dateien nicht mehr lesen (die Integritätsprüfung meldet sie). Ein fehlender oder geänderter Schlüssel wird außerdem beim Start als Fehler geloggt („Encrypted files below … can’t be read“).
-
Verschlüsselt werden nur Dateien, die nach dem Konfigurieren des Schlüssels gespeichert werden; zuvor gespeicherte Dateien behalten ihr Format und bleiben lesbar. Daher den Schlüssel vor dem Umstellen auf
dbkonfigurieren: Die aus dem JCR kopierten Dateien werden dann direkt verschlüsselt. -
Die in der Datenbank gespeicherten Anhänge (Schema
pf_files) werden nicht verschlüsselt, nur die Datentransfer-Dateien. -
Der Aufwand ist gering: Die Verschlüsselung läuft mit mehreren GB/s pro Kern (Java 21), das Komprimieren einer Textdatei von 10 GB dauert etwa eine Minute.
5.2. Liquiditätsplanung
Unterstützt die Cashflow-Prognose für eine einfach zu bedienende Liquiditätsplanung. Weitere Informationen stehen im Benutzerhandbuch.
5.3. Banking
Bankkonten und der Import von Kontoauszügen.
5.4. Softwarelizenzverwaltung
In den meisten Unternehmen fallen viele Programme und Lizenzschlüssel an. Mit diesem Plugin können Administratoren und Benutzer Lizenzschlüssel organisieren:
-
Jeder Benutzer kann einen Software-Eintrag mit Lizenzschlüsseln anlegen.
-
Der Administrator kann alle Lizenzschlüssel einsehen und bearbeiten.
-
Nur Benutzer, die einem Software-Eintrag zugeordnet sind (Eigentümer), können den Lizenzschlüssel sehen.
-
Über die Änderungshistorie jedes Eintrags lässt sich die Lizenznutzung durch die Benutzer im Zeitverlauf nachvollziehen.
-
Die Änderungshistorie ist nur für Administratoren und Software-Eigentümer sichtbar.
5.5. Merlin-Word®-Vorlagen
Vorlagen für Microsoft-Word®-Dokumente (mit Variablen, abhängigen Variablen sowie Serienausführung), nützlich für Verträge, Serienbriefe usw.
5.6. Skill-Matrix
Erfassung und Darstellung der Fähigkeiten der Mitarbeitenden, gepflegt von den Benutzern selbst.
5.7. Weitere Plugins
Einige weitere Plugins existieren aus Kompatibilitätsgründen für bestehende Installationen. Sie werden ebenfalls unter Administration → Plugins aufgeführt, aber nicht weiterentwickelt.