ldap-rest 0.1.3 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -21
- package/dist/abstract/ldapFlat.js +1 -1
- package/dist/lib/ldapActions.js +1 -1
- package/dist/plugins/ldap/groups.js +1 -1
- package/dist/src/abstract/ldapFlat.d.ts +9 -0
- package/dist/src/browser/ldap-user-editor/components/UserTree.d.ts +2 -1
- package/dist/src/browser/shared/components/DisposableComponent.d.ts +29 -0
- package/dist/src/browser/shared/components/Modal.d.ts +6 -1
- package/dist/src/lib/ldapActions.d.ts +9 -0
- package/dist/src/plugins/ldap/groups.d.ts +9 -0
- package/docs/README.md +23 -486
- package/docs/{DEVELOPER_GUIDE.md → client-development/README.md} +24 -24
- package/docs/client-development/api/README.md +75 -0
- package/docs/client-development/browser/README.md +65 -0
- package/docs/{plugins/DEVELOPMENT.md → plugin-development/README.md} +4 -9
- package/docs/plugin-development/hooks.md +18 -0
- package/docs/usage/README.md +89 -0
- package/docs/usage/configuration.md +375 -0
- package/docs/usage/plugins/README.md +87 -0
- package/docs/usage/plugins/auth/README.md +65 -0
- package/docs/usage/plugins/auth/crowdsec.md +95 -0
- package/docs/usage/plugins/auth/hmac.md +293 -0
- package/docs/usage/plugins/auth/llng.md +99 -0
- package/docs/usage/plugins/auth/oidc.md +167 -0
- package/docs/usage/plugins/auth/rate-limit.md +62 -0
- package/docs/usage/plugins/auth/token.md +136 -0
- package/docs/usage/plugins/auth/totp.md +213 -0
- package/docs/usage/plugins/auth/trusted-proxy.md +127 -0
- package/docs/usage/plugins/integrations/README.md +42 -0
- package/docs/usage/plugins/ldap/README.md +79 -0
- package/docs/usage/troubleshooting.md +105 -0
- package/package.json +9 -1
- package/static/browser/ldap-user-editor/components/UserTree.js +6 -3
- package/static/browser/ldap-user-editor/components/UserTree.js.map +1 -1
- package/static/browser/ldap-user-editor.esm.js +62 -3
- package/static/browser/ldap-user-editor.esm.js.map +1 -1
- package/static/browser/ldap-user-editor.js +62 -3
- package/static/browser/ldap-user-editor.js.map +1 -1
- package/static/browser/ldap-user-editor.min.js +1 -1
- package/static/browser/ldap-user-editor.min.js.map +1 -1
- package/static/browser/shared/components/DisposableComponent.js +59 -0
- package/static/browser/shared/components/DisposableComponent.js.map +1 -0
- package/static/browser/shared/components/Modal.js +16 -6
- package/static/browser/shared/components/Modal.js.map +1 -1
- package/static/browser/shared.esm.js +72 -6
- package/static/browser/shared.esm.js.map +1 -1
- package/static/browser/shared.js +72 -6
- package/static/browser/shared.js.map +1 -1
- package/static/browser/shared.min.js +1 -1
- package/static/browser/shared.min.js.map +1 -1
- package/docs/authentication.md +0 -1194
- /package/docs/{OPENAPI.md → client-development/api/openapi.md} +0 -0
- /package/docs/{api/REFERENCE.md → client-development/api/reference.md} +0 -0
- /package/docs/{api/REST_API.md → client-development/api/rest-api.md} +0 -0
- /package/docs/{browser/LIBRARIES.md → client-development/browser/libraries.md} +0 -0
- /package/docs/{examples/EXAMPLES.md → client-development/examples/README.md} +0 -0
- /package/docs/{examples → client-development/examples/ldif}/twake-mailbox-type-nomenclature.ldif +0 -0
- /package/docs/{examples → client-development/examples/ldif}/twake-mailbox-type-schema-amendment.ldif +0 -0
- /package/docs/{schemas/SCHEMAS.md → client-development/schemas/README.md} +0 -0
- /package/docs/{PLUGIN_DEPENDENCIES.md → plugin-development/dependencies.md} +0 -0
- /package/docs/{testing-with-embedded-ldap.md → plugin-development/testing.md} +0 -0
- /package/docs/{presenterm.md → presentations/en.md} +0 -0
- /package/docs/{presenterm-fr.md → presentations/fr.md} +0 -0
- /package/docs/{authzLinid1.md → usage/plugins/auth/authz-linid1.md} +0 -0
- /package/docs/{authzPerBranch.md → usage/plugins/auth/authz-per-branch.md} +0 -0
- /package/docs/{twakeAppAccountsApi.md → usage/plugins/integrations/app-accounts.md} +0 -0
- /package/docs/{twakeCalendarResources.md → usage/plugins/integrations/calendar-resources.md} +0 -0
- /package/docs/{twakeJames.md → usage/plugins/integrations/james-mail.md} +0 -0
- /package/docs/{jamesTeamMailboxes.md → usage/plugins/integrations/james-mailboxes.md} +0 -0
- /package/docs/{ldapBulkImport.md → usage/plugins/ldap/bulk-import.md} +0 -0
- /package/docs/{ldapExternalUsersInGroups.md → usage/plugins/ldap/external-users.md} +0 -0
- /package/docs/{ldapFlatGeneric.md → usage/plugins/ldap/flat-generic.md} +0 -0
- /package/docs/{ldapGroups.md → usage/plugins/ldap/groups.md} +0 -0
- /package/docs/{onChange.md → usage/plugins/ldap/on-change.md} +0 -0
- /package/docs/{ldapOrganizations.md → usage/plugins/ldap/organizations.md} +0 -0
- /package/docs/{ldapTrash.md → usage/plugins/ldap/trash.md} +0 -0
- /package/docs/{static.md → usage/plugins/utilities/static.md} +0 -0
- /package/docs/{weblogs.md → usage/plugins/utilities/weblogs.md} +0 -0
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# Plugins
|
|
2
|
+
|
|
3
|
+
LDAP-Rest is extensible through a plugin system. This section documents all available plugins.
|
|
4
|
+
|
|
5
|
+
## LDAP Plugins
|
|
6
|
+
|
|
7
|
+
LDAP entity management:
|
|
8
|
+
|
|
9
|
+
| Plugin | Description |
|
|
10
|
+
| ---------------------------------------- | ------------------------------------------------------- |
|
|
11
|
+
| [flat-generic](ldap/flat-generic.md) | Generic LDAP entity management (users, positions, etc.) |
|
|
12
|
+
| [groups](ldap/groups.md) | LDAP group management with member validation |
|
|
13
|
+
| [organizations](ldap/organizations.md) | Hierarchical organization management |
|
|
14
|
+
| [bulk-import](ldap/bulk-import.md) | Bulk import from CSV |
|
|
15
|
+
| [trash](ldap/trash.md) | Trash system (soft delete) |
|
|
16
|
+
| [external-users](ldap/external-users.md) | Automatic external contact creation |
|
|
17
|
+
| [on-change](ldap/on-change.md) | LDAP change detection |
|
|
18
|
+
|
|
19
|
+
## Authentication Plugins
|
|
20
|
+
|
|
21
|
+
Secure API access:
|
|
22
|
+
|
|
23
|
+
| Plugin | Description |
|
|
24
|
+
| ---------------------- | ---------------------------------------- |
|
|
25
|
+
| [token](auth/token.md) | Bearer token authentication |
|
|
26
|
+
| [totp](auth/totp.md) | TOTP authentication (time-based codes) |
|
|
27
|
+
| [hmac](auth/hmac.md) | HMAC-SHA256 signing for backend services |
|
|
28
|
+
| [llng](auth/llng.md) | LemonLDAP::NG SSO integration |
|
|
29
|
+
| [oidc](auth/oidc.md) | OpenID Connect / OAuth 2.0 |
|
|
30
|
+
|
|
31
|
+
## Authorization Plugins
|
|
32
|
+
|
|
33
|
+
Access control:
|
|
34
|
+
|
|
35
|
+
| Plugin | Description |
|
|
36
|
+
| -------------------------------------------- | ------------------------------- |
|
|
37
|
+
| [authz-per-branch](auth/authz-per-branch.md) | Branch-level LDAP authorization |
|
|
38
|
+
| [authz-linid1](auth/authz-linid1.md) | LinID 1.x integration |
|
|
39
|
+
|
|
40
|
+
## Security Plugins
|
|
41
|
+
|
|
42
|
+
Protection and rate limiting:
|
|
43
|
+
|
|
44
|
+
| Plugin | Description |
|
|
45
|
+
| -------------------------------------- | --------------------------------- |
|
|
46
|
+
| [trusted-proxy](auth/trusted-proxy.md) | X-Forwarded-For header validation |
|
|
47
|
+
| [rate-limit](auth/rate-limit.md) | Request rate limiting |
|
|
48
|
+
| [crowdsec](auth/crowdsec.md) | IP blocking via CrowdSec |
|
|
49
|
+
|
|
50
|
+
## Integration Plugins
|
|
51
|
+
|
|
52
|
+
Connect to external systems:
|
|
53
|
+
|
|
54
|
+
| Plugin | Description |
|
|
55
|
+
| -------------------------------------------------------- | ---------------------------- |
|
|
56
|
+
| [james-mail](integrations/james-mail.md) | Apache James synchronization |
|
|
57
|
+
| [james-mailboxes](integrations/james-mailboxes.md) | Apache James team mailboxes |
|
|
58
|
+
| [calendar-resources](integrations/calendar-resources.md) | Twake calendar resources |
|
|
59
|
+
| [app-accounts](integrations/app-accounts.md) | Applicative accounts API |
|
|
60
|
+
|
|
61
|
+
## Utility Plugins
|
|
62
|
+
|
|
63
|
+
| Plugin | Description |
|
|
64
|
+
| ------------------------------- | ------------------ |
|
|
65
|
+
| [static](utilities/static.md) | Static file server |
|
|
66
|
+
| [weblogs](utilities/weblogs.md) | HTTP logging |
|
|
67
|
+
|
|
68
|
+
## Plugin Dependencies
|
|
69
|
+
|
|
70
|
+
Some plugins require other plugins:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
core/twake/james
|
|
74
|
+
└─ requires: core/ldap/onChange
|
|
75
|
+
|
|
76
|
+
core/ldap/externalUsersInGroups
|
|
77
|
+
└─ requires: core/ldap/groups
|
|
78
|
+
|
|
79
|
+
core/auth/authzPerBranch
|
|
80
|
+
└─ requires: An authentication plugin
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
See [the complete dependencies matrix](../../plugin-development/dependencies.md).
|
|
84
|
+
|
|
85
|
+
## Load Order
|
|
86
|
+
|
|
87
|
+
Authentication plugins are loaded first to secure API endpoints. The order is defined in `src/plugins/priority.json`.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Authentication Plugins
|
|
2
|
+
|
|
3
|
+
LDAP-Rest provides multiple authentication plugins to secure API access. These plugins can be used individually or combined depending on your infrastructure requirements.
|
|
4
|
+
|
|
5
|
+
## Available Authentication Methods
|
|
6
|
+
|
|
7
|
+
| Method | Plugin | Description |
|
|
8
|
+
| ------------------------- | ------------------------- | ------------------------------------------------ |
|
|
9
|
+
| [Token](token.md) | `core/auth/token` | Simple bearer token authentication |
|
|
10
|
+
| [TOTP](totp.md) | `core/auth/totp` | Time-based One-Time Password authentication |
|
|
11
|
+
| [HMAC](hmac.md) | `core/auth/hmac` | HMAC-SHA256 request signing for backend services |
|
|
12
|
+
| [LemonLDAP::NG](llng.md) | `core/auth/llng` | Integration with LemonLDAP::NG SSO |
|
|
13
|
+
| [OpenID Connect](oidc.md) | `core/auth/openidconnect` | OAuth 2.0 / OpenID Connect authentication |
|
|
14
|
+
|
|
15
|
+
## Authorization Plugins
|
|
16
|
+
|
|
17
|
+
| Method | Plugin | Description |
|
|
18
|
+
| ----------------------------------------------- | -------------------------- | --------------------------- |
|
|
19
|
+
| [Authorization Per Branch](authz-per-branch.md) | `core/auth/authzPerBranch` | Branch-level access control |
|
|
20
|
+
| [Authorization LinID 1.x](authz-linid1.md) | `core/auth/authzLinid1` | LinID 1.x integration |
|
|
21
|
+
|
|
22
|
+
## Security Plugins
|
|
23
|
+
|
|
24
|
+
| Method | Plugin | Description |
|
|
25
|
+
| --------------------------------- | ------------------------ | ----------------------------------------------------- |
|
|
26
|
+
| [Trusted Proxy](trusted-proxy.md) | `core/auth/trustedProxy` | Validate X-Forwarded-For headers from reverse proxies |
|
|
27
|
+
| [Rate Limiting](rate-limit.md) | `core/auth/rateLimit` | Prevent brute force attacks |
|
|
28
|
+
| [CrowdSec](crowdsec.md) | `core/auth/crowdsec` | IP reputation and blocking |
|
|
29
|
+
|
|
30
|
+
## Choosing an Authentication Method
|
|
31
|
+
|
|
32
|
+
| Feature | Token | TOTP | HMAC | LemonLDAP::NG | OpenID Connect |
|
|
33
|
+
| ---------------------- | ------------- | ----------------- | ---------------------- | --------------------- | -------------------------------- |
|
|
34
|
+
| **Setup Complexity** | Simple | Simple | Medium | Medium | Medium |
|
|
35
|
+
| **User Management** | None | Manual | Manual (service-based) | External (LLNG) | External (Provider) |
|
|
36
|
+
| **SSO Support** | No | No | No | Yes | Yes |
|
|
37
|
+
| **MFA Support** | No | Yes (TOTP itself) | N/A | Yes (via LLNG) | Yes (via Provider) |
|
|
38
|
+
| **Session Management** | Stateless | Stateless | Stateless | LLNG Sessions | OIDC Sessions |
|
|
39
|
+
| **Code Expiration** | Never | 30-60 seconds | Per-request | Session-based | Session-based |
|
|
40
|
+
| **Request Integrity** | No | No | Yes (body + path hash) | No | No |
|
|
41
|
+
| **Replay Protection** | No | Yes (time-based) | Yes (timestamp) | Session-based | Session-based |
|
|
42
|
+
| **Best For** | APIs, Scripts | APIs, Enhanced | Backend Services | Enterprises with LLNG | Cloud/SaaS, Enterprises with SSO |
|
|
43
|
+
| **Dependencies** | None | None | None | lemonldap-ng-handler | express-openid-connect |
|
|
44
|
+
|
|
45
|
+
## Combining with Authorization
|
|
46
|
+
|
|
47
|
+
All authentication plugins set `req.user` to the authenticated identity. You can use hooks to implement custom authorization:
|
|
48
|
+
|
|
49
|
+
```javascript
|
|
50
|
+
hooks: {
|
|
51
|
+
afterAuth: async ([req, res]) => {
|
|
52
|
+
// Check if user can access this endpoint
|
|
53
|
+
if (req.path.startsWith('/api/v1/ldap/users') && !isAdmin(req.user)) {
|
|
54
|
+
throw new Error('Forbidden: Admin access required');
|
|
55
|
+
}
|
|
56
|
+
return [req, res];
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## See Also
|
|
62
|
+
|
|
63
|
+
- [LemonLDAP::NG Documentation](https://lemonldap-ng.org/documentation)
|
|
64
|
+
- [OpenID Connect Specification](https://openid.net/connect/)
|
|
65
|
+
- [express-openid-connect](https://github.com/auth0/express-openid-connect)
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# CrowdSec Integration
|
|
2
|
+
|
|
3
|
+
IP reputation and blocking using [CrowdSec](https://crowdsec.net/).
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
--plugin core/auth/crowdsec \
|
|
9
|
+
--crowdsec-url "http://localhost:8080" \
|
|
10
|
+
--crowdsec-api-key "your-api-key"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Environment Variables:**
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
DM_CROWDSEC_URL="http://localhost:8080"
|
|
17
|
+
DM_CROWDSEC_API_KEY="your-api-key"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
1. **CrowdSec Installation**: Running CrowdSec instance
|
|
23
|
+
2. **API Key**: Bouncer API key from CrowdSec
|
|
24
|
+
|
|
25
|
+
## How It Works
|
|
26
|
+
|
|
27
|
+
1. Extracts client IP from request (respects trusted proxy)
|
|
28
|
+
2. Queries CrowdSec API for IP reputation
|
|
29
|
+
3. Blocks requests from banned IPs with `403 Forbidden`
|
|
30
|
+
4. Allows legitimate requests to proceed
|
|
31
|
+
|
|
32
|
+
## Use Cases
|
|
33
|
+
|
|
34
|
+
- **IP Reputation**: Block known malicious IPs
|
|
35
|
+
- **Threat Intelligence**: Leverage community-shared threat data
|
|
36
|
+
- **Dynamic Blocking**: Automatic response to attacks
|
|
37
|
+
- **Compliance**: Security monitoring and logging
|
|
38
|
+
|
|
39
|
+
## CrowdSec Setup
|
|
40
|
+
|
|
41
|
+
### Install CrowdSec
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# Debian/Ubuntu
|
|
45
|
+
curl -s https://packagecloud.io/install/repositories/crowdsec/crowdsec/script.deb.sh | sudo bash
|
|
46
|
+
sudo apt install crowdsec
|
|
47
|
+
|
|
48
|
+
# Generate bouncer API key
|
|
49
|
+
sudo cscli bouncers add ldap-rest-bouncer
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Configure LDAP-Rest
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx ldap-rest \
|
|
56
|
+
--plugin core/auth/crowdsec \
|
|
57
|
+
--crowdsec-url "http://localhost:8080" \
|
|
58
|
+
--crowdsec-api-key "generated-api-key" \
|
|
59
|
+
...
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Combining with Other Security Plugins
|
|
63
|
+
|
|
64
|
+
Recommended security stack:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
--plugin core/auth/trustedProxy \
|
|
68
|
+
--trusted-proxy "127.0.0.1" \
|
|
69
|
+
--plugin core/auth/crowdsec \
|
|
70
|
+
--crowdsec-url "http://localhost:8080" \
|
|
71
|
+
--crowdsec-api-key "your-api-key" \
|
|
72
|
+
--plugin core/auth/rateLimit \
|
|
73
|
+
--rate-limit-max 100 \
|
|
74
|
+
--plugin core/auth/token \
|
|
75
|
+
--auth-token "your-token"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Order matters:
|
|
79
|
+
|
|
80
|
+
1. `trustedProxy` - Sanitize IP headers first
|
|
81
|
+
2. `crowdsec` - Block known bad IPs
|
|
82
|
+
3. `rateLimit` - Limit request frequency
|
|
83
|
+
4. Authentication plugins
|
|
84
|
+
|
|
85
|
+
## Security Considerations
|
|
86
|
+
|
|
87
|
+
- Keep CrowdSec updated for latest threat intelligence
|
|
88
|
+
- Monitor CrowdSec logs for blocked requests
|
|
89
|
+
- Consider local decisions for sensitive applications
|
|
90
|
+
- Use HTTPS between LDAP-Rest and CrowdSec API
|
|
91
|
+
|
|
92
|
+
## See Also
|
|
93
|
+
|
|
94
|
+
- [CrowdSec Documentation](https://docs.crowdsec.net/)
|
|
95
|
+
- [CrowdSec Hub](https://hub.crowdsec.net/)
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
# HMAC Authentication
|
|
2
|
+
|
|
3
|
+
HMAC-SHA256 request signing authentication for backend services (Registration Service, admin panel backend, cloudery, etc.).
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
### Basic Configuration
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
--plugin core/auth/hmac \
|
|
11
|
+
--auth-hmac "registration-service:secret-key-minimum-32-chars:Registration Service" \
|
|
12
|
+
--auth-hmac "cloudery:another-secret-key-long-enough:Cloudery Backend"
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**Environment Variable:**
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
DM_AUTH_HMAC="registration-service:secret-key-minimum-32-chars:Registration Service,cloudery:another-secret-key-long-enough:Cloudery Backend"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
**Syntax:** `service-id:secret:name`
|
|
22
|
+
|
|
23
|
+
- **service-id**: Service identifier (e.g., `registration-service`, `cloudery`)
|
|
24
|
+
- **secret**: Shared secret for HMAC (minimum 32 characters recommended)
|
|
25
|
+
- **name**: Descriptive service name (can contain colons)
|
|
26
|
+
|
|
27
|
+
### Advanced Configuration
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
--auth-hmac-window 120000 # Time window in milliseconds (default: 120000 = 2 minutes)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Environment Variable:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
DM_AUTH_HMAC_WINDOW=120000 # Default: 120000ms (2 minutes)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
- **window**: Maximum time difference (in milliseconds) between server and client timestamp
|
|
40
|
+
- Prevents replay attacks by rejecting requests with timestamps outside the window
|
|
41
|
+
|
|
42
|
+
## How It Works
|
|
43
|
+
|
|
44
|
+
### Request Signing Process
|
|
45
|
+
|
|
46
|
+
1. **Client calculates signature:**
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
signature = HMAC-SHA256(
|
|
50
|
+
secret,
|
|
51
|
+
"METHOD|PATH|timestamp|body-hash"
|
|
52
|
+
)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Where:
|
|
56
|
+
- `METHOD`: HTTP method (GET, POST, PATCH, DELETE, PUT, etc.)
|
|
57
|
+
- `PATH`: Request path with query string (e.g., `/api/v1/ldap/users?filter=active`)
|
|
58
|
+
- `timestamp`: Unix timestamp in milliseconds (e.g., `1698765432000`)
|
|
59
|
+
- `body-hash`: SHA256(request_body) for POST/PATCH/PUT, empty string for GET/DELETE/HEAD
|
|
60
|
+
|
|
61
|
+
2. **Client sends Authorization header:**
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
Authorization: HMAC-SHA256 service-id:timestamp:signature
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
3. **Server validates:**
|
|
68
|
+
- Extracts `service-id`, `timestamp`, and `signature` from header
|
|
69
|
+
- Verifies timestamp is within configured window (prevents replay attacks)
|
|
70
|
+
- Retrieves service secret using `service-id`
|
|
71
|
+
- Recalculates signature using same method
|
|
72
|
+
- Compares signatures using constant-time comparison (prevents timing attacks)
|
|
73
|
+
- Rejects if mismatch or timestamp expired
|
|
74
|
+
|
|
75
|
+
4. **On success:**
|
|
76
|
+
- Sets `req.user` to service name
|
|
77
|
+
- Allows request to proceed
|
|
78
|
+
|
|
79
|
+
## Usage
|
|
80
|
+
|
|
81
|
+
### Manual Request Example
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
# Example: GET request
|
|
85
|
+
SERVICE_ID="registration-service"
|
|
86
|
+
SECRET="secret-key-minimum-32-chars"
|
|
87
|
+
METHOD="GET"
|
|
88
|
+
PATH="/api/v1/ldap/users"
|
|
89
|
+
TIMESTAMP=$(date +%s000) # Unix timestamp in milliseconds
|
|
90
|
+
|
|
91
|
+
# Calculate body hash (empty for GET)
|
|
92
|
+
BODY_HASH=""
|
|
93
|
+
|
|
94
|
+
# Create signing string
|
|
95
|
+
SIGNING_STRING="${METHOD}|${PATH}|${TIMESTAMP}|${BODY_HASH}"
|
|
96
|
+
|
|
97
|
+
# Calculate HMAC-SHA256 signature
|
|
98
|
+
SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
|
|
99
|
+
|
|
100
|
+
# Make request
|
|
101
|
+
curl -H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:${SIGNATURE}" \
|
|
102
|
+
http://localhost:8081${PATH}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### POST Request with Body
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
SERVICE_ID="registration-service"
|
|
109
|
+
SECRET="secret-key-minimum-32-chars"
|
|
110
|
+
METHOD="POST"
|
|
111
|
+
PATH="/api/v1/ldap/users"
|
|
112
|
+
TIMESTAMP=$(date +%s000)
|
|
113
|
+
BODY='{"uid":"user1","mail":"user1@example.com"}'
|
|
114
|
+
|
|
115
|
+
# Calculate body hash
|
|
116
|
+
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 | cut -d' ' -f2)
|
|
117
|
+
|
|
118
|
+
# Create signing string
|
|
119
|
+
SIGNING_STRING="${METHOD}|${PATH}|${TIMESTAMP}|${BODY_HASH}"
|
|
120
|
+
|
|
121
|
+
# Calculate signature
|
|
122
|
+
SIGNATURE=$(echo -n "$SIGNING_STRING" | openssl dgst -sha256 -hmac "$SECRET" | cut -d' ' -f2)
|
|
123
|
+
|
|
124
|
+
# Make request
|
|
125
|
+
curl -X POST \
|
|
126
|
+
-H "Authorization: HMAC-SHA256 ${SERVICE_ID}:${TIMESTAMP}:${SIGNATURE}" \
|
|
127
|
+
-H "Content-Type: application/json" \
|
|
128
|
+
-d "$BODY" \
|
|
129
|
+
http://localhost:8081${PATH}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### Browser Client
|
|
133
|
+
|
|
134
|
+
The HMAC client library is available as an npm module export:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npm install ldap-rest
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
import { HmacAuthClient } from 'ldap-rest/browser-shared-utils-hmac';
|
|
142
|
+
|
|
143
|
+
const client = new HmacAuthClient({
|
|
144
|
+
serviceId: 'registration-service',
|
|
145
|
+
secret: 'secret-key-minimum-32-chars',
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Automatic authentication with HMAC signature
|
|
149
|
+
const response = await client.get('/api/v1/ldap/users');
|
|
150
|
+
const users = await response.json();
|
|
151
|
+
|
|
152
|
+
// POST with automatic body hashing and signing
|
|
153
|
+
await client.post('/api/v1/ldap/users', {
|
|
154
|
+
uid: 'user1',
|
|
155
|
+
mail: 'user1@example.com',
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Other methods: put, patch, delete
|
|
159
|
+
await client.put('/api/v1/ldap/users/user1', { mail: 'new@example.com' });
|
|
160
|
+
await client.delete('/api/v1/ldap/users/user1');
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Manual signature generation:**
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { generateHmacSignature } from 'ldap-rest/browser-shared-utils-hmac';
|
|
167
|
+
|
|
168
|
+
const signature = await generateHmacSignature(
|
|
169
|
+
'secret-key-minimum-32-chars',
|
|
170
|
+
'GET',
|
|
171
|
+
'/api/v1/ldap/users',
|
|
172
|
+
Date.now(),
|
|
173
|
+
undefined // no body for GET
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const authHeader = `HMAC-SHA256 registration-service:${Date.now()}:${signature}`;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Use Cases
|
|
180
|
+
|
|
181
|
+
- **Backend Services**: Service-to-service authentication (Registration Service, admin panels, etc.)
|
|
182
|
+
- **Microservices**: Secure inter-service communication
|
|
183
|
+
- **Webhooks**: Verify request authenticity and integrity
|
|
184
|
+
- **API Gateways**: Backend service authentication
|
|
185
|
+
- **Cloudery Integration**: Secure communication with cloudery backend
|
|
186
|
+
- **Automated Services**: CI/CD, monitoring, backup services
|
|
187
|
+
|
|
188
|
+
## Security Considerations
|
|
189
|
+
|
|
190
|
+
- **Secret Strength**: Use secrets of at least 32 characters (64+ recommended)
|
|
191
|
+
- **Secret Storage**: Store secrets securely (encrypted configuration, environment variables, secret managers)
|
|
192
|
+
- **HTTPS Required**: Always use HTTPS to protect signatures in transit
|
|
193
|
+
- **Time Synchronization**: Ensure server and client clocks are synchronized (NTP recommended)
|
|
194
|
+
- **Replay Protection**: Time window prevents replay attacks (adjust `auth-hmac-window` as needed)
|
|
195
|
+
- **Constant-Time Comparison**: Signature validation uses `timingSafeEqual` to prevent timing attacks
|
|
196
|
+
- **Secret Rotation**: Rotate secrets periodically for enhanced security
|
|
197
|
+
- **Body Integrity**: Body hash ensures request payload hasn't been tampered with
|
|
198
|
+
- **Path Integrity**: Full path (including query parameters) is signed
|
|
199
|
+
|
|
200
|
+
## Security Features
|
|
201
|
+
|
|
202
|
+
1. **Replay Attack Prevention**: Timestamp validation with configurable window
|
|
203
|
+
2. **Timing Attack Protection**: Constant-time signature comparison
|
|
204
|
+
3. **Request Integrity**: Body hash ensures payload integrity
|
|
205
|
+
4. **Path Integrity**: Query parameters included in signature
|
|
206
|
+
5. **Multi-Service Support**: Isolated secrets per service
|
|
207
|
+
6. **Clock Drift Tolerance**: Configurable time window (default 2 minutes)
|
|
208
|
+
|
|
209
|
+
## Advantages Over Other Methods
|
|
210
|
+
|
|
211
|
+
| Feature | HMAC | Token | TOTP |
|
|
212
|
+
| ------------------------- | ---------------- | ----------- | ---------------- |
|
|
213
|
+
| **Request Integrity** | Yes (body hash) | No | No |
|
|
214
|
+
| **Replay Protection** | Yes (timestamp) | No | Yes (time-based) |
|
|
215
|
+
| **Signature Per Request** | Yes | No (static) | Yes (30s codes) |
|
|
216
|
+
| **Body Tampering Detect** | Yes | No | No |
|
|
217
|
+
| **Path/Query Protection** | Yes | No | No |
|
|
218
|
+
| **Setup Complexity** | Medium | Simple | Simple |
|
|
219
|
+
| **Best For** | Backend services | Simple APIs | MFA, user auth |
|
|
220
|
+
|
|
221
|
+
## Comparison with Standards
|
|
222
|
+
|
|
223
|
+
This implementation is similar to:
|
|
224
|
+
|
|
225
|
+
- **AWS Signature V4**: Similar approach but simpler (AWS is more complex with canonicalization)
|
|
226
|
+
- **HTTP Message Signatures (RFC 9421)**: IETF standard for HTTP signatures
|
|
227
|
+
- **HMAC-Based Authentication**: Industry-standard pattern for service authentication
|
|
228
|
+
|
|
229
|
+
Our approach provides a good balance between security and simplicity:
|
|
230
|
+
|
|
231
|
+
- Simpler than AWS Signature V4 (easier to implement)
|
|
232
|
+
- More secure than static tokens (request-specific signatures)
|
|
233
|
+
- Better integrity than TOTP (includes body and path hashing)
|
|
234
|
+
- Standard cryptography (HMAC-SHA256)
|
|
235
|
+
|
|
236
|
+
## Troubleshooting
|
|
237
|
+
|
|
238
|
+
**Problem:** 401 Unauthorized despite correct signature
|
|
239
|
+
|
|
240
|
+
**Solutions:**
|
|
241
|
+
|
|
242
|
+
1. Verify service-id matches exactly (case-sensitive)
|
|
243
|
+
2. Verify secret is correctly configured (minimum 32 characters)
|
|
244
|
+
3. Check system clock synchronization (use NTP: `ntpdate -q pool.ntp.org`)
|
|
245
|
+
4. Increase `--auth-hmac-window` if experiencing timing issues
|
|
246
|
+
5. Verify Authorization header format: `HMAC-SHA256 service-id:timestamp:signature`
|
|
247
|
+
6. Check server logs for specific error messages
|
|
248
|
+
7. Ensure timestamp is in milliseconds, not seconds
|
|
249
|
+
8. Verify body hash calculation (must match exactly)
|
|
250
|
+
|
|
251
|
+
**Problem:** Timestamp outside allowed window
|
|
252
|
+
|
|
253
|
+
**Solutions:**
|
|
254
|
+
|
|
255
|
+
1. Synchronize clocks using NTP
|
|
256
|
+
2. Increase `--auth-hmac-window` (default: 120000ms = 2 minutes)
|
|
257
|
+
3. Check if timestamp is in milliseconds (not seconds)
|
|
258
|
+
4. Verify both server and client are using same timezone reference (UTC)
|
|
259
|
+
|
|
260
|
+
**Problem:** Signature mismatch
|
|
261
|
+
|
|
262
|
+
**Solutions:**
|
|
263
|
+
|
|
264
|
+
1. Verify signing string format: `METHOD|PATH|timestamp|body-hash`
|
|
265
|
+
2. Ensure METHOD is uppercase (GET, POST, etc.)
|
|
266
|
+
3. Include full path with query parameters
|
|
267
|
+
4. For POST/PATCH/PUT: verify body hash is SHA256(JSON.stringify(body))
|
|
268
|
+
5. For GET/DELETE/HEAD: body-hash must be empty string
|
|
269
|
+
6. Ensure secret is exactly the same on client and server
|
|
270
|
+
7. Use hex encoding for signature (lowercase)
|
|
271
|
+
8. Check for trailing whitespace in secret
|
|
272
|
+
|
|
273
|
+
**Problem:** Warning about short secrets
|
|
274
|
+
|
|
275
|
+
**Solutions:**
|
|
276
|
+
|
|
277
|
+
1. Use secrets of at least 32 characters
|
|
278
|
+
2. Recommended: 64+ characters for enhanced security
|
|
279
|
+
3. Generate secure random secrets:
|
|
280
|
+
```bash
|
|
281
|
+
openssl rand -hex 32 # 64-character hex string
|
|
282
|
+
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
**Debug Example:**
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# Enable debug logging
|
|
289
|
+
DM_LOG_LEVEL=debug npm start
|
|
290
|
+
|
|
291
|
+
# Check signing string in logs
|
|
292
|
+
# Expected format: "GET|/api/v1/ldap/users|1698765432000|"
|
|
293
|
+
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# LemonLDAP::NG Authentication
|
|
2
|
+
|
|
3
|
+
Integration with [LemonLDAP::NG](https://lemonldap-ng.org/) (LLNG) Web SSO solution.
|
|
4
|
+
|
|
5
|
+
## Configuration
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
--plugin core/auth/llng \
|
|
9
|
+
--llng-ini /etc/lemonldap-ng/lemonldap-ng.ini
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
**Environment Variable:**
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
DM_LLNG_INI="/etc/lemonldap-ng/lemonldap-ng.ini"
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
1. **LemonLDAP::NG Handler**: The `lemonldap-ng-handler` npm package (optional dependency)
|
|
21
|
+
2. **LLNG Configuration**: Valid `lemonldap-ng.ini` file
|
|
22
|
+
3. **Virtual Host Configuration**: LDAP-Rest must be configured as a protected application in LLNG
|
|
23
|
+
|
|
24
|
+
## How It Works
|
|
25
|
+
|
|
26
|
+
1. Uses the LemonLDAP::NG Handler to validate requests
|
|
27
|
+
2. Extracts user identity from `Lm-Remote-User` header
|
|
28
|
+
3. Sets `req.user` to authenticated username
|
|
29
|
+
4. Inherits all LLNG authorization rules and features
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
Install the optional dependency:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install lemonldap-ng-handler
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## LLNG Configuration
|
|
40
|
+
|
|
41
|
+
Configure LDAP-Rest as a protected virtual host in LemonLDAP::NG:
|
|
42
|
+
|
|
43
|
+
```apache
|
|
44
|
+
# In LLNG Manager: Virtual Hosts > api.example.com
|
|
45
|
+
<VirtualHost *:443>
|
|
46
|
+
ServerName api.example.com
|
|
47
|
+
|
|
48
|
+
# LemonLDAP::NG Handler
|
|
49
|
+
PerlHeaderParserHandler Lemonldap::NG::Handler::ApacheMP2
|
|
50
|
+
|
|
51
|
+
# Proxy to LDAP-Rest
|
|
52
|
+
ProxyPass / http://localhost:8081/
|
|
53
|
+
ProxyPassReverse / http://localhost:8081/
|
|
54
|
+
</VirtualHost>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Use Cases
|
|
58
|
+
|
|
59
|
+
- **Enterprise SSO**: Centralized authentication for multiple applications
|
|
60
|
+
- **Advanced Authorization**: Fine-grained access control using LLNG rules
|
|
61
|
+
- **Session Management**: Centralized session handling
|
|
62
|
+
- **Multi-Factor Authentication**: MFA support through LLNG
|
|
63
|
+
|
|
64
|
+
## Example: LLNG Authorization Rules
|
|
65
|
+
|
|
66
|
+
Configure access rules in LLNG Manager:
|
|
67
|
+
|
|
68
|
+
```perl
|
|
69
|
+
# Allow only HR group to access users endpoint
|
|
70
|
+
$groups =~ /\bhr\b/ and $uri =~ m#^/api/v1/ldap/users#
|
|
71
|
+
|
|
72
|
+
# Allow admins full access
|
|
73
|
+
$groups =~ /\badmins\b/
|
|
74
|
+
|
|
75
|
+
# Allow specific users to manage groups
|
|
76
|
+
$uid eq "groupmanager" and $uri =~ m#^/api/v1/ldap/groups#
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Troubleshooting
|
|
80
|
+
|
|
81
|
+
**Problem:** Handler not found
|
|
82
|
+
|
|
83
|
+
**Solution:** Install optional dependency:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
npm install lemonldap-ng-handler
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Problem:** Authentication refused
|
|
90
|
+
|
|
91
|
+
**Solutions:**
|
|
92
|
+
|
|
93
|
+
1. Verify LLNG handler is configured correctly
|
|
94
|
+
2. Check virtual host configuration
|
|
95
|
+
3. Review LLNG access logs
|
|
96
|
+
|
|
97
|
+
## See Also
|
|
98
|
+
|
|
99
|
+
- [LemonLDAP::NG Documentation](https://lemonldap-ng.org/documentation)
|