Compare commits
1 Commits
v1.4.0-alp
...
research/#
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
795798ee06 |
@@ -53,7 +53,6 @@ As an enhanced Identity service:
|
|||||||
- Central Matrix Identity servers
|
- Central Matrix Identity servers
|
||||||
- [Session Control](docs/threepids/session/session.md): Extensive control of where 3PIDs are transmitted so they are not
|
- [Session Control](docs/threepids/session/session.md): Extensive control of where 3PIDs are transmitted so they are not
|
||||||
leaked publicly by users
|
leaked publicly by users
|
||||||
- [Registration control](docs/features/registration.md): Control and restrict user registration based on 3PID patterns or criterias, like a pending invite
|
|
||||||
- [Authentication](docs/features/authentication.md): Use your Identity stores to perform authentication in [synapse](https://github.com/matrix-org/synapse)
|
- [Authentication](docs/features/authentication.md): Use your Identity stores to perform authentication in [synapse](https://github.com/matrix-org/synapse)
|
||||||
via the [REST password provider](https://github.com/kamax-io/matrix-synapse-rest-auth)
|
via the [REST password provider](https://github.com/kamax-io/matrix-synapse-rest-auth)
|
||||||
- [Directory search](docs/features/directory.md) which allows you to search for users within your organisation,
|
- [Directory search](docs/features/directory.md) which allows you to search for users within your organisation,
|
||||||
@@ -81,6 +80,8 @@ A basic troubleshooting guide is available [here](docs/troubleshooting.md).
|
|||||||
## Community
|
## Community
|
||||||
Over Matrix: [#mxisd:kamax.io](https://matrix.to/#/#mxisd:kamax.io) ([Preview](https://view.matrix.org/room/!NPRUEisLjcaMtHIzDr:kamax.io/))
|
Over Matrix: [#mxisd:kamax.io](https://matrix.to/#/#mxisd:kamax.io) ([Preview](https://view.matrix.org/room/!NPRUEisLjcaMtHIzDr:kamax.io/))
|
||||||
|
|
||||||
|
For more high-level discussion about the Identity Server architecture/API, go to [#matrix-identity:kamax.io](https://matrix.to/#/#matrix-identity:kamax.io)
|
||||||
|
|
||||||
## Commercial
|
## Commercial
|
||||||
If you would prefer professional support/custom development for mxisd and/or for Matrix in general, including other open
|
If you would prefer professional support/custom development for mxisd and/or for Matrix in general, including other open
|
||||||
source technologies/products:
|
source technologies/products:
|
||||||
|
|||||||
@@ -1,106 +1,25 @@
|
|||||||
# Application Service
|
# Integration as an Application Service
|
||||||
**WARNING:** These features are currently highly experimental. They can be removed or modified without notice.
|
**WARNING:** These features are currently highly experimental. They can be removed or modified without notice.
|
||||||
All the features requires a Homeserver capable of connecting [Application Services](https://matrix.org/docs/spec/application_service/r0.1.0.html).
|
All the features requires a Homeserver capable of connecting Application Services.
|
||||||
|
|
||||||
The following capabilities are provided in this feature:
|
## Email notification for Room invites by Matrix ID
|
||||||
- [Admin commands](#admin-commands)
|
|
||||||
- [Email Notification about room invites by Matrix IDs](#email-notification-about-room-invites-by-matrix-ids)
|
|
||||||
- [Auto-reject of expired 3PID invites](#auto-reject-of-expired-3pid-invites)
|
|
||||||
|
|
||||||
## Setup
|
|
||||||
> **NOTE:** Make sure you are familiar with [configuration format and rules](../../configure.md).
|
|
||||||
|
|
||||||
Integration as an Application service is a three steps process:
|
|
||||||
1. Create the baseline mxisd configuration to allow integration.
|
|
||||||
2. Integrate with the homeserver.
|
|
||||||
3. Configure the specific capabilities, if applicable.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
#### Variables
|
|
||||||
Under the `appsvc` namespace:
|
|
||||||
|
|
||||||
| Key | Type | Required | Default | Purpose |
|
|
||||||
|-----------------------|---------|----------|---------|----------------------------------------------------------------|
|
|
||||||
| `enabled` | boolean | No | `true` | Globally enable/disable the feature |
|
|
||||||
| `user.main` | string | No | `mxisd` | Localpart for the main appservice user |
|
|
||||||
| `endpoint.toHS.url` | string | Yes | *None* | Base URL to the Homeserver |
|
|
||||||
| `endpoint.toHS.token` | string | Yes | *None* | Token to use when sending requests to the Homeserver |
|
|
||||||
| `endpoint.toAS.url` | string | Yes | *None* | Base URL to mxisd from the Homeserver |
|
|
||||||
| `endpoint.toAS.token` | string | Yes | *None* | Token for the Homeserver to use when sending requests to mxisd |
|
|
||||||
|
|
||||||
#### Example
|
|
||||||
```yaml
|
|
||||||
appsvc:
|
|
||||||
endpoint:
|
|
||||||
toHS:
|
|
||||||
url: 'http://localhost:8008'
|
|
||||||
token: 'ExampleTokenToHS-ChangeMe!'
|
|
||||||
toAS:
|
|
||||||
url: 'http://localhost:8090'
|
|
||||||
token: 'ExampleTokenToAS-ChangeMe!'
|
|
||||||
```
|
|
||||||
### Integration
|
|
||||||
#### Synapse
|
|
||||||
Under the `appsvc.registration.synapse` namespace:
|
|
||||||
|
|
||||||
| Key | Type | Required | Default | Purpose |
|
|
||||||
|--------|--------|----------|--------------------|--------------------------------------------------------------------------|
|
|
||||||
| `id` | string | No | `appservice-mxisd` | The unique, user-defined ID of this application service. See spec. |
|
|
||||||
| `file` | string | Yes | *None* | If defined, the synapse registration file that should be created/updated |
|
|
||||||
|
|
||||||
##### Example
|
|
||||||
```yaml
|
|
||||||
appsvc:
|
|
||||||
registration:
|
|
||||||
synapse:
|
|
||||||
file: '/etc/matrix-synapse/mxisd-appservice-registration.yaml'
|
|
||||||
```
|
|
||||||
|
|
||||||
Edit your `homeserver.yaml` and add a new entry to the appservice config file, which should look something like this:
|
|
||||||
```yaml
|
|
||||||
app_service_config_files:
|
|
||||||
- '/etc/matrix-synapse/mxisd-appservice-registration.yaml'
|
|
||||||
- ...
|
|
||||||
```
|
|
||||||
|
|
||||||
Restart synapse when done to register mxisd.
|
|
||||||
|
|
||||||
#### Others
|
|
||||||
See your Homeserver documentation on how to integrate.
|
|
||||||
|
|
||||||
## Capabilities
|
|
||||||
### Admin commands
|
|
||||||
#### Setup
|
|
||||||
Min config:
|
|
||||||
```yaml
|
|
||||||
appsvc:
|
|
||||||
feature:
|
|
||||||
admin:
|
|
||||||
allowedRoles:
|
|
||||||
- '+aMatrixCommunity:example.org'
|
|
||||||
- 'SomeLdapGroup'
|
|
||||||
- 'AnyOtherArbitraryRoleFromIdentityStores'
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Use
|
|
||||||
The following steps assume:
|
|
||||||
- `matrix.domain` set to `example.org`
|
|
||||||
- `appsvc.user.main` set to `mxisd` or not set
|
|
||||||
|
|
||||||
1. Invite `@mxisd:example.org` to a new direct chat
|
|
||||||
2. Type `!help` to get all available commands
|
|
||||||
|
|
||||||
### Email Notification about room invites by Matrix IDs
|
|
||||||
This feature allows for users found in Identity stores to be instantly notified about Room Invites, regardless if their
|
This feature allows for users found in Identity stores to be instantly notified about Room Invites, regardless if their
|
||||||
account was already provisioned on the Homeserver.
|
account was already provisioned on the Homeserver.
|
||||||
|
|
||||||
#### Requirements
|
### Requirements
|
||||||
- [Identity store(s)](../../stores/README.md) supporting the Profile feature
|
- [Identity store(s)](../../stores/README.md) supporting the Profile feature
|
||||||
- At least one email entry in the identity store for each user that could be invited.
|
- At least one email entry in the identity store for each user that could be invited.
|
||||||
|
|
||||||
#### Configuration
|
### Configuration
|
||||||
In your mxisd config file:
|
In your mxisd config file:
|
||||||
```yaml
|
```yaml
|
||||||
|
matrix:
|
||||||
|
listener:
|
||||||
|
url: '<URL TO THE CS API OF THE HOMESERVER>'
|
||||||
|
localpart: 'appservice-mxisd'
|
||||||
|
token:
|
||||||
|
hs: 'HS_TOKEN_CHANGE_ME'
|
||||||
|
|
||||||
synapseSql:
|
synapseSql:
|
||||||
enabled: false ## Do not use this line if Synapse is used as an Identity Store
|
enabled: false ## Do not use this line if Synapse is used as an Identity Store
|
||||||
type: '<DB TYPE>'
|
type: '<DB TYPE>'
|
||||||
@@ -114,8 +33,40 @@ If you do not configure it, some placeholders will not be available in the notif
|
|||||||
You can also change the default template of the notification using the `generic.matrixId` template option.
|
You can also change the default template of the notification using the `generic.matrixId` template option.
|
||||||
See [the Template generator documentation](../../threepids/notification/template-generator.md) for more info.
|
See [the Template generator documentation](../../threepids/notification/template-generator.md) for more info.
|
||||||
|
|
||||||
#### Test
|
### Homeserver integration
|
||||||
Invite a user which is part of your domain while an appropriate Identity store is used.
|
#### Synapse
|
||||||
|
Create a new appservice registration file. Futher config will assume it is in `/etc/matrix-synapse/appservice-mxisd.yaml`
|
||||||
|
```yaml
|
||||||
|
id: "appservice-mxisd"
|
||||||
|
url: "http://127.0.0.1:8090"
|
||||||
|
as_token: "AS_TOKEN_CHANGE_ME"
|
||||||
|
hs_token: "HS_TOKEN_CHANGE_ME"
|
||||||
|
sender_localpart: "appservice-mxisd"
|
||||||
|
namespaces:
|
||||||
|
users:
|
||||||
|
- regex: "@*"
|
||||||
|
exclusive: false
|
||||||
|
aliases: []
|
||||||
|
rooms: []
|
||||||
|
```
|
||||||
|
`id`: An arbitrary unique string to identify the AS.
|
||||||
|
`url`: mxisd to reach mxisd. This ideally should be HTTP and not going through any reverse proxy.
|
||||||
|
`as_token`: Arbitrary value used by mxisd when talking to the HS. Not currently used.
|
||||||
|
`hs_token`: Arbitrary value used by synapse when talking to mxisd. Must match `token.hs` in mxisd config.
|
||||||
|
`sender_localpart`: Username for the mxisd itself on the HS. Default configuration should be kept.
|
||||||
|
`namespaces`: To be kept as is.
|
||||||
|
|
||||||
### Auto-reject of expired 3PID invites
|
Edit your `homeserver.yaml` and add a new entry to the appservice config file, which should look something like this:
|
||||||
*TBC*
|
```yaml
|
||||||
|
app_service_config_files:
|
||||||
|
- '/etc/matrix-synapse/appservice-mxisd.yaml'
|
||||||
|
- ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Restart synapse when done to register mxisd.
|
||||||
|
|
||||||
|
#### Others
|
||||||
|
See your Homeserver documentation on how to integrate.
|
||||||
|
|
||||||
|
### Test
|
||||||
|
Invite a user which is part of your domain while an appropriate Identity store is used.
|
||||||
|
|||||||
@@ -1,13 +1,6 @@
|
|||||||
# Identity
|
# Identity
|
||||||
Implementation of the [Identity Service API r0.1.0](https://matrix.org/docs/spec/identity_service/r0.1.0.html).
|
Implementation of the [Identity Service API r0.1.0](https://matrix.org/docs/spec/identity_service/r0.1.0.html).
|
||||||
|
|
||||||
- [Lookups](#lookups)
|
|
||||||
- [Invitations](#invitations)
|
|
||||||
- [Expiration](#expiration)
|
|
||||||
- [Policies](#policies)
|
|
||||||
- [Resolution](#resolution)
|
|
||||||
- [3PIDs Management](#3pids-management)
|
|
||||||
|
|
||||||
## Lookups
|
## Lookups
|
||||||
If you would like to use the central matrix.org Identity server to ensure maximum discovery at the cost of potentially
|
If you would like to use the central matrix.org Identity server to ensure maximum discovery at the cost of potentially
|
||||||
leaking all your contacts information, add the following to your configuration:
|
leaking all your contacts information, add the following to your configuration:
|
||||||
@@ -19,78 +12,8 @@ forward:
|
|||||||
**NOTE:** You should carefully consider enabling this option, which is discouraged.
|
**NOTE:** You should carefully consider enabling this option, which is discouraged.
|
||||||
For more info, see the [relevant issue](https://github.com/kamax-matrix/mxisd/issues/76).
|
For more info, see the [relevant issue](https://github.com/kamax-matrix/mxisd/issues/76).
|
||||||
|
|
||||||
## Invitations
|
## Room Invitations
|
||||||
### Expiration
|
Resolution can be customized using the following configuration:
|
||||||
#### Overview
|
|
||||||
Matrix does not provide a mean to remove/cancel pending 3PID invitations with the APIs. The current reference
|
|
||||||
implementations also do not provide any mean to do so. This leads to 3PID invites forever stuck in rooms.
|
|
||||||
|
|
||||||
To provide this functionality, mxisd uses a workaround: resolve the invite to a dedicated User ID, which can be
|
|
||||||
controlled by mxisd or a bot/service that will then reject the invite.
|
|
||||||
|
|
||||||
If this dedicated User ID is to be controlled by mxisd, the [Application Service](experimental/application-service.md)
|
|
||||||
feature must be configured and integrated with your Homeserver, as well as the *Auto-reject 3PID invite capability*.
|
|
||||||
|
|
||||||
#### Configuration
|
|
||||||
```yaml
|
|
||||||
invite:
|
|
||||||
expiration:
|
|
||||||
enabled: true/false
|
|
||||||
after: 5
|
|
||||||
resolveTo: '@john.doe:example.org'
|
|
||||||
```
|
|
||||||
`enabled`
|
|
||||||
- Purpose: Enable or disable the invite expiration feature.
|
|
||||||
- Default: `true`
|
|
||||||
|
|
||||||
`after`
|
|
||||||
- Purpose: Amount of minutes before an invitation expires.
|
|
||||||
- Default: `10080` (7 days)
|
|
||||||
|
|
||||||
`resolveTo`
|
|
||||||
- Purpose: Matrix User ID to resolve the expired invitations to.
|
|
||||||
- Default: Computed from `appsvc.user.inviteExpired` and `matrix.domain`
|
|
||||||
|
|
||||||
### Policies
|
|
||||||
3PID invite policies are the companion feature of [Registration](registration.md). While the Registration feature acts on
|
|
||||||
requirements for the invitee/register, this feature acts on requirement for the one(s) performing 3PID invites, ensuring
|
|
||||||
a coherent system.
|
|
||||||
|
|
||||||
It relies on only allowing people with specific [Roles](profile.md) to perform 3PID invites. This would typically allow
|
|
||||||
a tight-control on a server setup with is "invite-only" or semi-open (relying on trusted people to invite new members).
|
|
||||||
|
|
||||||
It's a middle ground between a closed server, where every user must be created or already exists in an Identity store,
|
|
||||||
and an open server, where anyone can register.
|
|
||||||
|
|
||||||
#### Integration
|
|
||||||
Because Identity Servers do not control 3PID invites as per Matrix spec, mxisd needs to intercept a set of Homeserver
|
|
||||||
endpoints to apply the policies.
|
|
||||||
|
|
||||||
##### Reverse Proxy
|
|
||||||
###### nginx
|
|
||||||
**IMPORTANT**: Must be placed before your global `/_matrix` entry:
|
|
||||||
```nginx
|
|
||||||
location ~* ^/_matrix/client/r0/rooms/([^/]+)/invite$ {
|
|
||||||
proxy_pass http://127.0.0.1:8090;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Configuration
|
|
||||||
The only policy currently available is to restrict 3PID invite to users having a specific (set of) role(s), like so:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
invite:
|
|
||||||
policy:
|
|
||||||
ifSender:
|
|
||||||
hasRole:
|
|
||||||
- '<THIS_ROLE>'
|
|
||||||
- '<OR_THIS_ROLE>'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Resolution
|
|
||||||
Resolution of 3PID invitations can be customized using the following configuration:
|
|
||||||
|
|
||||||
`invite.resolution.recursive`
|
`invite.resolution.recursive`
|
||||||
- Default value: `true`
|
- Default value: `true`
|
||||||
@@ -103,5 +26,5 @@ Resolution of 3PID invitations can be customized using the following configurati
|
|||||||
- Default value: `1`
|
- Default value: `1`
|
||||||
- Description: How often, in minutes, mxisd should try to resolve pending invites.
|
- Description: How often, in minutes, mxisd should try to resolve pending invites.
|
||||||
|
|
||||||
## 3PIDs Management
|
## 3PID addition to user profile
|
||||||
See the [3PID session documents](../threepids/session)
|
See the [3PID session documents](../threepids/session)
|
||||||
|
|||||||
@@ -1,111 +0,0 @@
|
|||||||
# Registration
|
|
||||||
- [Overview](#overview)
|
|
||||||
- [Integration](#integration)
|
|
||||||
- [Reverse Proxy](#reverse-proxy)
|
|
||||||
- [nginx](#nginx)
|
|
||||||
- [Apache](#apache)
|
|
||||||
- [Homeserver](#homeserver)
|
|
||||||
- [synapse](#synapse)
|
|
||||||
- [Configuration](#configuration)
|
|
||||||
- [Example](#example)
|
|
||||||
- [Usage](#usage)
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
**NOTE**: This feature is beta: it is considered stable enough for production but is incomplete and may contain bugs.
|
|
||||||
|
|
||||||
Registration is an enhanced feature of mxisd to control registrations involving 3PIDs on a Homeserver based on policies:
|
|
||||||
- Match pending 3PID invites on the server
|
|
||||||
- Match 3PID pattern, like a specific set of domains for emails
|
|
||||||
- In futher releases, use 3PIDs found in Identity stores
|
|
||||||
|
|
||||||
It aims to help open or invite-only registration servers control what is possible to do and ensure only approved people
|
|
||||||
can register on a given server in a implementation-agnostic manner.
|
|
||||||
|
|
||||||
**IMPORTANT:** This feature does not control registration in general. It only acts on endpoints related to 3PIDs during
|
|
||||||
the registration process.
|
|
||||||
As such, it relies on the homeserver to require 3PIDs with the registration flows.
|
|
||||||
|
|
||||||
This feature is not part of the Matrix Identity Server spec.
|
|
||||||
|
|
||||||
## Integration
|
|
||||||
mxisd needs to be integrated at several levels for this feature to work:
|
|
||||||
- Reverse proxy: intercept the 3PID register endpoints and act on them
|
|
||||||
- Homeserver: require 3PID to be part of the registration data
|
|
||||||
|
|
||||||
Later version(s) of this feature may directly control registration itself to create a coherent experience
|
|
||||||
### Reverse Proxy
|
|
||||||
#### nginx
|
|
||||||
```nginx
|
|
||||||
location ^/_matrix/client/r0/register/[^/]/?$ {
|
|
||||||
proxy_pass http://127.0.0.1:8090;
|
|
||||||
proxy_set_header Host $host;
|
|
||||||
proxy_set_header X-Forwarded-For $remote_addr;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### apache
|
|
||||||
> TBC
|
|
||||||
|
|
||||||
### Homeserver
|
|
||||||
#### Synapse
|
|
||||||
```yaml
|
|
||||||
enable_registration: true
|
|
||||||
registrations_require_3pid:
|
|
||||||
- email
|
|
||||||
```
|
|
||||||
|
|
||||||
## Configuration
|
|
||||||
See the [Configuration](../configuration.md) introduction doc on how to read the configuration keys.
|
|
||||||
An example of working configuration is avaiable at the end of this section.
|
|
||||||
### Enable/Disable
|
|
||||||
`register.allowed`, taking a boolean, can be used to enable/disable registration if the attempt is not 3PID-based.
|
|
||||||
`false` is the default value to prevent open registration, as you must allow it on the homeserver side.
|
|
||||||
|
|
||||||
### For invites
|
|
||||||
`register.invite`, taking a boolean, controls if registration can be made using a 3PID which matches a pending 3PID invite.
|
|
||||||
`true` is the default value.
|
|
||||||
|
|
||||||
### 3PID-specific
|
|
||||||
At this time, only `email` is supported with 3PID specific configuration with this feature.
|
|
||||||
|
|
||||||
#### Email
|
|
||||||
**Base key**: `register.threepid.email`
|
|
||||||
|
|
||||||
##### Domain whitelist/blacklist
|
|
||||||
If you would like to control which domains are allowed to be used when registrating with an email, the following sub-keys
|
|
||||||
are available:
|
|
||||||
- `domain.whitelist`
|
|
||||||
- `domain.blacklist`
|
|
||||||
|
|
||||||
The value format is an hybrid between glob patterns and postfix configuration files with the following syntax:
|
|
||||||
- `*<domain>` will match the domain and any sub-domain(s)
|
|
||||||
- `.<domain>` will only match sub-domain(s)
|
|
||||||
- `<domain>` will only match the exact domain
|
|
||||||
|
|
||||||
The following table illustrates pattern and maching status against example values:
|
|
||||||
|
|
||||||
| Config value | Matches `example.org` | Matches `sub.example.org` |
|
|
||||||
|--------------- |-----------------------|---------------------------|
|
|
||||||
| `*example.org` | Yes | Yes |
|
|
||||||
| `.example.org` | No | Yes |
|
|
||||||
| `example.org` | Yes | No |
|
|
||||||
|
|
||||||
### Example
|
|
||||||
For the following example configuration:
|
|
||||||
```yaml
|
|
||||||
register:
|
|
||||||
policy:
|
|
||||||
threepid:
|
|
||||||
email:
|
|
||||||
domain:
|
|
||||||
whitelist:
|
|
||||||
- '*example.org'
|
|
||||||
- '.example.net'
|
|
||||||
- 'example.com'
|
|
||||||
```
|
|
||||||
- Users can register using 3PIDs of pending invites, being allowed by default.
|
|
||||||
- Users can register using an email from `example.org` and any sub-domain, only sub-domains of `example.net` and `example.com` but not its sub-domains.
|
|
||||||
- Otherwise, user registration will be denied.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
Nothing special is needed. Register using a regular Matrix client.
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
# Synapse Identity Store
|
# Synapse Identity Store
|
||||||
Synapse's Database itself can be used as an Identity store. This identity store is a regular SQL store with
|
Synapse's Database itself can be used as an Identity store.
|
||||||
built-in default queries that matches Synapse DB.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
| Name | Supported |
|
| Name | Supported |
|
||||||
@@ -10,8 +9,7 @@ built-in default queries that matches Synapse DB.
|
|||||||
| [Identity](../features/identity.md) | Yes |
|
| [Identity](../features/identity.md) | Yes |
|
||||||
| [Profile](../features/profile.md) | Yes |
|
| [Profile](../features/profile.md) | Yes |
|
||||||
|
|
||||||
- Authentication is done by Synapse itself.
|
Authentication is done by Synapse itself.
|
||||||
- Roles are mapped to communities. The Role name/ID uses the community ID in the form `+id:domain.tld`
|
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
### Basic
|
### Basic
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ threepid:
|
|||||||
session:
|
session:
|
||||||
validation: '/path/to/validate-template.eml'
|
validation: '/path/to/validate-template.eml'
|
||||||
unbind:
|
unbind:
|
||||||
fraudulent: '/path/to/unbind-fraudulent-template.eml'
|
frandulent: '/path/to/unbind-fraudulent-template.eml'
|
||||||
generic:
|
generic:
|
||||||
matrixId: '/path/to/mxid-invite-template.eml'
|
matrixId: '/path/to/mxid-invite-template.eml'
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -3,7 +3,5 @@ Maintainer: Kamax.io <foss@kamax.io>
|
|||||||
Homepage: https://github.com/kamax-matrix/mxisd
|
Homepage: https://github.com/kamax-matrix/mxisd
|
||||||
Description: Federated Matrix Identity Server
|
Description: Federated Matrix Identity Server
|
||||||
Architecture: all
|
Architecture: all
|
||||||
Section: net
|
|
||||||
Priority: optional
|
|
||||||
Depends: openjdk-8-jre | openjdk-8-jre-headless | openjdk-8-jdk | openjdk-8-jdk-headless
|
Depends: openjdk-8-jre | openjdk-8-jre-headless | openjdk-8-jdk | openjdk-8-jdk-headless
|
||||||
Version: 0
|
Version: 0
|
||||||
|
|||||||
@@ -72,7 +72,11 @@ public abstract class LdapBackend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected synchronized LdapConnection getConn() {
|
protected synchronized LdapConnection getConn() {
|
||||||
return new LdapNetworkConnection(cfg.getConnection().getHost(), cfg.getConnection().getPort(), cfg.getConnection().isTls());
|
return getConn(cfg.getConnection().getHost());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized LdapConnection getConn(String host) {
|
||||||
|
return new LdapNetworkConnection(host, cfg.getConnection().getPort(), cfg.getConnection().isTls());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void bind(LdapConnection conn) throws LdapException {
|
protected void bind(LdapConnection conn) throws LdapException {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import io.kamax.mxisd.lookup.SingleLookupRequest;
|
|||||||
import io.kamax.mxisd.lookup.ThreePidMapping;
|
import io.kamax.mxisd.lookup.ThreePidMapping;
|
||||||
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
|
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
|
||||||
import io.kamax.mxisd.util.GsonUtil;
|
import io.kamax.mxisd.util.GsonUtil;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.directory.api.ldap.model.cursor.CursorException;
|
import org.apache.directory.api.ldap.model.cursor.CursorException;
|
||||||
import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
|
import org.apache.directory.api.ldap.model.cursor.CursorLdapReferralException;
|
||||||
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
|
import org.apache.directory.api.ldap.model.cursor.EntryCursor;
|
||||||
@@ -37,8 +38,10 @@ import org.apache.directory.api.ldap.model.message.SearchScope;
|
|||||||
import org.apache.directory.ldap.client.api.LdapConnection;
|
import org.apache.directory.ldap.client.api.LdapConnection;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.xbill.DNS.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@@ -91,7 +94,10 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
|
|||||||
return Optional.of(buildMatrixIdFromUid(data.get()));
|
return Optional.of(buildMatrixIdFromUid(data.get()));
|
||||||
}
|
}
|
||||||
} catch (CursorLdapReferralException e) {
|
} catch (CursorLdapReferralException e) {
|
||||||
log.warn("3PID {} is only available via referral, skipping", value);
|
log.info("Got referral info: {}", e.getReferralInfo());
|
||||||
|
|
||||||
|
return followReferral(medium, value, e.getReferralInfo());
|
||||||
|
//log.warn("3PID {} is only available via referral, skipping", value);
|
||||||
} catch (IOException | LdapException | CursorException e) {
|
} catch (IOException | LdapException | CursorException e) {
|
||||||
throw new InternalServerError(e);
|
throw new InternalServerError(e);
|
||||||
}
|
}
|
||||||
@@ -104,12 +110,50 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
|
|||||||
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
||||||
log.info("Performing LDAP lookup {} of type {}", request.getThreePid(), request.getType());
|
log.info("Performing LDAP lookup {} of type {}", request.getThreePid(), request.getType());
|
||||||
|
|
||||||
try (LdapConnection conn = getConn()) {
|
List<String> hosts = new ArrayList<>();
|
||||||
bind(conn);
|
|
||||||
return lookup(conn, request.getType(), request.getThreePid()).map(id -> new SingleLookupReply(request, id));
|
String domain = getCfg().getConnection().getDomain();
|
||||||
} catch (LdapException | IOException e) {
|
if (StringUtils.isNotBlank(domain)) {
|
||||||
throw new InternalServerError(e);
|
try {
|
||||||
|
Record[] records = new Lookup("_ldap._tcp.DomainDnsZones." + domain, Type.SRV).run();
|
||||||
|
if (records == null || records.length == 0) {
|
||||||
|
log.warn("No LDAP server found for domain {}", domain);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Record record : records) {
|
||||||
|
if (record instanceof SRVRecord) {
|
||||||
|
SRVRecord srvRec = (SRVRecord) record;
|
||||||
|
hosts.add(srvRec.getTarget().toString(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hosts.isEmpty()) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
} catch (TextParseException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
hosts.add(getCfg().getConnection().getHost());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (String host : hosts) {
|
||||||
|
log.info("Trying host {}", host);
|
||||||
|
try (LdapConnection conn = getConn(host)) {
|
||||||
|
bind(conn);
|
||||||
|
Optional<SingleLookupReply> reply = lookup(conn, request.getType(), request.getThreePid()).map(id -> new SingleLookupReply(request, id));
|
||||||
|
if (reply.isPresent()) return reply;
|
||||||
|
} catch (LdapException | IOException e) {
|
||||||
|
if (hosts.size() == 1) {
|
||||||
|
throw new InternalServerError(e);
|
||||||
|
} else {
|
||||||
|
log.warn("Unable to query {}: {}", host, e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -137,4 +181,51 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
|
|||||||
return mappingsFound;
|
return mappingsFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Optional<String> followReferral(String medium, String value, String ref) {
|
||||||
|
URI uri = URI.create(ref);
|
||||||
|
|
||||||
|
Optional<String> tPidQueryOpt = getCfg().getIdentity().getQuery(medium);
|
||||||
|
if (!tPidQueryOpt.isPresent()) {
|
||||||
|
log.warn("{} is not a configured 3PID type for LDAP lookup", medium);
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
LdapConnection conn = getConn(uri.getHost());
|
||||||
|
try {
|
||||||
|
bind(conn);
|
||||||
|
} catch (LdapException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we merge 3PID specific query with global/specific filter, if one exists.
|
||||||
|
String tPidQuery = tPidQueryOpt.get().replaceAll(getCfg().getIdentity().getToken(), value);
|
||||||
|
String searchQuery = buildWithFilter(tPidQuery, getCfg().getIdentity().getFilter());
|
||||||
|
log.debug("Query: {}", searchQuery);
|
||||||
|
log.debug("Attributes: {}", GsonUtil.build().toJson(getUidAtt()));
|
||||||
|
|
||||||
|
try (EntryCursor cursor = conn.search(uri.getPath().substring(1), searchQuery, SearchScope.SUBTREE, getUidAtt())) {
|
||||||
|
while (cursor.next()) {
|
||||||
|
Entry entry = cursor.get();
|
||||||
|
log.info("Found possible match, DN: {}", entry.getDn().getName());
|
||||||
|
|
||||||
|
Optional<String> data = getAttribute(entry, getUidAtt());
|
||||||
|
if (!data.isPresent()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("DN {} is a valid match", entry.getDn().getName());
|
||||||
|
return Optional.of(buildMatrixIdFromUid(data.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
} catch (CursorLdapReferralException e) {
|
||||||
|
log.info("Got referral info: {}", e.getReferralInfo());
|
||||||
|
|
||||||
|
return followReferral(medium, value, e.getReferralInfo());
|
||||||
|
//log.warn("3PID {} is only available via referral, skipping", value);
|
||||||
|
} catch (IOException | LdapException | CursorException e) {
|
||||||
|
throw new InternalServerError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public class InvitationConfig {
|
|||||||
public static class Expiration {
|
public static class Expiration {
|
||||||
|
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
private long after = 60 * 24 * 7; // One calendar week (60min/1h * 24 = 1d * 7 = 1w)
|
private long after;
|
||||||
private String resolveTo;
|
private String resolveTo;
|
||||||
|
|
||||||
public Boolean isEnabled() {
|
public Boolean isEnabled() {
|
||||||
|
|||||||
@@ -125,6 +125,7 @@ public abstract class LdapConfig {
|
|||||||
|
|
||||||
private boolean tls = false;
|
private boolean tls = false;
|
||||||
private String host;
|
private String host;
|
||||||
|
private String domain;
|
||||||
private int port = 389;
|
private int port = 389;
|
||||||
private String bindDn;
|
private String bindDn;
|
||||||
private String bindPassword;
|
private String bindPassword;
|
||||||
@@ -147,6 +148,14 @@ public abstract class LdapConfig {
|
|||||||
this.host = host;
|
this.host = host;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDomain() {
|
||||||
|
return domain;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDomain(String domain) {
|
||||||
|
this.domain = domain;
|
||||||
|
}
|
||||||
|
|
||||||
public int getPort() {
|
public int getPort() {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class GenericKeyIdentifier implements KeyIdentifier {
|
|||||||
|
|
||||||
public GenericKeyIdentifier(KeyType type, String algo, String serial) {
|
public GenericKeyIdentifier(KeyType type, String algo, String serial) {
|
||||||
if (StringUtils.isAnyBlank(algo, serial)) {
|
if (StringUtils.isAnyBlank(algo, serial)) {
|
||||||
throw new IllegalArgumentException("Algorithm and/or Serial cannot be blank");
|
throw new IllegalArgumentException("Aglorith and/or Serial cannot be blank");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.type = Objects.requireNonNull(type);
|
this.type = Objects.requireNonNull(type);
|
||||||
|
|||||||
@@ -172,6 +172,12 @@ public class InvitationManager {
|
|||||||
|
|
||||||
// Enabled by default
|
// Enabled by default
|
||||||
cfg.getInvite().getExpiration().setEnabled(true);
|
cfg.getInvite().getExpiration().setEnabled(true);
|
||||||
|
|
||||||
|
// We'll resolve to our computed User ID
|
||||||
|
cfg.getInvite().getExpiration().setResolveTo(mxId);
|
||||||
|
|
||||||
|
// One calendar week (60min/1h * 24 = 1d * 7 = 1w)
|
||||||
|
cfg.getInvite().getExpiration().setAfter(60 * 24 * 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cfg.getInvite().getExpiration().isEnabled()) {
|
if (cfg.getInvite().getExpiration().isEnabled()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user