Compare commits

...

38 Commits

Author SHA1 Message Date
Max Dor
3e240fe34d Improve fraudulent unbind notification 2019-02-01 15:41:44 +01:00
Max Dor
635f6fdbe7 Implementation for blocking fraudulent 3PID /unbind attempts 2019-02-01 02:34:52 +01:00
Max Dor
4237eeb3b6 Skeleton for blocking fraudulent 3PID /unbind attempts 2019-01-30 00:29:51 +01:00
Max Dor
a0e91e7896 Use proper return codes for session errors 2019-01-30 00:28:55 +01:00
Max Dor
aab0b86646 Talk about projects using mxisd under the hood 2019-01-23 18:50:00 +01:00
Max Dor
3e22301af7 Properly handle /v1/store-invite 2019-01-16 02:57:40 +01:00
Max Dor
2b202323c0 Catch and handle more exceptions in Base HTTP handler 2019-01-16 02:57:40 +01:00
Max Dor
4ec05f518e Properly handle v1 of 3pid/bind 2019-01-16 02:57:40 +01:00
Max Dor
6da68298b0 Fix invalid paths 2019-01-16 02:57:40 +01:00
Max Dor
aecaafdeca Set theme jekyll for github pages 2019-01-16 01:31:21 +01:00
Max Dor
d885932f45 Fix loading failures of JDBC drivers for SQL-based Identity stores 2019-01-15 06:22:03 +01:00
Max Dor
c689a3f161 Fix classpath resources config 2019-01-13 00:30:52 +01:00
Max Dor
7805112548 Fix #110 2019-01-11 23:07:58 +01:00
Max Dor
3e89f0bc5e Fix #109 2019-01-11 23:07:52 +01:00
Max Dor
c6b8f7d48e Better handle of File reading / Input Streams 2019-01-11 23:02:57 +01:00
Max Dor
83377ebee0 Protect against NPE 2019-01-11 22:08:35 +01:00
Max Dor
2aa6e4d142 Fix missing .html from Spring to Undertow port 2019-01-11 22:08:22 +01:00
Max Dor
82a1a3df68 Fix invalid parsing of 3PID medium configs 2019-01-11 21:44:51 +01:00
Max Dor
7ec11ba8cf Use NetIQ config for NetIQ identity store instead of generic LDAP one 2019-01-07 04:32:12 +01:00
Max Dor
9317c11434 Use sane handler for all endpoints 2019-01-07 04:25:29 +01:00
Max Dor
b257a0275f Properly handle signing Key ID format 2019-01-07 04:19:53 +01:00
Max Dor
2aaa04062f Fix tests 2019-01-07 03:13:12 +01:00
Max Dor
54c3014568 Port distributions and start scripts to Undertow 2019-01-07 03:01:46 +01:00
Max Dor
c3ca73f576 Port documentation about Thymeleaf 2019-01-07 03:01:46 +01:00
Max Dor
4185b644b7 Continue structural port from Spring Boot to Undertow
- Configuration options
- Configuration documentation
2019-01-07 03:01:46 +01:00
Max Dor
ace5918342 Continue structural port from Spring Boot to Undertow
- Notification template generator
- Add tests for email notification handler
2019-01-07 03:01:46 +01:00
Max Dor
7ad985fead Continue structural port from Spring Boot to Undertow 2019-01-07 03:01:46 +01:00
Max Dor
6a376db322 Formatting (no-op) 2019-01-07 03:01:46 +01:00
Max Dor
950f7c931c Be consistent about testing package 2019-01-07 03:01:46 +01:00
Max Dor
d160a44509 Port default configuration values 2019-01-07 03:01:46 +01:00
Max Dor
05493da27c Start structural port from Spring Boot to Undertow 2019-01-07 03:01:46 +01:00
Max Dor
df44428a85 Fix #106 2019-01-04 19:26:45 +01:00
Max Dor
e6f9c30611 Add support for multiple Base DNs in LDAP Identity Store (Fix #104) 2018-12-23 00:06:15 +01:00
Max Dor
06b2c787d3 Remove unused reference 2018-12-22 04:03:44 +01:00
Max Dor
5645f69208 Add better support for AS transactions (Fix #97)
- Process transactions async with completion parking
- Detect transactions deduplication
2018-12-22 03:52:02 +01:00
Max Dor
92cf5c6b21 Add support for Profile feature in REST Identity store (Fix #91) 2018-12-21 19:21:15 +01:00
Max Dor
ad1b91f370 Proper HTTP encoding for username rewrite 2018-12-21 16:48:29 +01:00
Max Dor
e9c29f1c03 Add support for username rewrite (Fix #103) 2018-12-21 14:22:51 +01:00
292 changed files with 7646 additions and 3503 deletions

1
.gitignore vendored
View File

@@ -7,6 +7,7 @@ out/
.idea/ .idea/
# Local dev config # Local dev config
/mxisd.yaml
/application.yaml /application.yaml
# Local dev storage # Local dev storage

View File

@@ -14,4 +14,5 @@ ENV SQLITE_DATABASE_PATH="/var/mxisd/mxisd.db"
CMD [ "/start.sh" ] CMD [ "/start.sh" ]
ADD src/docker/start.sh /start.sh ADD src/docker/start.sh /start.sh
ADD build/libs/mxisd.jar /mxisd.jar ADD src/script/mxisd /app/mxisd
ADD build/libs/mxisd.jar /app/mxisd.jar

View File

@@ -8,6 +8,7 @@ mxisd - Federated Matrix Identity Server
- [Getting Started](#getting-started) - [Getting Started](#getting-started)
- [Support](#support) - [Support](#support)
- [Contribute](#contribute) - [Contribute](#contribute)
- [Powered by mxisd](#powered-by-mxisd)
- [FAQ](#faq) - [FAQ](#faq)
- [Contact](#contact) - [Contact](#contact)
@@ -96,6 +97,11 @@ You can contribute as an organisation/corporation by:
maintained regularly and you get direct access to the support team. maintained regularly and you get direct access to the support team.
- Sponsoring new features or bug fixes. [Get in touch](#contact) so we can discuss it further. - Sponsoring new features or bug fixes. [Get in touch](#contact) so we can discuss it further.
# Powered by mxisd
The following projects use mxisd under the hood for some or all their features. Check them out!
- [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy)
- [matrix-register-bot](https://github.com/krombel/matrix-register-bot)
# FAQ # FAQ
See the [dedicated document](docs/faq.md) See the [dedicated document](docs/faq.md)

View File

@@ -21,9 +21,11 @@
import java.util.regex.Pattern import java.util.regex.Pattern
apply plugin: 'java' apply plugin: 'java'
apply plugin: 'org.springframework.boot' apply plugin: 'application'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'idea'
def confFileName = "application.example.yaml" def confFileName = "mxisd.example.yaml"
def distDir = "${project.buildDir}/dist" def distDir = "${project.buildDir}/dist"
def debBinPath = "/usr/lib/mxisd" def debBinPath = "/usr/lib/mxisd"
@@ -31,7 +33,8 @@ def debConfPath = "/etc/mxisd"
def debDataPath = "/var/lib/mxisd" def debDataPath = "/var/lib/mxisd"
def debSystemdPath = "/etc/systemd/system" def debSystemdPath = "/etc/systemd/system"
def debConfFileName = "mxisd-sample.yaml" def debConfFileName = confFileName
def debStartScriptFilename = "mxisd"
def debBuildBasePath = "${project.buildDir}/tmp/debian" def debBuildBasePath = "${project.buildDir}/tmp/debian"
def debBuildDebianPath = "${debBuildBasePath}/DEBIAN" def debBuildDebianPath = "${debBuildBasePath}/DEBIAN"
@@ -43,6 +46,9 @@ def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}"
def dockerImageName = "kamax/mxisd" def dockerImageName = "kamax/mxisd"
def dockerImageTag = "${dockerImageName}:${mxisdVersion()}" def dockerImageTag = "${dockerImageName}:${mxisdVersion()}"
group = 'io.kamax'
mainClassName = 'io.kamax.mxisd.MxisdStandaloneExec'
String mxisdVersion() { String mxisdVersion() {
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?") def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
@@ -59,38 +65,41 @@ String gitVersion() {
commandLine = ['git', 'describe', '--tags', '--always', '--dirty'] commandLine = ['git', 'describe', '--tags', '--always', '--dirty']
standardOutput = out standardOutput = out
} }
return out.toString().replace(System.lineSeparator(), ''); return out.toString().replace(System.lineSeparator(), '')
} }
buildscript { buildscript {
repositories { repositories {
mavenCentral() jcenter()
} }
dependencies { dependencies {
classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.5.3.RELEASE' classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.3'
} }
} }
repositories { repositories {
mavenCentral() jcenter()
maven { url "https://kamax.io/maven/releases/" } maven { url "https://kamax.io/maven/releases/" }
maven { url "https://kamax.io/maven/snapshots/" } maven { url "https://kamax.io/maven/snapshots/" }
} }
dependencies { dependencies {
// Logging
compile 'org.slf4j:slf4j-simple:1.7.25'
// Easy file management // Easy file management
compile 'commons-io:commons-io:2.5' compile 'commons-io:commons-io:2.5'
// Spring Boot - standalone app // Config management
compile 'org.springframework.boot:spring-boot-starter-web:1.5.10.RELEASE' compile 'org.yaml:snakeyaml:1.23'
// Thymeleaf for HTML templates
compile "org.springframework.boot:spring-boot-starter-thymeleaf:1.5.10.RELEASE"
// Matrix Java SDK // Matrix Java SDK
compile 'io.kamax:matrix-java-sdk:0.0.14-8-g0e57ec6' compile 'io.kamax:matrix-java-sdk:0.0.14-8-g0e57ec6'
// ORMLite
compile 'com.j256.ormlite:ormlite-jdbc:5.0'
// ed25519 handling // ed25519 handling
compile 'net.i2p.crypto:eddsa:0.1.0' compile 'net.i2p.crypto:eddsa:0.1.0'
@@ -107,15 +116,12 @@ dependencies {
compile 'com.googlecode.libphonenumber:libphonenumber:8.7.1' compile 'com.googlecode.libphonenumber:libphonenumber:8.7.1'
// E-mail sending // E-mail sending
compile 'com.sun.mail:javax.mail:1.6.2'
compile 'javax.mail:javax.mail-api:1.6.2' compile 'javax.mail:javax.mail-api:1.6.2'
compile 'com.sun.mail:javax.mail:1.6.2'
// Google Firebase Authentication backend // Google Firebase Authentication backend
compile 'com.google.firebase:firebase-admin:5.3.0' compile 'com.google.firebase:firebase-admin:5.3.0'
// ORMLite
compile 'com.j256.ormlite:ormlite-jdbc:5.0'
// Connection Pool // Connection Pool
compile 'com.mchange:c3p0:0.9.5.2' compile 'com.mchange:c3p0:0.9.5.2'
@@ -123,7 +129,7 @@ dependencies {
compile 'org.xerial:sqlite-jdbc:3.20.0' compile 'org.xerial:sqlite-jdbc:3.20.0'
// PostgreSQL // PostgreSQL
compile 'org.postgresql:postgresql:42.1.4' compile 'org.postgresql:postgresql:42.2.5'
// MariaDB/MySQL // MariaDB/MySQL
compile 'org.mariadb.jdbc:mariadb-java-client:2.1.2' compile 'org.mariadb.jdbc:mariadb-java-client:2.1.2'
@@ -137,36 +143,28 @@ dependencies {
// ZT-Exec for exec identity store // ZT-Exec for exec identity store
compile 'org.zeroturnaround:zt-exec:1.10' compile 'org.zeroturnaround:zt-exec:1.10'
// HTTP server
compile 'io.undertow:undertow-core:2.0.16.Final'
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
testCompile 'com.github.tomakehurst:wiremock:2.8.0' testCompile 'com.github.tomakehurst:wiremock:2.8.0'
testCompile 'com.unboundid:unboundid-ldapsdk:4.0.9'
testCompile 'com.icegreen:greenmail:1.5.9'
} }
springBoot { shadowJar {
executable = true baseName = project.name
classifier = null
embeddedLaunchScriptProperties = [ version = null
confFolder: "/etc/default"
]
} }
processResources { task debBuild(dependsOn: shadowJar) {
doLast { doLast {
copy { String debVersion = mxisdVersion()
from('build/resources/main/application.yaml') { println "Version for package: ${debVersion}"
rename 'application.yaml', 'mxisd.yaml'
}
into 'build/resources/main'
}
}
}
task buildDeb(dependsOn: build) {
doLast {
def v = mxisdVersion()
println "Version for package: ${v}"
mkdir distDir mkdir distDir
mkdir debBuildBasePath mkdir debBuildBasePath
mkdir "${debBuildBasePath}/DEBIAN" mkdir debBuildDebianPath
mkdir debBuildBinPath mkdir debBuildBinPath
mkdir debBuildConfPath mkdir debBuildConfPath
mkdir debBuildDataPath mkdir debBuildDataPath
@@ -177,10 +175,10 @@ task buildDeb(dependsOn: build) {
into debBuildBinPath into debBuildBinPath
} }
ant.chmod( copy {
file: "${debBuildBinPath}/mxisd.jar", from "${project.file("src/script/" + debStartScriptFilename)}"
perm: 'a+x' into debBuildBinPath
) }
copy { copy {
from(project.file(confFileName)) { from(project.file(confFileName)) {
@@ -189,16 +187,16 @@ task buildDeb(dependsOn: build) {
into debBuildConfPath into debBuildConfPath
} }
ant.replaceregexp( ant.replaceregexp( // FIXME adapt to new config format
file: "${debBuildConfPath}/${debConfFileName}", file: "${debBuildConfPath}/${debConfFileName}",
match: "key.path:(.*)", match: "key:\\R path:(.*)",
replace: "key.path: '${debDataPath}/signing.key'" replace: "key:\n path: '${debDataPath}/signing.key'"
) )
ant.replaceregexp( ant.replaceregexp( // FIXME adapt to new config format
file: "${debBuildConfPath}/${debConfFileName}", file: "${debBuildConfPath}/${debConfFileName}",
match: "storage.provider.sqlite.database:(.*)", match: "storage:\\R provider:\\R sqlite:\\R database:(.*)",
replace: "storage.provider.sqlite.database: '${debDataPath}/mxisd.db'" replace: "storage:\n provider:\n sqlite:\n database: '${debDataPath}/mxisd.db'"
) )
copy { copy {
@@ -209,7 +207,7 @@ task buildDeb(dependsOn: build) {
ant.replace( ant.replace(
file: "${debBuildDebianPath}/control", file: "${debBuildDebianPath}/control",
token: 'Version: 0', token: 'Version: 0',
value: "Version: ${v}" value: "Version: ${debVersion}"
) )
ant.replace( ant.replace(
@@ -245,7 +243,7 @@ task buildDeb(dependsOn: build) {
} }
} }
task dockerBuild(type: Exec, dependsOn: build) { task dockerBuild(type: Exec, dependsOn: shadowJar) {
commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir commandLine 'docker', 'build', '-t', dockerImageTag, project.rootDir
doLast { doLast {

View File

@@ -5,6 +5,7 @@
- Installation - Installation
- [Debian package](install/debian.md) - [Debian package](install/debian.md)
- [ArchLinux](install/archlinux.md) - [ArchLinux](install/archlinux.md)
- [NixOS](install/nixos.md)
- [Docker](install/docker.md) - [Docker](install/docker.md)
- [From source](install/source.md) - [From source](install/source.md)
- [Architecture overview](architecture.md) - [Architecture overview](architecture.md)

View File

@@ -1 +1 @@
theme: jekyll-theme-cayman theme: jekyll-theme-hacker

View File

@@ -17,9 +17,8 @@ cd mxisd
./gradlew build ./gradlew build
``` ```
Create a new configuration file by coping `application.example.yaml` to `application.yaml` and edit to your needs. Create a new configuration file by coping `mxisd.example.yaml` to `mxisd.yaml` and edit to your needs.
For advanced configuration, see the [Configure section](configure.md). For advanced configuration, see the [Configure section](configure.md).
**NOTE**: `application.yaml` is also called `mxisd.yaml` in some specific installations.
Start the server in foreground to validate the build and configuration: Start the server in foreground to validate the build and configuration:
```bash ```bash
@@ -29,12 +28,14 @@ java -jar build/libs/mxisd.jar
Ensure the signing key is available: Ensure the signing key is available:
```bash ```bash
$ curl 'http://localhost:8090/_matrix/identity/api/v1/pubkey/ed25519:0' $ curl 'http://localhost:8090/_matrix/identity/api/v1/pubkey/ed25519:0'
{"public_key":"..."} {"public_key":"..."}
``` ```
Test basic recursive lookup (requires Internet connection with access to TCP 443): Test basic recursive lookup (requires Internet connection with access to TCP 443):
```bash ```bash
$ curl 'http://localhost:8090/_matrix/identity/api/v1/lookup?medium=email&address=mxisd-federation-test@kamax.io' $ curl 'http://localhost:8090/_matrix/identity/api/v1/lookup?medium=email&address=mxisd-federation-test@kamax.io'
{"address":"mxisd-federation-test@kamax.io","medium":"email","mxid":"@mxisd-lookup-test:kamax.io",...} {"address":"mxisd-federation-test@kamax.io","medium":"email","mxid":"@mxisd-lookup-test:kamax.io",...}
``` ```
@@ -57,7 +58,7 @@ Requirements:
[Build mxisd](#build) then: [Build mxisd](#build) then:
```bash ```bash
./gradlew buildDeb ./gradlew debBuild
``` ```
You will find the debian package in `build/dist`. You will find the debian package in `build/dist`.
Then follow the instruction in the [Debian package](install/debian.md) document. Then follow the instruction in the [Debian package](install/debian.md) document.

View File

@@ -1,7 +1,6 @@
# Configuration # Configuration
- [Concepts](#concepts) - [Concepts](#concepts)
- [Syntax](#syntax) - [Syntax](#syntax)
- [Variables](#variables)
- [Matrix](#matrix) - [Matrix](#matrix)
- [Server](#server) - [Server](#server)
- [Storage](#storage) - [Storage](#storage)
@@ -11,36 +10,15 @@
## Concepts ## Concepts
### Syntax ### Syntax
The configuration file is [YAML](http://yaml.org/) based, allowing two types of syntax. The configuration file is [YAML](http://yaml.org/) based:
Properties-like:
```yaml
my.config.item: 'value'
```
Object-like:
```yaml ```yaml
my: my:
config: config:
item: 'value' item: 'value'
``` ```
These can also be combined within the same file.
Both syntax will be used interchangeably in these documents.
### Variables
It is possible to copy the value of a configuration item into another using the syntax `${config.key.item}`.
Example that will copy the value of `matrix.domain` into `server.name`:
```yaml
matrix:
domain: 'example.org'
server:
name: '${matrix.domain}'
```
**WARNING:** mxisd might overwrite/adapt some values during launch. Those changes will not be reflected into copied keys.
When referencing keys in all documents, a property-like shorthand will be used. The shorthand for the above example would be `my.config.item`
## Matrix ## Matrix
`matrix.domain` `matrix.domain`
@@ -53,7 +31,9 @@ Namespace to create arbitrary list of Identity servers, usable in other parts of
Example: Example:
```yaml ```yaml
matrix.identity.servers: matrix:
identity:
servers:
myOtherServers: myOtherServers:
- 'https://other1.example.org' - 'https://other1.example.org'
- 'https://other2.example.org' - 'https://other2.example.org'
@@ -82,19 +62,23 @@ See the dedicated documents:
Example: Example:
```yaml ```yaml
notification.handler.email: 'sendgrid' notification:
notification.handler.msisdn: 'raw' handler:
email: 'sendgrid'
msisdn: 'raw'
``` ```
- Emails notifications would use the `sendgrid` handler, which define its own configuration under `notification.handlers.sendgrid` - Emails notifications would use the `sendgrid` handler, which define its own configuration under `notification.handlers.sendgrid`
- Phone notification would use the `raw` handler, basic default built-in handler of mxisd - Phone notification would use the `raw` handler, basic default built-in handler in mxisd
### Handlers ### Handlers
- `notification.handers.<handler ID>`: Handler-specific configuration for the given handler ID. Repeatable. - `notification.handers.<handler ID>`: Handler-specific configuration for the given handler ID. Repeatable.
Example: Example:
```yaml ```yaml
notification.handlers.raw: ... notification:
notification.handlers.sendgrid: ... handlers:
raw: ...
sendgrid: ...
``` ```
Built-in: Built-in:

View File

@@ -74,7 +74,15 @@ See your Identity store [documentation](../stores/README.md) on how to enable th
## Advanced ## Advanced
The Authentication feature allows users to login to their Homeserver by using their 3PIDs in a configured Identity store. The Authentication feature allows users to:
- Rewrite usernames matching a pattern to be mapped to another username via a 3PID.
- login to their Homeserver by using their 3PIDs in a configured Identity store.
This feature also allows to work around the following issues:
- Lowercase all usernames for synapse, allowing case-insensitive login
- Unable to login on synapse if username is numerical
- Any generic transformation of username prior to sending to synapse, bypassing the restriction that password providers
cannot change the localpart being authenticated.
### Overview ### Overview
This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/login` as depicted below: This is performed by intercepting the Homeserver endpoint `/_matrix/client/r0/login` as depicted below:
@@ -109,10 +117,10 @@ Steps of user authentication using a 3PID:
4. The response from the Homeserver is sent back to the client, believing it was the HS which directly answered. 4. The response from the Homeserver is sent back to the client, believing it was the HS which directly answered.
### Requirements ### Requirements
- [Basic Authentication configured and working](#basic)
- Reverse proxy setup
- Homeserver
- Compatible [Identity store](../stores/README.md) - Compatible [Identity store](../stores/README.md)
- [Basic Authentication configured and working](#basic)
- Client and Homeserver using the [C2S API r0.4.x](https://matrix.org/docs/spec/client_server/r0.4.0.html) or later
- Reverse proxy setup
### Configuration ### Configuration
#### Reverse Proxy #### Reverse Proxy
@@ -143,7 +151,10 @@ the internal IP of the Homeserver so it can talk to it directly to integrate its
To do so, put the following configuration in your mxisd configuration: To do so, put the following configuration in your mxisd configuration:
```yaml ```yaml
dns.overwrite.homeserver.client: dns:
overwrite:
homeserver:
client:
- name: 'example.org' - name: 'example.org'
value: 'http://localhost:8008' value: 'http://localhost:8008'
``` ```
@@ -153,3 +164,40 @@ In case the hostname is the same as your Matrix domain and `server.name` is not
`matrix.domain` and will still probably have the correct value. `matrix.domain` and will still probably have the correct value.
`value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`. `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`.
#### Username rewrite
In mxisd config:
```yaml
auth:
rewrite:
user:
rules:
- regex: <your regexp>
medium: 'your.custom.medium.type'
```
`rules` takes a list of rules. Rules have two properties:
- `regexp`: The regex pattern to match. This **MUST** match the full string. See [Java regex](https://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) for syntax.
- `medium`: Custom 3PID type that will be used in the 3PID lookup. This can be anything you want and needs to be supported
by your Identity store config and/or code.
Rules are matched in listed order.
Common regexp patterns:
- Numerical usernames: `[0-9]+`
##### LDAP Example
If your users use their numerical employee IDs, which cannot be used with synapse, you can make it work with (relevant config only):
```yaml
auth:
rewrite:
user:
rules:
- regex: '[0-9]+'
medium: 'kmx.employee.id'
ldap:
attribute:
threepid:
kmx.employee.id:
- 'ldapAttributeForEmployeeId'
```

View File

@@ -5,15 +5,18 @@ to 3PID queries if no mapping was found, allowing seamless bridging to a network
This is performed by implementing a specific endpoint on the bridge to map a 3PID lookup to a virtual user. This is performed by implementing a specific endpoint on the bridge to map a 3PID lookup to a virtual user.
**NOTE**: This document is incomplete and might be misleading. In doubt, come in our Matrix room. **NOTE**: This document is incomplete and might be misleading. In doubt, come in our Matrix room.
You can also look at our [Email Bridge README](https://github.com/kamax-io/matrix-appservice-email#mxisd) for an example You can also look at our [Email Bridge README](https://github.com/kamax-matrix/matrix-appservice-email#mxisd) for an example
of working configuration. of working configuration.
## Configuration ## Configuration
```yaml ```yaml
lookup.recursive.bridge.enabled: <boolean> lookup:
lookup.recursive.bridge.recursiveOnly: <boolean> recursive:
lookup.recursive.bridge.server: <URL to the bridge endpoint for all 3PID medium> bridge:
lookup.recursive.bridge.mappings: enabled: <boolean>
recursiveOnly: <boolean>
server: <URL to the bridge endpoint for all 3PID medium>
mappings:
<3PID MEDIUM HERE>: <URL to dedicated bridge for that medium> <3PID MEDIUM HERE>: <URL to dedicated bridge for that medium>
``` ```

View File

@@ -123,27 +123,31 @@ the internal IP of the Homeserver so it can talk to it directly to integrate its
To do so, use the following configuration: To do so, use the following configuration:
```yaml ```yaml
dns.overwrite.homeserver.client: dns:
overwrite:
homeserver:
client:
- name: 'example.org' - name: 'example.org'
value: 'http://localhost:8008' value: 'http://localhost:8008'
``` ```
`name` must be the hostname of the URL that clients use when connecting to the Homeserver. - `name` must be the hostname of the URL that clients use when connecting to the Homeserver.
In case the hostname is the same as your Matrix domain, you can use `${matrix.domain}` to auto-populate the value using - `value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`.
the `matrix.domain` configuration option and avoid duplicating it.
`value` is the base internal URL of the Homeserver, without any `/_matrix/..` or trailing `/`.
## Next steps ## Next steps
### Homeserver results ### Homeserver results
You can configure if the Homeserver should be queried at all when doing a directory search. You can configure if the Homeserver should be queried at all when doing a directory search.
To disable Homeserver results, set the following in mxisd configuration file: To disable Homeserver results, set the following in mxisd configuration file:
```yaml ```yaml
directory.exclude.homeserver: true directory:
exclude:
homeserver: true
``` ```
### 3PID exclusion in search ### 3PID exclusion in search
You can configure if the 3PID should also be included when doing a directory search. You can configure if the 3PID should also be included when doing a directory search.
By default, a search is performed on the 3PIDs. If you would like to not include them: By default, a search is performed on the 3PIDs. If you would like to not include them:
```yaml ```yaml
directory.exclude.threepid: true directory:
exclude:
threepid: true
``` ```

View File

@@ -1,12 +1,16 @@
# Profile enhancement # Profile
**WARNING**: Alpha feature, not officially supported. Do not use. **WARNING**: The following sub-features are considered experimental and not officially supported. Use at your own peril.
This feature allows to enhance a profile query with more info than just Matrix ID and Display name, allowing for custom ## Public Profile enhancement
applications to retrieve custom data not currently provided by synapse, per example. This feature allows to enhance a public profile query with more info than just Matrix ID and Display name, allowing for
custom applications to retrieve custom data not currently provided by synapse, per example.
## Configuration **WARNING**: This information can be queried without authentication as per the specification. Do not enable unless in a
### Reverse proxy controlled environment.
#### Apache
### Configuration
#### Reverse proxy
##### Apache
```apache ```apache
ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)$" "http://127.0.0.1:8090/_matrix/client/r0/profile/$1" ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)$" "http://127.0.0.1:8090/_matrix/client/r0/profile/$1"
``` ```

View File

@@ -40,10 +40,21 @@ The port must be HTTPS capable which is what you get in a regular setup with a r
If you would like to disable outbound federation and isolate your identity server from the rest of the Matrix network, If you would like to disable outbound federation and isolate your identity server from the rest of the Matrix network,
use the following mxisd configuration options: use the following mxisd configuration options:
```yaml ```yaml
lookup.recursive.enabled: false lookup:
invite.resolution.recursive: false recursive:
session.policy.validation.forLocal.toRemote.enabled: false enabled: false
session.policy.validation.forRemote.toRemote.enabled: false invite:
resolution:
recursive: false
session:
policy:
validation:
forLocal:
toRemote:
enabled: false
forRemote:
toRemote:
enabled: false
``` ```
There is currently no way to selectively disable federation towards specific servers, but this feature is planned. There is currently no way to selectively disable federation towards specific servers, but this feature is planned.

View File

@@ -7,7 +7,8 @@ Implementation of the [Unofficial Matrix Identity Service API](https://kamax.io/
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:
```yaml ```yaml
forward.servers: forward:
servers:
- 'matrix-org' - 'matrix-org'
``` ```
**NOTE:** You should carefully consider enabling this option, which is discouraged. **NOTE:** You should carefully consider enabling this option, which is discouraged.

10
docs/features/profile.md Normal file
View File

@@ -0,0 +1,10 @@
# Profile
The profile feature does not do anything on its own and acts as a support feature for others, allowing to retrieve
information about a user based on its Matrix ID by querying enabled [Identity stores](../stores/README.md).
Currently supported:
- Display name
- 3PIDs
- Roles/Groups
Experimental sub-features are also available. See [the dedicated document](experimental/profile.md).

View File

@@ -10,6 +10,15 @@ Following these quick start instructions, you will have a basic setup that can p
talk to the central Matrix.org Identity server. talk to the central Matrix.org Identity server.
This will be a good ground work for further integration with features and your existing Identity stores. This will be a good ground work for further integration with features and your existing Identity stores.
---
If you would like a more fully integrated setup out of the box, the [matrix-docker-ansible-deploy](https://github.com/spantaleev/matrix-docker-ansible-deploy)
project provides a turn-key full-stack solution, including LDAP and the various mxisd features enabled and ready.
We work closely with the project owner so the latest mxisd version is always supported.
If you choose to use it, this Getting Started guide is not applicable - See the project documentation. You may then
directly go to the [Next steps](#next-steps).
## Preparation ## Preparation
You will need: You will need:
- Working Homeserver, ideally with working federation - Working Homeserver, ideally with working federation
@@ -38,13 +47,20 @@ Install via:
See the [Latest release](https://github.com/kamax-matrix/mxisd/releases/latest) for links to each. See the [Latest release](https://github.com/kamax-matrix/mxisd/releases/latest) for links to each.
## Configure ## Configure
**NOTE**: please view the install instruction for your platform, as this step might be optional or already handled for you. > **NOTE**: Please view the install instruction for your platform, as this step might be optional or already handled for you.
> **NOTE**: Details about configuration syntax and format are described [here](configure.md)
Create/edit a minimal configuration (see installer doc for the location): Create/edit a minimal configuration (see installer doc for the location):
```yaml ```yaml
matrix.domain: 'example.org' matrix:
key.path: '/path/to/signing.key.file' domain: 'example.org'
storage.provider.sqlite.database: '/path/to/mxisd.db' key:
path: '/path/to/signing.key.file'
storage:
provider:
sqlite:
database: '/path/to/mxisd.db'
``` ```
- `matrix.domain` should be set to your Homeserver domain (`server_name` in synapse configuration) - `matrix.domain` should be set to your Homeserver domain (`server_name` in synapse configuration)
- `key.path` will store the signing keys, which must be kept safe! If the file does not exist, keys will be generated for you. - `key.path` will store the signing keys, which must be kept safe! If the file does not exist, keys will be generated for you.

View File

@@ -2,37 +2,43 @@
## Instructions ## Instructions
Follow the [build instructions](../build.md) then: Follow the [build instructions](../build.md) then:
1. Prepare files and directories: ### Prepare files and directories:
```bash ```bash
# Create a dedicated user # Create a dedicated user
useradd -r mxisd useradd -r mxisd
# Create bin directory
mkdir /opt/mxisd
# Create config directory and set ownership # Create config directory and set ownership
mkdir -p /etc/opt/mxisd mkdir -p /etc/mxisd
chown -R mxisd /etc/opt/mxisd
# Create data directory and set ownership # Create data directory and set ownership
mkdir -p /var/opt/mxisd mkdir -p /var/lib/mxisd
chown -R mxisd /var/opt/mxisd chown -R mxisd /var/lib/mxisd
# Copy <repo root>/build/libs/mxisd.jar to bin directory # Create bin directory, copy the jar and launch scriot to bin directory
cp ./build/libs/mxisd.jar /opt/mxisd/ mkdir /usr/lib/mxisd
chown mxisd /opt/mxisd/mxisd.jar cp ./build/libs/mxisd.jar /usr/lib/mxisd/
chmod a+x /opt/mxisd/mxisd.jar cp ./src/script/mxisd /usr/lib/mxisd
chown -R mxisd /usr/lib/mxisd
chmod a+x /usr/lib/mxisd/mxisd
# Create symlink for easy exec # Create symlink for easy exec
ln -s /opt/mxisd/mxisd.jar /usr/bin/mxisd ln -s /usr/lib/mxisd/mxisd /usr/bin/mxisd
``` ```
2. Copy the sample config file `./application.example.yaml` to `/etc/opt/mxisd/mxisd.yaml`, edit to your needs
3. Copy `src/systemd/mxisd.service` to `/etc/systemd/system/` and edit if needed ### Prepare config file
4. Enable service for auto-startup Copy the sample config file `./mxisd.example.yaml` to `/etc/mxisd/mxisd.yaml`, edit to your needs
### Prepare Systemd
1. Copy `src/systemd/mxisd.service` to `/etc/systemd/system/` and edit if needed
2. Enable service for auto-startup
```bash ```bash
systemctl enable mxisd systemctl enable mxisd
``` ```
5. Start mxisd
### Run
```bash ```bash
systemctl start mxisd systemctl start mxisd
``` ```
## Debug
mxisd logs to stdout, which is normally sent to `/var/log/syslog` or `/var/log/messages`.

View File

@@ -68,7 +68,8 @@ We will use the term `Executable` for each lookup/action and `Processor` for eac
### Global ### Global
```yaml ```yaml
exec.enabled: <boolean> exec:
enabled: <boolean>
``` ```
Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled. Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled.
@@ -79,7 +80,9 @@ Not all features use all tokens, and each feature might also have its own specif
They can be set within the following scope: They can be set within the following scope:
```yaml ```yaml
exec.token.<token>: '<value>' exec:
token:
<token>: '<value>'
``` ```
--- ---
@@ -184,12 +187,15 @@ The following types are available:
### Examples ### Examples
#### Basic #### Basic
```yaml ```yaml
exec.auth.enabled: true exec:
exec.auth.command: '/opt/mxisd-exec/auth.sh' auth:
exec.auth.args: ['{localpart}'] enabled: true
exec.auth.input.type: 'plain' command: '/opt/mxisd-exec/auth.sh'
exec.auth.input.template: '{password}' args: ['{localpart}']
exec.auth.env: input:
type: 'plain'
template: '{password}'
env:
DOMAIN: '{domain}' DOMAIN: '{domain}'
``` ```
With Authentication enabled, run `/opt/mxisd-exec/auth.sh` when validating credentials, providing: With Authentication enabled, run `/opt/mxisd-exec/auth.sh` when validating credentials, providing:
@@ -243,14 +249,17 @@ See each dedicated [Feature](#features) section.
## Authentication ## Authentication
The Authentication feature can be enabled/disabled using: The Authentication feature can be enabled/disabled using:
```yaml ```yaml
exec.auth.enabled: <true/false> exec:
auth:
enabled: <true/false>
``` ```
--- ---
This feature provides a single *Executable* under the namespace: This feature provides a single *Executable* under the namespace:
```yaml ```yaml
exec.auth: exec:
auth:
... ...
``` ```
@@ -294,7 +303,9 @@ Default template:
## Directory ## Directory
The Directory feature can be enabled/disabled using: The Directory feature can be enabled/disabled using:
```yaml ```yaml
exec.directory.enabled: <true/false> exec:
directory:
enabled: <true/false>
``` ```
--- ---
@@ -303,12 +314,18 @@ Two search types configuration namespace are available, using the same input/out
By name: By name:
```yaml ```yaml
exec.directory.search.byName: exec:
directory:
search:
byName:
... ...
``` ```
By 3PID: By 3PID:
```yaml ```yaml
exec.directory.search.byThreepid: exec:
directory:
search:
byThreepid:
... ...
``` ```
@@ -386,7 +403,10 @@ The User ID type will default to `localpart` if:
### Bulk lookup ### Bulk lookup
Configuration namespace: Configuration namespace:
```yaml ```yaml
exec.identity.lookup.bulk: exec:
identity:
lookup:
bulk:
... ...
``` ```
@@ -418,7 +438,9 @@ Same as the [REST Identity Store](rest.md).
## Profile ## Profile
The Profile feature can be enabled/disabled using: The Profile feature can be enabled/disabled using:
```yaml ```yaml
exec.profile.enabled: <true/false> exec:
profile:
enabled: <true/false>
``` ```
--- ---
@@ -427,19 +449,25 @@ The following *Executable*s namespace are available, share the same input/output
Get Display name: Get Display name:
```yaml ```yaml
exec.profile.displayName: exec:
profile:
displayName:
... ...
``` ```
Get 3PIDs: Get 3PIDs:
```yaml ```yaml
exec.profile.threePid: exec:
profile:
threePid:
... ...
``` ```
Get Roles: Get Roles:
```yaml ```yaml
exec.profile.role: exec:
profile:
role:
... ...
``` ```

View File

@@ -19,35 +19,41 @@ If your client is Riot, you will need a custom version.
## Configuration ## Configuration
```yaml ```yaml
firebase.enabled: <boolean> firebase:
enabled: <boolean>
``` ```
Enable/disable this identity store. Enable/disable this identity store.
Example: Example:
```yaml ```yaml
firebase.enabled: <boolean> firebase:
enabled: <boolean>
``` ```
--- ---
```yaml ```yaml
firebase.credentials: <string> firebase:
credentials: <string>
``` ```
Path to the credentials file provided by Google Firebase to use with an external app. Path to the credentials file provided by Google Firebase to use with an external app.
Example: Example:
```yaml ```yaml
firebase.credentials: '/path/to/firebase/credentials.json' firebase:
credentials: '/path/to/firebase/credentials.json'
``` ```
--- ---
```yaml ```yaml
firebase.database: <string> firebase:
database: <string>
``` ```
URL to your Firebase database. URL to your Firebase database.
Example: Example:
```yaml ```yaml
firebase.database: 'https://my-project.firebaseio.com/' firebase:
database: 'https://my-project.firebaseio.com/'
``` ```

View File

@@ -19,26 +19,34 @@ For NetIQ, replace all the `ldap` prefix in the configuration by `netiq`.
### Base ### Base
To use your LDAP backend, add the bare minimum configuration in mxisd config file: To use your LDAP backend, add the bare minimum configuration in mxisd config file:
```yaml ```yaml
ldap.enabled: true ldap:
ldap.connection.host: 'ldapHostnameOrIp' enabled: true
ldap.connection.port: 389 connection:
ldap.connection.bindDn: 'CN=My Mxisd User,OU=Users,DC=example,DC=org' host: 'ldapHostnameOrIp'
ldap.connection.bindPassword: 'TheUserPassword' port: 389
ldap.connection.baseDn: 'OU=Users,DC=example,DC=org' bindDn: 'CN=My Mxisd User,OU=Users,DC=example,DC=org'
bindPassword: 'TheUserPassword'
baseDNs:
- 'OU=Users,DC=example,DC=org'
``` ```
These are standard LDAP connection configuration. mxisd will try to connect on port default port 389 without encryption. These are standard LDAP connection configuration. mxisd will try to connect on port default port 389 without encryption.
If you would like to use several Base DNs, simply add more entries under `baseDNs`.
### TLS/SSL connection ### TLS/SSL connection
If you would like to use a TLS/SSL connection, use the following configuration options (STARTLS not supported): If you would like to use a TLS/SSL connection, use the following configuration options (STARTLS not supported):
```yaml ```yaml
ldap.connection.tls: true ldap:
ldap.connection.port: 12345 connection:
tls: true
port: 12345
``` ```
### Filter results ### Filter results
You can also set a default global filter on any LDAP queries: You can also set a default global filter on any LDAP queries:
```yaml ```yaml
ldap.filter: '(memberOf=CN=My Matrix Users,OU=Groups,DC=example,DC=org)' ldap:
filter: '(memberOf=CN=My Matrix Users,OU=Groups,DC=example,DC=org)'
``` ```
This example would only return users part of the group called `My Matrix Users`. This example would only return users part of the group called `My Matrix Users`.
This can be overwritten or append in each specific flow describe below. This can be overwritten or append in each specific flow describe below.
@@ -61,8 +69,11 @@ most certainly configure those mappings.
The following example would set the `sAMAccountName` attribute as a Matrix User ID localpart: The following example would set the `sAMAccountName` attribute as a Matrix User ID localpart:
```yaml ```yaml
ldap.attribute.uid.type: 'uid' ldap:
ldap.attribute.uid.value: 'sAMAccountName' attribute:
uid:
type: 'uid'
value: 'sAMAccountName'
``` ```
#### Display name #### Display name
@@ -70,7 +81,9 @@ Use `ldap.attribute.name`.
The following example would set the display name to the value of the `cn` attribute: The following example would set the display name to the value of the `cn` attribute:
```yaml ```yaml
ldap.attribute.name: 'cn' ldap:
attribute:
name: 'cn'
``` ```
#### 3PIDs #### 3PIDs
@@ -79,11 +92,13 @@ You can also change the attribute lists for 3PID, like email or phone numbers.
The following example would overwrite the [default list of attributes](../../src/main/resources/application.yaml#L67) The following example would overwrite the [default list of attributes](../../src/main/resources/application.yaml#L67)
for emails and phone number: for emails and phone number:
```yaml ```yaml
ldap.attribute.threepid.email: ldap:
attribute:
threepid:
email:
- 'mail' - 'mail'
- 'otherMailAttribute' - 'otherMailAttribute'
msisdn:
ldap.attribute.threepid.msisdn:
- 'phone' - 'phone'
- 'otherPhoneAttribute' - 'otherPhoneAttribute'
``` ```
@@ -114,7 +129,10 @@ To set a specific filter applied during directory search, use `ldap.directory.fi
If you would like to use extra attributes in search that are not 3PIDs, like nicknames, group names, employee number: If you would like to use extra attributes in search that are not 3PIDs, like nicknames, group names, employee number:
```yaml ```yaml
ldap.directory.attribute.other: ldap:
directory:
attribute:
other:
- 'myNicknameAttribute' - 'myNicknameAttribute'
- 'memberOf' - 'memberOf'
- 'employeeNumberAttribute' - 'employeeNumberAttribute'

View File

@@ -3,38 +3,45 @@ The REST backend allows you to query identity data in existing webapps, like:
- Forums (phpBB, Discourse, etc.) - Forums (phpBB, Discourse, etc.)
- Custom Identity stores (Keycloak, ...) - Custom Identity stores (Keycloak, ...)
- CRMs (Wordpress, ...) - CRMs (Wordpress, ...)
- self-hosted clouds (Nextcloud, ownCloud, ...) - Self-hosted clouds (Nextcloud, ownCloud, ...)
To integrate this backend with your webapp, you will need to implement three specific REST endpoints detailed below. To integrate this backend with your webapp, you will need to implement the REST endpoints described below.
## Features ## Features
| Name | Supported? | | Name | Supported? |
|----------------|------------| |-------------------------------------------------|------------|
| Authentication | Yes | | [Authentication](../features/authentication.md) | Yes |
| Directory | Yes | | [Directory](../features/directory.md) | Yes |
| Identity | Yes | | [Identity](../features/identity.md) | Yes |
| Profile | No | | [Profile](../features/profile.md) | Yes |
## Configuration ## Configuration
| Key | Default | Description | | Key | Default | Description |
|----------------------------------|------------------------------------------------|------------------------------------------------------| |--------------------------------------|------------------------------------------------|------------------------------------------------------|
| `rest.enabled` | `false` | Globally enable/disable the REST backend | | `rest.enabled` | `false` | Globally enable/disable the REST backend |
| `rest.host` | *None* | Default base URL to use for the different endpoints. | | `rest.host` | *None* | Default base URL to use for the different endpoints. |
| `rest.endpoints.auth` | `/_mxisd/backend/api/v1/auth/login` | Validate credentials and get user profile | | `rest.endpoints.auth` | `/_mxisd/backend/api/v1/auth/login` | Validate credentials and get user profile |
| `rest.endpoints.directory` | `/_mxisd/backend/api/v1/directory/user/search` | Search for users by arbitrary input | | `rest.endpoints.directory` | `/_mxisd/backend/api/v1/directory/user/search` | Search for users by arbitrary input |
| `rest.endpoints.identity.single` | `/_mxisd/backend/api/v1/identity/single` | Endpoint to query a single 3PID | | `rest.endpoints.identity.single` | `/_mxisd/backend/api/v1/identity/single` | Endpoint to query a single 3PID |
| `rest.endpoints.identity.bulk` | `/_mxisd/backend/api/v1/identity/bulk` | Endpoint to query a list of 3PID | | `rest.endpoints.identity.bulk` | `/_mxisd/backend/api/v1/identity/bulk` | Endpoint to query a list of 3PID |
| `rest.endpoints.profile.displayName` | `/_mxisd/backend/api/v1/profile/displayName` | Query the display name for a Matrix ID
| `rest.endpoints.profile.threepids` | `/_mxisd/backend/api/v1/profile/threepids` | Query the 3PIDs for a Matrix ID
| `rest.endpoints.profile.roles` | `/_mxisd/backend/api/v1/profile/roles` | Query the Roles for a Matrix ID
Endpoint values can handle two formats: Endpoint values can handle two formats:
- URL Path starting with `/` that gets happened to the `rest.host` - URL Path starting with `/` that gets happened to the `rest.host`
- Full URL, if you want each endpoint to go to a specific server/protocol/port - Full URL, if you want each endpoint to go to a specific server/protocol/port
If an endpoint value is configured as an empty string, it will disable that specific feature, essentially bypassing the
Identity store for that specific query.
`rest.host` is mandatory if at least one endpoint is not a full URL. `rest.host` is mandatory if at least one endpoint is not a full URL.
## Endpoints ## Endpoints
### Authentication ### Authentication
HTTP method: `POST` - Method: `POST`
Content-type: JSON UTF-8 - Content-Type: `application/json` (JSON)
- Encoding: `UTF8`
#### Request Body #### Request Body
```json ```json
@@ -87,8 +94,9 @@ If the authentication succeed:
``` ```
### Directory ### Directory
HTTP method: `POST` - Method: `POST`
Content-type: JSON UTF-8 - Content-Type: `application/json` (JSON)
- Encoding: `UTF8`
#### Request Body #### Request Body
```json ```json
@@ -113,7 +121,7 @@ If users found:
"user_id": "UserIdLocalpart" "user_id": "UserIdLocalpart"
}, },
{ {
... "...": "..."
} }
] ]
} }
@@ -129,10 +137,11 @@ If no user found:
### Identity ### Identity
#### Single 3PID lookup #### Single 3PID lookup
HTTP method: `POST` - Method: `POST`
Content-type: JSON UTF-8 - Content-Type: `application/json` (JSON)
- Encoding: `UTF8`
#### Request Body ##### Request Body
```json ```json
{ {
"lookup": { "lookup": {
@@ -142,7 +151,7 @@ Content-type: JSON UTF-8
} }
``` ```
#### Response Body ##### Response Body
If a match was found: If a match was found:
- `lookup.id.type` supported values: `localpart`, `mxid` - `lookup.id.type` supported values: `localpart`, `mxid`
```json ```json
@@ -164,10 +173,11 @@ If no match was found:
``` ```
#### Bulk 3PID lookup #### Bulk 3PID lookup
HTTP method: `POST` - Method: `POST`
Content-type: JSON UTF-8 - Content-Type: `application/json` (JSON)
- Encoding: `UTF8`
#### Request Body ##### Request Body
```json ```json
{ {
"lookup": [ "lookup": [
@@ -183,7 +193,7 @@ Content-type: JSON UTF-8
} }
``` ```
#### Response Body ##### Response Body
For all entries where a match was found: For all entries where a match was found:
- `lookup[].id.type` supported values: `localpart`, `mxid` - `lookup[].id.type` supported values: `localpart`, `mxid`
```json ```json
@@ -215,3 +225,53 @@ If no match was found:
"lookup": [] "lookup": []
} }
``` ```
### Profile
#### Request Body
For all requests, the values are the same:
- Method: `POST`
- Content-Type: `application/json` (JSON)
- Encoding: `UTF8`
With body (example values):
##### Request Body
```json
{
"mxid": "@john.doe:example.org",
"localpart": "john.doe",
"domain": "example.org"
}
```
#### Response Body
For all responses, the same object structure will be parsed, making the non-relevant fields as optional.
Structure with example values:
```json
{
"profile": {
"display_name": "John Doe",
"threepids": [
{
"medium": "email",
"address": "john.doe@example.org"
},
{
"...": "..."
}
],
"roles": [
"DomainUsers",
"SalesOrg",
"..."
]
}
}
```
The base `profile` key is mandatory. `display_name`, `threepids` and `roles` are only to be returned on the relevant request.
If there is no profile, the following response is expected:
```json
{
"profile": {}
}
```

View File

@@ -15,19 +15,21 @@
Due to the implementation complexity of supporting arbitrary hashing/encoding mechanisms or auth flow, Authentication Due to the implementation complexity of supporting arbitrary hashing/encoding mechanisms or auth flow, Authentication
will be out of scope of SQL Identity stores and should be done via one of the other identity stores, typically will be out of scope of SQL Identity stores and should be done via one of the other identity stores, typically
the [REST Identity store](rest.md). the [Exec Identity Store](exec.md) or the [REST Identity Store](rest.md).
## Configuration ## Configuration
### Basic ### Basic
```yaml ```yaml
sql.enabled: <boolean> sql:
enabled: <boolean>
``` ```
Enable/disable the identity store Enable/disable the identity store
--- ---
```yaml ```yaml
sql.type: <string> sql:
type: <string>
``` ```
Set the SQL backend to use: Set the SQL backend to use:
- `sqlite` - `sqlite`
@@ -38,14 +40,16 @@ Set the SQL backend to use:
### Connection ### Connection
#### SQLite #### SQLite
```yaml ```yaml
sql.connection: <string> sql:
connection: <string>
``` ```
Set the value to the absolute path to the Synapse SQLite DB file. Set the value to the absolute path to the Synapse SQLite DB file.
Example: `/path/to/sqlite/file.db` Example: `/path/to/sqlite/file.db`
#### Others #### Others
```yaml ```yaml
sql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS sql:
connection: //<HOST[:PORT]/DB?user=USER&password=PASS
``` ```
Set the connection info for the database by replacing the following values: Set the connection info for the database by replacing the following values:
- `HOST`: Hostname of the SQL server - `HOST`: Hostname of the SQL server
@@ -58,14 +62,17 @@ This follow the JDBC URI syntax. See [official website](https://docs.oracle.com/
### Directory ### Directory
```yaml ```yaml
sql.directory.enabled: false sql:
directory:
enabled: false
``` ```
--- ---
```yaml ```yaml
sql.directory.query: sql:
directory:
query:
name: name:
type: <string> type: <string>
value: <string> value: <string>
@@ -83,7 +90,9 @@ For each query, `type` can be used to tell mxisd how to process the ID column:
Example: Example:
```yaml ```yaml
sql.directory.query: sql:
directory:
query:
name: name:
type: 'localpart' type: 'localpart'
value: 'SELECT idColumn, displayNameColumn FROM table WHERE displayNameColumn LIKE ?' value: 'SELECT idColumn, displayNameColumn FROM table WHERE displayNameColumn LIKE ?'
@@ -94,6 +103,8 @@ sql.directory.query:
### Identity ### Identity
```yaml ```yaml
sql.identity.type: <string> sql:
sql.identity.query: <string> identity:
type: <string>
query: <string>
``` ```

View File

@@ -14,14 +14,16 @@ Authentication is done by Synapse itself.
## Configuration ## Configuration
### Basic ### Basic
```yaml ```yaml
synapseSql.enabled: <boolean> synapseSql:
enabled: <boolean>
``` ```
Enable/disable the identity store Enable/disable the identity store
--- ---
```yaml ```yaml
synapseSql.type: <string> synapseSql:
type: <string>
``` ```
Set the SQL backend to use which is configured in synapse: Set the SQL backend to use which is configured in synapse:
- `sqlite` - `sqlite`
@@ -29,14 +31,16 @@ Set the SQL backend to use which is configured in synapse:
### SQLite ### SQLite
```yaml ```yaml
synapseSql.connection: <string> synapseSql:
connection: <string>
``` ```
Set the value to the absolute path to the Synapse SQLite DB file. Set the value to the absolute path to the Synapse SQLite DB file.
Example: `/path/to/synapse/sqliteFile.db` Example: `/path/to/synapse/sqliteFile.db`
### PostgreSQL ### PostgreSQL
```yaml ```yaml
synapseSql.connection: //<HOST[:PORT]/DB?user=USER&password=PASS synapseSql:
connection: //<HOST[:PORT]/DB?user=USER&password=PASS
``` ```
Set the connection info for the database by replacing the following values: Set the connection info for the database by replacing the following values:
- `HOST`: Hostname of the SQL server - `HOST`: Hostname of the SQL server

View File

@@ -34,22 +34,29 @@ If this is not the case for your installation, the mxisd URL will need to be app
### mxisd ### mxisd
Enable in the configuration: Enable in the configuration:
```yaml ```yaml
wordpress.enabled: true wordpress:
enabled: true
``` ```
Configure the URL to your Wordpress installation - see above about added `/index.php`: Configure the URL to your Wordpress installation - see above about added `/index.php`:
```yaml ```yaml
wordpress.rest.base: 'http://localhost:8080' wordpress:
rest:
base: 'http://localhost:8080'
``` ```
Configure the SQL connection to your Wordpress database: Configure the SQL connection to your Wordpress database:
```yaml ```yaml
wordpress.sql.connection: '//127.0.0.1/wordpress?user=root&password=example' wordpress:
sql:
connection: '//127.0.0.1/wordpress?user=root&password=example'
``` ```
--- ---
By default, MySQL database is expected. If you use another database, use: By default, MySQL database is expected. If you use another database, use:
```yaml ```yaml
wordpress.sql.type: <string> wordpress:
sql:
type: <string>
``` ```
With possible values: With possible values:
- `mysql` - `mysql`
@@ -61,6 +68,8 @@ With possible values:
To configure the tables prefix for default queries, in case a custom value was set during Wordpress install: To configure the tables prefix for default queries, in case a custom value was set during Wordpress install:
```yaml ```yaml
wordpress.sql.tablePrefix: <string> wordpress:
sql:
tablePrefix: <string>
``` ```
By default, the value is set to `wp_`. By default, the value is set to `wp_`.

View File

@@ -5,7 +5,9 @@ Connector ID: `smtp`
## Configuration ## Configuration
```yaml ```yaml
threepid.medium.email: threepid:
medium:
email:
identity: identity:
from: 'identityServerEmail@example.org' from: 'identityServerEmail@example.org'
name: 'My Identity Server' name: 'My Identity Server'

View File

@@ -5,7 +5,12 @@ Connector ID: `twilio`
## Configuration ## Configuration
```yaml ```yaml
threepid.medium.msisdn.connectors.twilio.accountSid: 'myAccountSid' threepid:
threepid.medium.msisdn.connectors.twilio.authToken: 'myAuthToken' medium:
threepid.medium.msisdn.connectors.twilio.number: '+123456789' msisdn:
connectors:
twilio:
accountSid: 'myAccountSid'
authToken: 'myAuthToken'
number: '+123456789'
``` ```

View File

@@ -18,13 +18,16 @@ This handler can be used with the 3PID types:
## Configuration ## Configuration
Enabled by default or with: Enabled by default or with:
```yaml ```yaml
notification.handler.email: 'raw' notification:
handler:
email: 'raw'
``` ```
**WARNING:** Will be consolidated soon, prone to breaking changes. **WARNING:** Will be consolidated soon, prone to breaking changes.
Structure and default values: Structure and default values:
```yaml ```yaml
threepid.medium: threepid:
medium:
email: email:
identity: identity:
from: '' from: ''

View File

@@ -1,7 +1,45 @@
# SendGrid Notification handler # SendGrid Notification handler
To be completed. See [raw possible configuration items](https://github.com/kamax-matrix/mxisd/blob/master/src/main/resources/application.yaml#L172). > **WARNING:** This section is incomplete and may be misleading. Contact us if guidance is needed.
Enabled with: Enable with:
```yaml ```yaml
notification.handler.email: 'sendgrid' notification:
handler:
email: 'sendgrid'
```
Available Configuration keys:
```yaml
notification:
handlers:
sendgrid:
api:
key: <API key>
identity:
from: <Sender email address>
name: <Sender name>
templates:
invite:
subject: <Subject of the email notification sent for room invites>
body:
text: <Path to file containing the raw text part of the email. Do not set to not use one>
html: <Path to file containing the HTML part of the email. Do not set to not use one>
session:
validation:
local:
subject: <Subject of the email notification sent for local 3PID sessions>
body:
text: <Path to file containing the raw text part of the email. Do not set to not use one>
html: <Path to file containing the HTML part of the email. Do not set to not use one>
remote:
subject: <Subject of the email notification sent for remote 3PID sessions>
body:
text: <Path to file containing the raw text part of the email. Do not set to not use one>
html: <Path to file containing the HTML part of the email. Do not set to not use one>
unbind:
fraudulent:
subject: <Subject of the email notification sent for potentially fraudulent 3PID unbinds>
body:
text: <Path to file containing the raw text part of the email. Do not set to not use one>
html: <Path to file containing the raw text part of the email. Do not set to not use one>
``` ```

View File

@@ -11,14 +11,18 @@ placeholders and also have their own individual set of placeholders.
## Configuration ## Configuration
To configure paths to the various templates: To configure paths to the various templates:
```yaml ```yaml
threepid.medium.<YOUR 3PID MEDIUM HERE>: threepid:
medium:
<YOUR 3PID MEDIUM HERE>:
generators: generators:
template: template:
invite: '/path/to/invite-template.eml' invite: '/path/to/invite-template.eml'
session: session:
validation: validation:
local: '/path/to/validate-local-template.eml' local: '/path/to/validate-local-template.eml'
remote: 'path/to/validate-remote-template.eml' remote: '/path/to/validate-remote-template.eml'
unbind:
frandulent: '/path/to/unbind-fraudulent-template.eml'
generic: generic:
matrixId: '/path/to/mxid-invite-template.eml' matrixId: '/path/to/mxid-invite-template.eml'
``` ```

View File

@@ -1,20 +1,22 @@
# Web pages for the 3PID sessions # Web pages for the 3PID sessions
You can customize the various pages used during a 3PID validation using [Thymeleaf templates](http://www.thymeleaf.org/). You can customize the various pages used during a 3PID validation using the options below.
## Configuration ## Configuration
Pseudo-configuration to illustrate the structure: Pseudo-configuration to illustrate the structure:
```yaml ```yaml
# CONFIGURATION EXAMPLE # CONFIGURATION EXAMPLE
# DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION
view.session.local: view:
session:
local:
onTokenSubmit: onTokenSubmit:
success: '/path/to/session/local/tokenSubmitSuccess-page.html' success: '/path/to/session/local/tokenSubmitSuccess-page.html'
failure: '/path/to/session/local/tokenSubmitFailure-page.html' failure: '/path/to/session/local/tokenSubmitFailure-page.html'
view.session.localRemote: localRemote:
onTokenSubmit: onTokenSubmit:
success: '/path/to/session/localRemote/tokenSubmitSuccess-page.html' success: '/path/to/session/localRemote/tokenSubmitSuccess-page.html'
failure: '/path/to/session/local/tokenSubmitFailure-page.html' failure: '/path/to/session/local/tokenSubmitFailure-page.html'
view.session.remote: remote:
onRequest: onRequest:
success: '/path/to/session/remote/requestSuccess-page.html' success: '/path/to/session/remote/requestSuccess-page.html'
failure: '/path/to/session/remote/requestFailure-page.html' failure: '/path/to/session/remote/requestFailure-page.html'
@@ -55,7 +57,7 @@ client if they do not wish to proceed any further.
#### Placeholders #### Placeholders
##### Success ##### Success
`<a th:href="${remoteSessionLink}">text</a>` can be used to display the link to start a Remote 3PID session. `<a href="${remoteSessionLink}">text</a>` can be used to display the link to start a Remote 3PID session.
##### Failure ##### Failure
No object/placeholder are currently available. No object/placeholder are currently available.
@@ -70,7 +72,7 @@ the remote Identity server and, once that is done, click a link to validate the
#### Placeholders #### Placeholders
##### Success ##### Success
`<a th:href="${checkLink}">text</a>` can be used to display the link to validate the Remote 3PID session. `<a href="${checkLink}">text</a>` can be used to display the link to validate the Remote 3PID session.
##### Failure ##### Failure
No object/placeholder are currently available. No object/placeholder are currently available.

View File

@@ -133,19 +133,25 @@ file unless you want to specifically overwrite them.
```yaml ```yaml
# CONFIGURATION EXAMPLE # CONFIGURATION EXAMPLE
# DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION
session.policy.validation.enabled: true session:
session.policy.validation.forLocal: policy:
validation:
enabled: true
forLocal:
enabled: true enabled: true
toLocal: true toLocal: true
toRemote: toRemote:
enabled: true enabled: true
server: 'configExample' # Not to be included in config! Already present in default config! server: 'configExample' # Not to be included in config! Already present in default config!
session.policy.validation.forRemote: forRemote:
enabled: true enabled: true
toLocal: true toLocal: true
toRemote: toRemote:
enabled: true enabled: true
server: 'configExample' # Not to be included in config! Already present in default config! server: 'configExample' # Not to be included in config! Already present in default config!
unbind:
fraudulent:
sendWarning: true
# DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION # DO NOT COPY/PASTE THIS IN YOUR CONFIGURATION
# CONFIGURATION EXAMPLE # CONFIGURATION EXAMPLE
``` ```
@@ -165,6 +171,14 @@ Each scope is divided into three parts:
If both `toLocal` and `toRemote` are enabled, the user will be offered to initiate a remote session once their 3PID If both `toLocal` and `toRemote` are enabled, the user will be offered to initiate a remote session once their 3PID
locally validated. locally validated.
---
`unbind.fraudulent` controls warning notifications if an illegal/fraudulent 3PID removal is attempted on the Identity server.
This is directly related to synapse disregard for privacy and new GDPR laws in Europe in an attempt to inform users about
potential privacy leaks.
For more information, see the corresponding [synapse issue](https://github.com/matrix-org/synapse/issues/4540).
### Web views ### Web views
Once a user click on a validation link, it is taken to the Identity Server validation page where the token is submitted. Once a user click on a validation link, it is taken to the Identity Server validation page where the token is submitted.
If the session or token is invalid, an error page is displayed. If the session or token is invalid, an error page is displayed.
@@ -219,13 +233,16 @@ On the flip side, people with *Remote* 3PID scopes will not be found from other
Use the following values: Use the following values:
```yaml ```yaml
session.policy.validation.enabled: true session:
session.policy.validation.forLocal: policy:
validation:
enabled: true
forLocal:
enabled: true enabled: true
toLocal: true toLocal: true
toRemote: toRemote:
enabled: false enabled: false
session.policy.validation.forRemote: forRemote:
enabled: true enabled: true
toLocal: true toLocal: true
toRemote: toRemote:
@@ -245,13 +262,16 @@ Typical use cases:
Use the following values: Use the following values:
```yaml ```yaml
session.policy.validation.enabled: true session:
session.policy.validation.forLocal: policy:
validation:
enabled: true
forLocal:
enabled: true enabled: true
toLocal: false toLocal: false
toRemote: toRemote:
enabled: true enabled: true
session.policy.validation.forRemote: forRemote:
enabled: true enabled: true
toLocal: false toLocal: false
toRemote: toRemote:
@@ -272,5 +292,8 @@ It is therefore recommended to not fully disable sessions but instead restrict s
Use the following values to enable this mode: Use the following values to enable this mode:
```yaml ```yaml
session.policy.validation.enabled: false session:
policy:
validation:
enabled: false
``` ```

View File

@@ -1,50 +1,46 @@
# Sample configuration file explaining the minimum required keys to be set to run mxisd # Sample configuration file explaining the minimum required keys to be set to run mxisd
# #
# For a complete list of options, see https://github.com/kamax-matrix/mxisd # For a complete list of options, see https://github.com/kamax-matrix/mxisd/docs/README.md
####################### #######################
# Matrix config items # # Matrix config items #
####################### #######################
# Matrix domain, same as the domain configure in your Homeserver configuration. # Matrix domain, same as the domain configure in your Homeserver configuration.
# (note: in Synapse Homeserver, the Matrix domain may be defined as 'server_name' in configuration file). # NOTE: in Synapse Homeserver, the Matrix domain is defined as 'server_name' in configuration file.
# #
# This is used to build the various identifiers for identity, auth and directory. # This is used to build the various identifiers in all the features.
matrix.domain: '' matrix:
domain: ''
################ ################
# Signing keys # # Signing keys #
################ ################
# Absolute path for the Identity Server signing key. # Absolute path for the Identity Server signing key.
# During testing, /var/tmp/mxisd.key is a possible value # This is **NOT** your homeserver key.
# The signing key is auto-generated during execution time if not present.
# #
# During testing, /var/tmp/mxisd.key is a possible value
# For production, recommended location shall be one of the following: # For production, recommended location shall be one of the following:
# - /var/opt/mxisd/sign.key # - /var/opt/mxisd/sign.key
# - /var/local/mxisd/sign.key # - /var/local/mxisd/sign.key
# - /var/lib/mxisd/sign.key # - /var/lib/mxisd/sign.key
# #
# The signing key is auto-generated during execution time if not present. key:
key.path: '' path: ''
############################ # Path to the SQLite DB file for mxisd internal storage
# Persistence config items #
############################
# Configure the storage backend, usually a DB
# Possible built-in values:
# sqlite SQLite backend, default
#
#storage.backend: 'sqlite'
# Path to the SQLite DB file
# #
# Examples: # Examples:
# - /var/opt/mxisd/mxisd.db # - /var/opt/mxisd/mxisd.db
# - /var/local/mxisd/mxisd.db # - /var/local/mxisd/mxisd.db
# - /var/lib/mxisd/mxisd.db # - /var/lib/mxisd/mxisd.db
# #
storage.provider.sqlite.database: '/path/to/mxisd.db' storage:
provider:
sqlite:
database: '/path/to/mxisd.db'
#################### ####################
@@ -52,12 +48,13 @@ storage.provider.sqlite.database: '/path/to/mxisd.db'
#################### ####################
# #
# Root/Central servers to be used as final fallback when performing lookups. # Root/Central servers to be used as final fallback when performing lookups.
# By default, for privacy reasons, matrix.org servers are not enabled anymore. # By default, for privacy reasons, matrix.org servers are not enabled.
# See the following issue: https://github.com/kamax-matrix/mxisd/issues/76 # See the following issue: https://github.com/kamax-matrix/mxisd/issues/76
# #
# If you would like to use them and trade away your privacy for convenience, uncomment the following option: # If you would like to use them and trade away your privacy for convenience, uncomment the following option:
# #
#forward.servers: ['matrix-org'] #forward:
# servers: ['matrix-org']
################ ################
@@ -88,27 +85,32 @@ storage.provider.sqlite.database: '/path/to/mxisd.db'
# see https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/notification/template-generator.md # see https://github.com/kamax-matrix/mxisd/blob/master/docs/threepids/notification/template-generator.md
# #
#### E-mail invite sender #### E-mail invite sender
# threepid:
# SMTP host medium:
threepid.medium.email.connectors.smtp.host: "smtp.example.org" email:
identity:
# The e-mail to send as.
from: "matrix-identity@example.org"
# SMTP port connectors:
threepid.medium.email.connectors.smtp.port: 587 smtp:
# SMTP host
host: "smtp.example.org"
# TLS mode for the connection. # SMTP port
# port: 587
# Possible values:
# 0 Disable TLS entirely
# 1 Enable TLS if supported by server (default)
# 2 Force TLS and fail if not available
#
#threepid.medium.email.connectors.smtp.tls: 1
# Login for SMTP # TLS mode for the connection.
threepid.medium.email.connectors.smtp.login: "matrix-identity@example.org" #
# Possible values:
# 0 Disable TLS entirely
# 1 Enable TLS if supported by server (default)
# 2 Force TLS and fail if not available
#
tls: 1
# Password for the account # Login for SMTP
threepid.medium.email.connectors.smtp.password: "ThePassword" login: "matrix-identity@example.org"
# The e-mail to send as. # Password for the account
threepid.medium.email.identity.from: "matrix-identity@example.org" password: "ThePassword"

View File

@@ -6,8 +6,8 @@ useradd -r mxisd || true
# Set permissions for data directory # Set permissions for data directory
chown -R mxisd:mxisd %DEB_DATA_DIR% chown -R mxisd:mxisd %DEB_DATA_DIR%
# Create symlink to mxusd # Create symlink to mxisd run script
ln -sfT /usr/lib/mxisd/mxisd.jar /usr/bin/mxisd ln -sfT /usr/lib/mxisd/mxisd /usr/bin/mxisd
# Enable systemd service # Enable systemd service
systemctl enable mxisd.service systemctl enable mxisd.service

View File

@@ -1,25 +1,34 @@
#!/usr/bin/env bash #!/bin/bash
if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then if [[ -n "$CONF_FILE_PATH" ]] && [ ! -f "$CONF_FILE_PATH" ]; then
echo "Generating config file $CONF_FILE_PATH" echo "Generating config file $CONF_FILE_PATH"
touch "CONF_FILE_PATH" touch "CONF_FILE_PATH"
if [[ -n "$MATRIX_DOMAIN" ]]; then if [[ -n "$MATRIX_DOMAIN" ]]; then
echo "Setting matrix domain to $MATRIX_DOMAIN" echo "Setting matrix domain to $MATRIX_DOMAIN"
echo "matrix.domain: $MATRIX_DOMAIN" >> "$CONF_FILE_PATH" echo "matrix:" >> "$CONF_FILE_PATH"
echo " domain: '$MATRIX_DOMAIN'" >> "$CONF_FILE_PATH"
echo >> "$CONF_FILE_PATH"
fi fi
if [[ -n "$SIGN_KEY_PATH" ]]; then if [[ -n "$SIGN_KEY_PATH" ]]; then
echo "Setting signing key path to $SIGN_KEY_PATH" echo "Setting signing key path to $SIGN_KEY_PATH"
echo "key.path: $SIGN_KEY_PATH" >> "$CONF_FILE_PATH" echo "key:" >> "$CONF_FILE_PATH"
echo " path: '$SIGN_KEY_PATH'" >> "$CONF_FILE_PATH"
echo >> "$CONF_FILE_PATH"
fi fi
if [[ -n "$SQLITE_DATABASE_PATH" ]]; then if [[ -n "$SQLITE_DATABASE_PATH" ]]; then
echo "Setting SQLite DB path to $SQLITE_DATABASE_PATH" echo "Setting SQLite DB path to $SQLITE_DATABASE_PATH"
echo "storage.provider.sqlite.database: $SQLITE_DATABASE_PATH" >> "$CONF_FILE_PATH" echo "storage:" >> "$CONF_FILE_PATH"
echo " provider:" >> "$CONF_FILE_PATH"
echo " sqlite:" >> "$CONF_FILE_PATH"
echo " database: '$SQLITE_DATABASE_PATH'" >> "$CONF_FILE_PATH"
echo >> "$CONF_FILE_PATH"
fi fi
echo "Starting mxisd..." echo "Starting mxisd..."
echo echo
fi fi
exec java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -Dspring.config.location=/etc/mxisd/ -Dspring.config.name=mxisd -jar /mxisd.jar exec java -jar /app/mxisd.jar -c /etc/mxisd/mxisd.yaml

View File

@@ -37,6 +37,7 @@ import java.util.List;
* both IPv4 and IPv6. * both IPv4 and IPv6.
*/ */
public class CIDRUtils { public class CIDRUtils {
private final String cidr; private final String cidr;
private InetAddress inetAddress; private InetAddress inetAddress;
@@ -44,7 +45,6 @@ public class CIDRUtils {
private InetAddress endAddress; private InetAddress endAddress;
private final int prefixLength; private final int prefixLength;
public CIDRUtils(String cidr) throws UnknownHostException { public CIDRUtils(String cidr) throws UnknownHostException {
this.cidr = cidr; this.cidr = cidr;
@@ -66,7 +66,6 @@ public class CIDRUtils {
private void calculate() throws UnknownHostException { private void calculate() throws UnknownHostException {
ByteBuffer maskBuffer; ByteBuffer maskBuffer;
int targetSize; int targetSize;
if (inetAddress.getAddress().length == 4) { if (inetAddress.getAddress().length == 4) {
@@ -120,14 +119,9 @@ public class CIDRUtils {
} }
public String getNetworkAddress() { public String getNetworkAddress() {
return this.startAddress.getHostAddress(); return this.startAddress.getHostAddress();
} }
public String getBroadcastAddress() {
return this.endAddress.getHostAddress();
}
public boolean isInRange(String ipAddress) throws UnknownHostException { public boolean isInRange(String ipAddress) throws UnknownHostException {
InetAddress address = InetAddress.getByName(ipAddress); InetAddress address = InetAddress.getByName(ipAddress);
BigInteger start = new BigInteger(1, this.startAddress.getAddress()); BigInteger start = new BigInteger(1, this.startAddress.getAddress());
@@ -139,4 +133,5 @@ public class CIDRUtils {
return (st == -1 || st == 0) && (te == -1 || te == 0); return (st == -1 || st == 0) && (te == -1 || te == 0);
} }
} }

View File

@@ -0,0 +1,115 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.http.undertow.handler.SaneHandler;
import io.kamax.mxisd.http.undertow.handler.as.v1.AsNotFoundHandler;
import io.kamax.mxisd.http.undertow.handler.as.v1.AsTransactionHandler;
import io.kamax.mxisd.http.undertow.handler.auth.RestAuthHandler;
import io.kamax.mxisd.http.undertow.handler.auth.v1.LoginGetHandler;
import io.kamax.mxisd.http.undertow.handler.auth.v1.LoginHandler;
import io.kamax.mxisd.http.undertow.handler.auth.v1.LoginPostHandler;
import io.kamax.mxisd.http.undertow.handler.directory.v1.UserDirectorySearchHandler;
import io.kamax.mxisd.http.undertow.handler.identity.v1.*;
import io.kamax.mxisd.http.undertow.handler.profile.v1.InternalProfileHandler;
import io.kamax.mxisd.http.undertow.handler.profile.v1.ProfileHandler;
import io.kamax.mxisd.http.undertow.handler.status.StatusHandler;
import io.undertow.Handlers;
import io.undertow.Undertow;
import io.undertow.server.HttpHandler;
public class HttpMxisd {
// Core
private Mxisd m;
// I/O
private Undertow httpSrv;
public HttpMxisd(MxisdConfig cfg) {
m = new Mxisd(cfg);
}
public void start() {
m.start();
HttpHandler asNotFoundHandler = SaneHandler.around(new AsNotFoundHandler(m.getAs()));
HttpHandler asTxnHandler = SaneHandler.around(new AsTransactionHandler(m.getAs()));
HttpHandler storeInvHandler = SaneHandler.around(new StoreInviteHandler(m.getConfig().getServer(), m.getInvitationManager(), m.getKeyManager()));
HttpHandler sessValidateHandler = SaneHandler.around(new SessionValidateHandler(m.getSession(), m.getConfig().getServer(), m.getConfig().getView()));
httpSrv = Undertow.builder().addHttpListener(m.getConfig().getServer().getPort(), "0.0.0.0").setHandler(Handlers.routing()
// Status endpoints
.get(StatusHandler.Path, SaneHandler.around(new StatusHandler()))
// Authentication endpoints
.get(LoginHandler.Path, SaneHandler.around(new LoginGetHandler(m.getAuth(), m.getHttpClient())))
.post(LoginHandler.Path, SaneHandler.around(new LoginPostHandler(m.getAuth())))
.post(RestAuthHandler.Path, SaneHandler.around(new RestAuthHandler(m.getAuth())))
// Directory endpoints
.post(UserDirectorySearchHandler.Path, SaneHandler.around(new UserDirectorySearchHandler(m.getDirectory())))
// Key endpoints
.get(KeyGetHandler.Path, SaneHandler.around(new KeyGetHandler(m.getKeyManager())))
.get(RegularKeyIsValidHandler.Path, SaneHandler.around(new RegularKeyIsValidHandler(m.getKeyManager())))
.get(EphemeralKeyIsValidHandler.Path, SaneHandler.around(new EphemeralKeyIsValidHandler()))
// Identity endpoints
.get(HelloHandler.Path, SaneHandler.around(new HelloHandler()))
.get(SingleLookupHandler.Path, SaneHandler.around(new SingleLookupHandler(m.getIdentity(), m.getSign())))
.post(BulkLookupHandler.Path, SaneHandler.around(new BulkLookupHandler(m.getIdentity())))
.post(StoreInviteHandler.Path, storeInvHandler)
.post(SessionStartHandler.Path, SaneHandler.around(new SessionStartHandler(m.getSession())))
.get(SessionValidateHandler.Path, sessValidateHandler)
.post(SessionValidateHandler.Path, sessValidateHandler)
.get(SessionTpidGetValidatedHandler.Path, SaneHandler.around(new SessionTpidGetValidatedHandler(m.getSession())))
.post(SessionTpidBindHandler.Path, SaneHandler.around(new SessionTpidBindHandler(m.getSession(), m.getInvitationManager())))
.post(SessionTpidUnbindHandler.Path, SaneHandler.around(new SessionTpidUnbindHandler(m.getSession())))
.get(RemoteIdentityAPIv1.SESSION_REQUEST_TOKEN, SaneHandler.around(new RemoteSessionStartHandler(m.getSession(), m.getConfig().getView())))
.get(RemoteIdentityAPIv1.SESSION_CHECK, SaneHandler.around(new RemoteSessionCheckHandler(m.getSession(), m.getConfig().getView())))
// Profile endpoints
.get(ProfileHandler.Path, SaneHandler.around(new ProfileHandler(m.getProfile())))
.get(InternalProfileHandler.Path, SaneHandler.around(new InternalProfileHandler(m.getProfile())))
// Application Service endpoints
.get("/_matrix/app/v1/users/**", asNotFoundHandler)
.get("/users/**", asNotFoundHandler) // Legacy endpoint
.get("/_matrix/app/v1/rooms/**", asNotFoundHandler)
.get("/rooms/**", asNotFoundHandler) // Legacy endpoint
.put(AsTransactionHandler.Path, asTxnHandler)
.put("/transactions/{" + AsTransactionHandler.ID + "}", asTxnHandler) // Legacy endpoint
).build();
httpSrv.start();
}
public void stop() {
httpSrv.stop();
m.stop();
}
}

View File

@@ -0,0 +1,172 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd;
import io.kamax.matrix.crypto.KeyManager;
import io.kamax.matrix.crypto.SignatureManager;
import io.kamax.mxisd.as.AppSvcManager;
import io.kamax.mxisd.auth.AuthManager;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.backend.sql.synapse.Synapse;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.crypto.CryptoFactory;
import io.kamax.mxisd.directory.DirectoryManager;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.dns.ClientDnsOverwrite;
import io.kamax.mxisd.dns.FederationDnsOverwrite;
import io.kamax.mxisd.invitation.InvitationManager;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.lookup.fetcher.IRemoteIdentityServerFetcher;
import io.kamax.mxisd.lookup.provider.BridgeFetcher;
import io.kamax.mxisd.lookup.provider.RemoteIdentityServerFetcher;
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
import io.kamax.mxisd.lookup.strategy.RecursivePriorityLookupStrategy;
import io.kamax.mxisd.notification.NotificationHandlerSupplier;
import io.kamax.mxisd.notification.NotificationHandlers;
import io.kamax.mxisd.notification.NotificationManager;
import io.kamax.mxisd.profile.ProfileManager;
import io.kamax.mxisd.profile.ProfileProviders;
import io.kamax.mxisd.session.SessionMananger;
import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.ormlite.OrmLiteSqlStorage;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import java.util.ServiceLoader;
public class Mxisd {
protected MxisdConfig cfg;
protected CloseableHttpClient httpClient;
protected IRemoteIdentityServerFetcher srvFetcher;
protected IStorage store;
protected KeyManager keyMgr;
protected SignatureManager signMgr;
// Features
protected AuthManager authMgr;
protected DirectoryManager dirMgr;
protected LookupStrategy idStrategy;
protected InvitationManager invMgr;
protected ProfileManager pMgr;
protected AppSvcManager asHander;
protected SessionMananger sessMgr;
protected NotificationManager notifMgr;
public Mxisd(MxisdConfig cfg) {
this.cfg = cfg.build();
}
protected void build() {
httpClient = HttpClients.custom()
.setUserAgent("mxisd")
.setMaxConnPerRoute(Integer.MAX_VALUE)
.setMaxConnTotal(Integer.MAX_VALUE)
.build();
srvFetcher = new RemoteIdentityServerFetcher(httpClient);
store = new OrmLiteSqlStorage(cfg);
keyMgr = CryptoFactory.getKeyManager(cfg.getKey());
signMgr = CryptoFactory.getSignatureManager(keyMgr, cfg.getServer());
ClientDnsOverwrite clientDns = new ClientDnsOverwrite(cfg.getDns().getOverwrite());
FederationDnsOverwrite fedDns = new FederationDnsOverwrite(cfg.getDns().getOverwrite());
Synapse synapse = new Synapse(cfg.getSynapseSql());
BridgeFetcher bridgeFetcher = new BridgeFetcher(cfg.getLookup().getRecursive().getBridge(), srvFetcher);
ServiceLoader.load(IdentityStoreSupplier.class).iterator().forEachRemaining(p -> p.accept(this));
ServiceLoader.load(NotificationHandlerSupplier.class).iterator().forEachRemaining(p -> p.accept(this));
idStrategy = new RecursivePriorityLookupStrategy(cfg.getLookup(), ThreePidProviders.get(), bridgeFetcher);
pMgr = new ProfileManager(ProfileProviders.get(), clientDns, httpClient);
notifMgr = new NotificationManager(cfg.getNotification(), NotificationHandlers.get());
sessMgr = new SessionMananger(cfg.getSession(), cfg.getMatrix(), store, notifMgr, idStrategy, httpClient);
invMgr = new InvitationManager(cfg.getInvite(), store, idStrategy, signMgr, fedDns, notifMgr);
authMgr = new AuthManager(cfg, AuthProviders.get(), idStrategy, invMgr, clientDns, httpClient);
dirMgr = new DirectoryManager(cfg.getDirectory(), clientDns, httpClient, DirectoryProviders.get());
asHander = new AppSvcManager(cfg, store, pMgr, notifMgr, synapse);
}
public MxisdConfig getConfig() {
return cfg;
}
public CloseableHttpClient getHttpClient() {
return httpClient;
}
public IRemoteIdentityServerFetcher getServerFetcher() {
return srvFetcher;
}
public KeyManager getKeyManager() {
return keyMgr;
}
public InvitationManager getInvitationManager() {
return invMgr;
}
public LookupStrategy getIdentity() {
return idStrategy;
}
public AuthManager getAuth() {
return authMgr;
}
public SessionMananger getSession() {
return sessMgr;
}
public DirectoryManager getDirectory() {
return dirMgr;
}
public ProfileManager getProfile() {
return pMgr;
}
public SignatureManager getSign() {
return signMgr;
}
public AppSvcManager getAs() {
return asHander;
}
public NotificationManager getNotif() {
return notifMgr;
}
public void start() {
build();
}
public void stop() {
// no-op
}
}

View File

@@ -0,0 +1,69 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.config.YamlConfigLoader;
import org.apache.commons.lang3.StringUtils;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Objects;
public class MxisdStandaloneExec {
public static void main(String[] args) throws IOException {
MxisdConfig cfg = null;
Iterator<String> argsIt = Arrays.asList(args).iterator();
while (argsIt.hasNext()) {
String arg = argsIt.next();
if (StringUtils.equals("-c", arg)) {
String cfgFile = argsIt.next();
cfg = YamlConfigLoader.loadFromFile(cfgFile);
System.out.println("Loaded configuration from " + cfgFile);
} else {
System.out.println("Invalid argument: " + arg);
System.exit(1);
}
}
if (Objects.isNull(cfg)) {
cfg = YamlConfigLoader.tryLoadFromFile("mxisd.yaml").orElseGet(MxisdConfig::new);
}
try {
HttpMxisd mxisd = new HttpMxisd(cfg);
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
mxisd.stop();
System.out.println("------------- mxisd stopped -------------");
}));
mxisd.start();
System.out.println("------------- mxisd started -------------");
} catch (Throwable t) {
t.printStackTrace();
System.exit(1);
}
}
}

View File

@@ -29,38 +29,119 @@ import io.kamax.matrix.event.EventKey;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.backend.sql.synapse.Synapse; import io.kamax.mxisd.backend.sql.synapse.Synapse;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.exception.HttpMatrixException;
import io.kamax.mxisd.exception.NotAllowedException;
import io.kamax.mxisd.notification.NotificationManager; import io.kamax.mxisd.notification.NotificationManager;
import io.kamax.mxisd.profile.ProfileManager; import io.kamax.mxisd.profile.ProfileManager;
import io.kamax.mxisd.storage.IStorage;
import io.kamax.mxisd.storage.ormlite.dao.ASTransactionDao;
import io.kamax.mxisd.util.GsonParser;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashMap; import java.io.InputStream;
import java.util.List; import java.time.Instant;
import java.util.Map; import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Component public class AppSvcManager {
public class AppServiceHandler {
private final Logger log = LoggerFactory.getLogger(AppServiceHandler.class); private transient final Logger log = LoggerFactory.getLogger(AppSvcManager.class);
private final GsonParser parser;
private MatrixConfig cfg; private MatrixConfig cfg;
private IStorage store;
private ProfileManager profiler; private ProfileManager profiler;
private NotificationManager notif; private NotificationManager notif;
private Synapse synapse; private Synapse synapse;
@Autowired private Map<String, CompletableFuture<String>> transactionsInProgress;
public AppServiceHandler(MatrixConfig cfg, ProfileManager profiler, NotificationManager notif, Synapse synapse) {
this.cfg = cfg; public AppSvcManager(MxisdConfig cfg, IStorage store, ProfileManager profiler, NotificationManager notif, Synapse synapse) {
this.cfg = cfg.getMatrix();
this.store = store;
this.profiler = profiler; this.profiler = profiler;
this.notif = notif; this.notif = notif;
this.synapse = synapse; this.synapse = synapse;
parser = new GsonParser();
transactionsInProgress = new ConcurrentHashMap<>();
}
public AppSvcManager withToken(String token) {
if (StringUtils.isBlank(token)) {
throw new HttpMatrixException(401, "M_UNAUTHORIZED", "No HS token");
}
if (!StringUtils.equals(cfg.getListener().getToken().getHs(), token)) {
throw new NotAllowedException("Invalid HS token");
}
return this;
}
public CompletableFuture<String> processTransaction(String txnId, InputStream is) {
if (StringUtils.isEmpty(txnId)) {
throw new IllegalArgumentException("Transaction ID cannot be empty");
}
synchronized (this) {
Optional<ASTransactionDao> dao = store.getTransactionResult(cfg.getListener().getLocalpart(), txnId);
if (dao.isPresent()) {
log.info("AS Transaction {} already processed - returning computed result", txnId);
return CompletableFuture.completedFuture(dao.get().getResult());
}
CompletableFuture<String> f = transactionsInProgress.get(txnId);
if (Objects.nonNull(f)) {
log.info("Returning future for transaction {}", txnId);
return f;
}
transactionsInProgress.put(txnId, new CompletableFuture<>());
}
CompletableFuture<String> future = transactionsInProgress.get(txnId);
Instant start = Instant.now();
log.info("Processing AS Transaction {}: start", txnId);
try {
List<JsonObject> events = GsonUtil.asList(GsonUtil.getArray(parser.parse(is), "events"), JsonObject.class);
is.close();
log.debug("{} event(s) parsed", events.size());
processTransaction(events);
Instant end = Instant.now();
String result = "{}";
try {
log.info("Saving transaction details to store");
store.insertTransactionResult(cfg.getListener().getLocalpart(), txnId, end, result);
} finally {
log.debug("Removing CompletedFuture from transaction map");
transactionsInProgress.remove(txnId);
}
log.info("Processed AS transaction {} in {} ms", txnId, (Instant.now().toEpochMilli() - start.toEpochMilli()));
future.complete(result);
} catch (Exception e) {
log.error("Unable to properly process transaction {}", txnId, e);
future.completeExceptionally(e);
}
log.info("Processing AS Transaction {}: end", txnId);
return future;
} }
public void processTransaction(List<JsonObject> eventsJson) { public void processTransaction(List<JsonObject> eventsJson) {
log.info("Processing transaction events: start");
eventsJson.forEach(ev -> { eventsJson.forEach(ev -> {
String evId = EventKey.Id.getStringOrNull(ev); String evId = EventKey.Id.getStringOrNull(ev);
if (StringUtils.isBlank(evId)) { if (StringUtils.isBlank(evId)) {
@@ -78,10 +159,11 @@ public class AppServiceHandler {
String senderId = EventKey.Sender.getStringOrNull(ev); String senderId = EventKey.Sender.getStringOrNull(ev);
if (StringUtils.isBlank(senderId)) { if (StringUtils.isBlank(senderId)) {
log.debug("Event has no room ID, skipping"); log.debug("Event has no sender ID, skipping");
return; return;
} }
_MatrixID sender = MatrixID.asAcceptable(senderId); _MatrixID sender = MatrixID.asAcceptable(senderId);
log.debug("Sender: {}", senderId);
if (!StringUtils.equals("m.room.member", GsonUtil.getStringOrNull(ev, "type"))) { if (!StringUtils.equals("m.room.member", GsonUtil.getStringOrNull(ev, "type"))) {
log.debug("This is not a room membership event, skipping"); log.debug("This is not a room membership event, skipping");
@@ -105,7 +187,7 @@ public class AppServiceHandler {
return; return;
} }
log.info("Got invite for {}", inviteeId); log.info("Got invite from {} to {}", senderId, inviteeId);
boolean wasSent = false; boolean wasSent = false;
List<_ThreePid> tpids = profiler.getThreepids(invitee).stream() List<_ThreePid> tpids = profiler.getThreepids(invitee).stream()
@@ -121,7 +203,7 @@ public class AppServiceHandler {
synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name)); synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name));
} catch (RuntimeException e) { } catch (RuntimeException e) {
log.warn("Could not fetch room name", e); log.warn("Could not fetch room name", e);
log.warn("Unable to fetch room name: Did you integrate your Homeserver as documented?"); log.info("Unable to fetch room name: Did you integrate your Homeserver as documented?");
} }
IMatrixIdInvite inv = new MatrixIdInvite(roomId, sender, invitee, tpid.getMedium(), tpid.getAddress(), properties); IMatrixIdInvite inv = new MatrixIdInvite(roomId, sender, invitee, tpid.getMedium(), tpid.getAddress(), properties);
@@ -134,6 +216,8 @@ public class AppServiceHandler {
log.debug("Event {}: processing end", evId); log.debug("Event {}: processing end", evId);
}); });
log.info("Processing transaction events: end");
} }
} }

View File

@@ -20,37 +20,92 @@
package io.kamax.mxisd.auth; package io.kamax.mxisd.auth;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonSyntaxException;
import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid; import io.kamax.matrix._ThreePid;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
import io.kamax.mxisd.config.AuthenticationConfig;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.dns.ClientDnsOverwrite;
import io.kamax.mxisd.exception.RemoteLoginException;
import io.kamax.mxisd.invitation.InvitationManager; import io.kamax.mxisd.invitation.InvitationManager;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.strategy.LookupStrategy;
import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Objects;
@Service
public class AuthManager { public class AuthManager {
private Logger log = LoggerFactory.getLogger(AuthManager.class); private static final String TypeKey = "type";
private static final String UserKey = "user";
private static final String IdentifierKey = "identifier";
private static final String ThreepidMediumKey = "medium";
private static final String ThreepidAddressKey = "address";
private static final String UserIdTypeValue = "m.id.user";
private static final String ThreepidTypeValue = "m.id.thirdparty";
@Autowired private transient final Logger log = LoggerFactory.getLogger(AuthManager.class);
private List<AuthenticatorProvider> providers = new ArrayList<>(); private final Gson gson = GsonUtil.get(); // FIXME replace
@Autowired private List<AuthenticatorProvider> providers;
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
private AuthenticationConfig cfg;
@Autowired
private InvitationManager invMgr; private InvitationManager invMgr;
private ClientDnsOverwrite dns;
private LookupStrategy strategy;
private CloseableHttpClient client;
public AuthManager(
MxisdConfig cfg,
List<? extends AuthenticatorProvider> providers,
LookupStrategy strategy,
InvitationManager invMgr,
ClientDnsOverwrite dns,
CloseableHttpClient client
) {
this.cfg = cfg.getAuth();
this.mxCfg = cfg.getMatrix();
this.providers = new ArrayList<>(providers);
this.strategy = strategy;
this.invMgr = invMgr;
this.dns = dns;
this.client = client;
}
public String resolveProxyUrl(URI target) {
URIBuilder builder = dns.transform(target);
String urlToLogin = builder.toString();
log.info("Proxy resolution: {} to {}", target.toString(), urlToLogin);
return urlToLogin;
}
public UserAuthResult authenticate(String id, String password) { public UserAuthResult authenticate(String id, String password) {
_MatrixID mxid = MatrixID.asAcceptable(id); _MatrixID mxid = MatrixID.asAcceptable(id);
@@ -92,4 +147,128 @@ public class AuthManager {
return new UserAuthResult().failure(); return new UserAuthResult().failure();
} }
public String proxyLogin(URI target, String body) {
JsonObject reqJsonObject = io.kamax.matrix.json.GsonUtil.parseObj(body);
GsonUtil.findObj(reqJsonObject, IdentifierKey).ifPresent(obj -> {
GsonUtil.findString(obj, TypeKey).ifPresent(type -> {
if (StringUtils.equals(type, UserIdTypeValue)) {
log.info("Login request is User ID type");
if (cfg.getRewrite().getUser().getRules().isEmpty()) {
log.info("No User ID rewrite rules to apply");
} else {
log.info("User ID rewrite rules: checking for a match");
String userId = GsonUtil.getStringOrThrow(obj, UserKey);
for (AuthenticationConfig.Rule m : cfg.getRewrite().getUser().getRules()) {
if (m.getPattern().matcher(userId).matches()) {
log.info("Found matching pattern, resolving to 3PID with medium {}", m.getMedium());
// Remove deprecated login info on the top object if exists to avoid duplication
reqJsonObject.remove(UserKey);
obj.addProperty(TypeKey, ThreepidTypeValue);
obj.addProperty(ThreepidMediumKey, m.getMedium());
obj.addProperty(ThreepidAddressKey, userId);
log.info("Rewrite to 3PID done");
}
}
log.info("User ID rewrite rules: done checking rules");
}
}
});
});
GsonUtil.findObj(reqJsonObject, IdentifierKey).ifPresent(obj -> {
GsonUtil.findString(obj, TypeKey).ifPresent(type -> {
if (StringUtils.equals(type, ThreepidTypeValue)) {
// Remove deprecated login info if exists to avoid duplication
reqJsonObject.remove(ThreepidMediumKey);
reqJsonObject.remove(ThreepidAddressKey);
GsonUtil.findPrimitive(obj, ThreepidMediumKey).ifPresent(medium -> {
GsonUtil.findPrimitive(obj, ThreepidAddressKey).ifPresent(address -> {
log.info("Login request with medium '{}' and address '{}'", medium.getAsString(), address.getAsString());
strategy.findLocal(medium.getAsString(), address.getAsString()).ifPresent(lookupDataOpt -> {
obj.remove(ThreepidMediumKey);
obj.remove(ThreepidAddressKey);
obj.addProperty(TypeKey, UserIdTypeValue);
obj.addProperty(UserKey, lookupDataOpt.getMxid().getLocalPart());
});
});
});
}
if (StringUtils.equals(type, "m.id.phone")) {
// Remove deprecated login info if exists to avoid duplication
reqJsonObject.remove(ThreepidMediumKey);
reqJsonObject.remove(ThreepidAddressKey);
GsonUtil.findPrimitive(obj, "number").ifPresent(number -> {
GsonUtil.findPrimitive(obj, "country").ifPresent(country -> {
log.info("Login request with phone '{}'-'{}'", country.getAsString(), number.getAsString());
try {
PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
Phonenumber.PhoneNumber phoneNumber = phoneUtil.parse(number.getAsString(), country.getAsString());
String msisdn = phoneUtil.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164).replace("+", "");
String medium = "msisdn";
strategy.findLocal(medium, msisdn).ifPresent(lookupDataOpt -> {
obj.remove("country");
obj.remove("number");
obj.addProperty(TypeKey, UserIdTypeValue);
obj.addProperty(UserKey, lookupDataOpt.getMxid().getLocalPart());
});
} catch (NumberParseException e) {
log.error("Not a valid phone number");
throw new RuntimeException(e);
}
});
});
}
});
});
// invoke 'login' on homeserver
HttpPost httpPost = RestClientUtils.post(resolveProxyUrl(target), gson, reqJsonObject);
try (CloseableHttpResponse httpResponse = client.execute(httpPost)) {
// check http status
int status = httpResponse.getStatusLine().getStatusCode();
log.info("http status = {}", status);
if (status != 200) {
// try to get possible json error message from response
// otherwise just get returned plain error message
String errcode = String.valueOf(httpResponse.getStatusLine().getStatusCode());
String error = EntityUtils.toString(httpResponse.getEntity());
if (httpResponse.getEntity() != null) {
try {
JsonObject bodyJson = new JsonParser().parse(error).getAsJsonObject();
if (bodyJson.has("errcode")) {
errcode = bodyJson.get("errcode").getAsString();
}
if (bodyJson.has("error")) {
error = bodyJson.get("error").getAsString();
}
throw new RemoteLoginException(status, errcode, error, bodyJson);
} catch (JsonSyntaxException e) {
log.warn("Response body is not JSON");
}
}
throw new RemoteLoginException(status, errcode, error);
}
// return response
HttpEntity entity = httpResponse.getEntity();
if (Objects.isNull(entity)) {
log.warn("Expected HS to return data but got nothing");
return "";
} else {
return IOUtils.toString(httpResponse.getEntity().getContent(), StandardCharsets.UTF_8);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} }

View File

@@ -0,0 +1,42 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.auth;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class AuthProviders {
private static final List<Supplier<? extends AuthenticatorProvider>> suppliers = new ArrayList<>();
public static void register(Supplier<? extends AuthenticatorProvider> supplier) {
suppliers.add(supplier);
}
public static List<? extends AuthenticatorProvider> get() {
return suppliers.stream().map(Supplier::get).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,29 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend;
import io.kamax.mxisd.Mxisd;
import java.util.function.Consumer;
public interface IdentityStoreSupplier extends Consumer<Mxisd> {
}

View File

@@ -33,20 +33,16 @@ import io.kamax.mxisd.exception.InternalServerError;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@Component
public class ExecAuthStore extends ExecStore implements AuthenticatorProvider { public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
private final Logger log = LoggerFactory.getLogger(ExecAuthStore.class); private transient final Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
private ExecConfig.Auth cfg; private ExecConfig.Auth cfg;
@Autowired
public ExecAuthStore(ExecConfig cfg) { public ExecAuthStore(ExecConfig cfg) {
this.cfg = Objects.requireNonNull(cfg.getAuth()); this.cfg = Objects.requireNonNull(cfg.getAuth());
} }

View File

@@ -24,22 +24,19 @@ import io.kamax.matrix.MatrixID;
import io.kamax.matrix.json.GsonUtil; import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.config.ExecConfig; import io.kamax.mxisd.config.ExecConfig;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest; import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.directory.IDirectoryProvider; import io.kamax.mxisd.http.io.UserDirectorySearchRequest;
import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component public class ExecDirectoryStore extends ExecStore implements DirectoryProvider {
public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider {
private ExecConfig.Directory cfg; private ExecConfig.Directory cfg;
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
@Autowired public ExecDirectoryStore(MxisdConfig cfg) {
public ExecDirectoryStore(ExecConfig cfg, MatrixConfig mxCfg) { this(cfg.getExec().getDirectory(), cfg.getMatrix());
this(cfg.getDirectory(), mxCfg);
} }
public ExecDirectoryStore(ExecConfig.Directory cfg, MatrixConfig mxCfg) { public ExecDirectoryStore(ExecConfig.Directory cfg, MatrixConfig mxCfg) {
@@ -47,11 +44,6 @@ public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
private UserDirectorySearchResult search(ExecConfig.Process cfg, UserDirectorySearchRequest request) { private UserDirectorySearchResult search(ExecConfig.Process cfg, UserDirectorySearchRequest request) {
if (StringUtils.isEmpty(cfg.getCommand())) { if (StringUtils.isEmpty(cfg.getCommand())) {
return UserDirectorySearchResult.empty(); return UserDirectorySearchResult.empty();

View File

@@ -40,8 +40,6 @@ import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@@ -49,15 +47,13 @@ import java.util.Objects;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Component
public class ExecIdentityStore extends ExecStore implements IThreePidProvider { public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
private final Logger log = LoggerFactory.getLogger(ExecIdentityStore.class); private transient final Logger log = LoggerFactory.getLogger(ExecIdentityStore.class);
private final ExecConfig.Identity cfg; private final ExecConfig.Identity cfg;
private final MatrixConfig mxCfg; private final MatrixConfig mxCfg;
@Autowired
public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) { public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) {
this(cfg.getIdentity(), mxCfg); this(cfg.getIdentity(), mxCfg);
} }
@@ -67,11 +63,6 @@ public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;

View File

@@ -0,0 +1,56 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.exec;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class ExecIdentityStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getExec().getAuth().isEnabled()) {
AuthProviders.register(() -> new ExecAuthStore(cfg.getExec()));
}
if (cfg.getExec().getDirectory().isEnabled()) {
DirectoryProviders.register(() -> new ExecDirectoryStore(cfg));
}
if (cfg.getExec().getIdentity().isEnabled()) {
ThreePidProviders.register(() -> new ExecIdentityStore(cfg.getExec(), cfg.getMatrix()));
}
if (cfg.getExec().getProfile().isEnabled()) {
ProfileProviders.register(() -> new ExecProfileStore(cfg.getExec()));
}
}
}

View File

@@ -28,19 +28,15 @@ import io.kamax.mxisd.profile.JsonProfileRequest;
import io.kamax.mxisd.profile.JsonProfileResult; import io.kamax.mxisd.profile.JsonProfileResult;
import io.kamax.mxisd.profile.ProfileProvider; import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component
public class ExecProfileStore extends ExecStore implements ProfileProvider { public class ExecProfileStore extends ExecStore implements ProfileProvider {
private ExecConfig.Profile cfg; private ExecConfig.Profile cfg;
@Autowired
public ExecProfileStore(ExecConfig cfg) { public ExecProfileStore(ExecConfig cfg) {
this(cfg.getProfile()); this(cfg.getProfile());
} }
@@ -49,11 +45,6 @@ public class ExecProfileStore extends ExecStore implements ProfileProvider {
this.cfg = cfg; this.cfg = cfg;
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
private Optional<JsonProfileResult> getFull(_MatrixID userId, ExecConfig.Process cfg) { private Optional<JsonProfileResult> getFull(_MatrixID userId, ExecConfig.Process cfg) {
Processor<Optional<JsonProfileResult>> p = new Processor<>(cfg); Processor<Optional<JsonProfileResult>> p = new Processor<>(cfg);

View File

@@ -47,7 +47,7 @@ public class ExecStore {
return GsonUtil.get().toJson(o); return GsonUtil.get().toJson(o);
} }
private final Logger log = LoggerFactory.getLogger(ExecStore.class); private transient final Logger log = LoggerFactory.getLogger(ExecStore.class);
private Supplier<ProcessExecutor> executorSupplier = () -> new ProcessExecutor().readOutput(true); private Supplier<ProcessExecutor> executorSupplier = () -> new ProcessExecutor().readOutput(true);

View File

@@ -29,6 +29,7 @@ import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
import io.kamax.mxisd.config.FirebaseConfig;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -38,10 +39,14 @@ import java.util.concurrent.TimeUnit;
public class GoogleFirebaseAuthenticator extends GoogleFirebaseBackend implements AuthenticatorProvider { public class GoogleFirebaseAuthenticator extends GoogleFirebaseBackend implements AuthenticatorProvider {
private Logger log = LoggerFactory.getLogger(GoogleFirebaseAuthenticator.class); private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseAuthenticator.class);
private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
public GoogleFirebaseAuthenticator(FirebaseConfig cfg) {
this(cfg.isEnabled(), cfg.getCredentials(), cfg.getDatabase());
}
public GoogleFirebaseAuthenticator(boolean isEnabled, String credsPath, String db) { public GoogleFirebaseAuthenticator(boolean isEnabled, String credsPath, String db) {
super(isEnabled, "AuthenticationProvider", credsPath, db); super(isEnabled, "AuthenticationProvider", credsPath, db);
} }

View File

@@ -35,7 +35,7 @@ import java.io.IOException;
public class GoogleFirebaseBackend { public class GoogleFirebaseBackend {
private Logger log = LoggerFactory.getLogger(GoogleFirebaseBackend.class); private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseBackend.class);
private boolean isEnabled; private boolean isEnabled;
private FirebaseAuth fbAuth; private FirebaseAuth fbAuth;
@@ -60,7 +60,9 @@ public class GoogleFirebaseBackend {
private FirebaseCredential getCreds(String credsPath) throws IOException { private FirebaseCredential getCreds(String credsPath) throws IOException {
if (StringUtils.isNotBlank(credsPath)) { if (StringUtils.isNotBlank(credsPath)) {
return FirebaseCredentials.fromCertificate(new FileInputStream(credsPath)); try (FileInputStream is = new FileInputStream(credsPath)) {
return FirebaseCredentials.fromCertificate(is);
}
} else { } else {
return FirebaseCredentials.applicationDefault(); return FirebaseCredentials.applicationDefault();
} }

View File

@@ -25,6 +25,7 @@ import com.google.firebase.tasks.OnFailureListener;
import com.google.firebase.tasks.OnSuccessListener; import com.google.firebase.tasks.OnSuccessListener;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
@@ -40,9 +41,13 @@ import java.util.concurrent.TimeUnit;
public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements IThreePidProvider { public class GoogleFirebaseProvider extends GoogleFirebaseBackend implements IThreePidProvider {
private Logger log = LoggerFactory.getLogger(GoogleFirebaseProvider.class); private transient final Logger log = LoggerFactory.getLogger(GoogleFirebaseProvider.class);
private String domain; private String domain;
public GoogleFirebaseProvider(MxisdConfig cfg) {
this(cfg.getFirebase().isEnabled(), cfg.getFirebase().getCredentials(), cfg.getFirebase().getDatabase(), cfg.getMatrix().getDomain());
}
public GoogleFirebaseProvider(boolean isEnabled, String credsPath, String db, String domain) { public GoogleFirebaseProvider(boolean isEnabled, String credsPath, String db, String domain) {
super(isEnabled, "ThreePidProvider", credsPath, db); super(isEnabled, "ThreePidProvider", credsPath, db);
this.domain = domain; this.domain = domain;

View File

@@ -1,6 +1,6 @@
/* /*
* mxisd - Matrix Identity Server Daemon * mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Kamax Sarl * Copyright (C) 2018 Kamax Sarl
* *
* https://www.kamax.io/ * https://www.kamax.io/
* *
@@ -18,21 +18,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.kamax.mxisd.spring; package io.kamax.mxisd.backend.firebase;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.Mxisd;
import org.springframework.boot.diagnostics.AbstractFailureAnalyzer; import io.kamax.mxisd.auth.AuthProviders;
import org.springframework.boot.diagnostics.FailureAnalysis; import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.lookup.ThreePidProviders;
public class ConfigurationFailureAnalyzer extends AbstractFailureAnalyzer<ConfigurationException> { public class GoogleFirebaseStoreSupplier implements IdentityStoreSupplier {
@Override @Override
protected FailureAnalysis analyze(Throwable rootFailure, ConfigurationException cause) { public void accept(Mxisd mxisd) {
String message = cause.getMessage(); accept(mxisd.getConfig());
if (cause.getDetailedMessage().isPresent()) { }
message += " - " + cause.getDetailedMessage().get();
public void accept(MxisdConfig cfg) {
if (cfg.getFirebase().isEnabled()) {
AuthProviders.register(() -> new GoogleFirebaseAuthenticator(cfg.getFirebase()));
ThreePidProviders.register(() -> new GoogleFirebaseProvider(cfg));
} }
return new FailureAnalysis(message, "Double check the key value", cause);
} }
} }

View File

@@ -30,6 +30,7 @@ import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.LdapConfig; import io.kamax.mxisd.config.ldap.LdapConfig;
import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.directory.api.ldap.model.cursor.CursorException; import org.apache.directory.api.ldap.model.cursor.CursorException;
@@ -42,8 +43,6 @@ 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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.HashSet; import java.util.HashSet;
@@ -51,14 +50,12 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.Set; import java.util.Set;
@Component
public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvider { public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvider {
private Logger log = LoggerFactory.getLogger(LdapAuthProvider.class); private transient final Logger log = LoggerFactory.getLogger(LdapAuthProvider.class);
private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance(); private PhoneNumberUtil phoneUtil = PhoneNumberUtil.getInstance();
@Autowired
public LdapAuthProvider(LdapConfig cfg, MatrixConfig mxCfg) { public LdapAuthProvider(LdapConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }
@@ -87,7 +84,6 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
public BackendAuthResult authenticate(_MatrixID mxid, String password) { public BackendAuthResult authenticate(_MatrixID mxid, String password) {
log.info("Performing auth for {}", mxid); log.info("Performing auth for {}", mxid);
try (LdapConnection conn = getConn()) { try (LdapConnection conn = getConn()) {
bind(conn); bind(conn);
@@ -108,11 +104,13 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
String[] attArray = new String[attributes.size()]; String[] attArray = new String[attributes.size()];
attributes.toArray(attArray); attributes.toArray(attArray);
log.debug("Base DN: {}", getBaseDn());
log.debug("Query: {}", userFilter); log.debug("Query: {}", userFilter);
log.debug("Attributes: {}", GsonUtil.build().toJson(attArray)); log.debug("Attributes: {}", GsonUtil.build().toJson(attArray));
try (EntryCursor cursor = conn.search(getBaseDn(), userFilter, SearchScope.SUBTREE, attArray)) { for (String baseDN : getBaseDNs()) {
log.debug("Base DN: {}", baseDN);
try (EntryCursor cursor = conn.search(baseDN, userFilter, SearchScope.SUBTREE, attArray)) {
while (cursor.next()) { while (cursor.next()) {
Entry entry = cursor.get(); Entry entry = cursor.get();
String dn = entry.getDn().getName(); String dn = entry.getDn().getName();
@@ -159,11 +157,12 @@ public class LdapAuthProvider extends LdapBackend implements AuthenticatorProvid
} catch (CursorLdapReferralException e) { } catch (CursorLdapReferralException e) {
log.warn("Entity for {} is only available via referral, skipping", mxid); log.warn("Entity for {} is only available via referral, skipping", mxid);
} }
}
log.info("No match were found for {}", mxid); log.info("No match were found for {}", mxid);
return BackendAuthResult.failure(); return BackendAuthResult.failure();
} catch (LdapException | IOException | CursorException e) { } catch (LdapException | IOException | CursorException e) {
throw new RuntimeException(e); throw new InternalServerError(e);
} }
} }

View File

@@ -45,7 +45,7 @@ public abstract class LdapBackend {
public static final String UID = "uid"; public static final String UID = "uid";
public static final String MATRIX_ID = "mxid"; public static final String MATRIX_ID = "mxid";
private Logger log = LoggerFactory.getLogger(LdapBackend.class); private transient final Logger log = LoggerFactory.getLogger(LdapBackend.class);
private LdapConfig cfg; private LdapConfig cfg;
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
@@ -59,8 +59,8 @@ public abstract class LdapBackend {
return cfg; return cfg;
} }
protected String getBaseDn() { protected List<String> getBaseDNs() {
return cfg.getConnection().getBaseDn(); return cfg.getConnection().getBaseDNs();
} }
protected LdapConfig.Attribute getAt() { protected LdapConfig.Attribute getAt() {

View File

@@ -22,9 +22,9 @@ package io.kamax.mxisd.backend.ldap;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.LdapConfig; import io.kamax.mxisd.config.ldap.LdapConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
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;
@@ -35,28 +35,19 @@ 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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Component public class LdapDirectoryProvider extends LdapBackend implements DirectoryProvider {
public class LdapDirectoryProvider extends LdapBackend implements IDirectoryProvider {
private Logger log = LoggerFactory.getLogger(LdapDirectoryProvider.class); private transient final Logger log = LoggerFactory.getLogger(LdapDirectoryProvider.class);
@Autowired
public LdapDirectoryProvider(LdapConfig cfg, MatrixConfig mxCfg) { public LdapDirectoryProvider(LdapConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }
@Override
public boolean isEnabled() {
return getCfg().isEnabled();
}
protected UserDirectorySearchResult search(String query, List<String> attributes) { protected UserDirectorySearchResult search(String query, List<String> attributes) {
UserDirectorySearchResult result = new UserDirectorySearchResult(); UserDirectorySearchResult result = new UserDirectorySearchResult();
result.setLimited(false); result.setLimited(false);
@@ -65,18 +56,19 @@ public class LdapDirectoryProvider extends LdapBackend implements IDirectoryProv
bind(conn); bind(conn);
LdapConfig.Attribute atCfg = getCfg().getAttribute(); LdapConfig.Attribute atCfg = getCfg().getAttribute();
attributes = new ArrayList<>(attributes); attributes = new ArrayList<>(attributes);
attributes.add(getUidAtt()); attributes.add(getUidAtt());
String[] attArray = new String[attributes.size()]; String[] attArray = new String[attributes.size()];
attributes.toArray(attArray); attributes.toArray(attArray);
String searchQuery = buildOrQueryWithFilter(getCfg().getDirectory().getFilter(), "*" + query + "*", attArray); String searchQuery = buildOrQueryWithFilter(getCfg().getDirectory().getFilter(), "*" + query + "*", attArray);
log.debug("Base DN: {}", getBaseDn());
log.debug("Query: {}", searchQuery); log.debug("Query: {}", searchQuery);
log.debug("Attributes: {}", GsonUtil.build().toJson(attArray)); log.debug("Attributes: {}", GsonUtil.build().toJson(attArray));
try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, attArray)) { for (String baseDN : getBaseDNs()) {
log.debug("Base DN: {}", baseDN);
try (EntryCursor cursor = conn.search(baseDN, searchQuery, SearchScope.SUBTREE, attArray)) {
while (cursor.next()) { while (cursor.next()) {
Entry entry = cursor.get(); Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName()); log.info("Found possible match, DN: {}", entry.getDn().getName());
@@ -93,6 +85,7 @@ public class LdapDirectoryProvider extends LdapBackend implements IDirectoryProv
}); });
} }
} }
}
} catch (CursorLdapReferralException e) { } catch (CursorLdapReferralException e) {
log.warn("An entry is only available via referral, skipping"); log.warn("An entry is only available via referral, skipping");
} catch (IOException | LdapException | CursorException e) { } catch (IOException | LdapException | CursorException e) {

View File

@@ -36,8 +36,6 @@ 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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -45,21 +43,14 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component
public class LdapProfileProvider extends LdapBackend implements ProfileProvider { public class LdapProfileProvider extends LdapBackend implements ProfileProvider {
private transient Logger log = LoggerFactory.getLogger(LdapProfileProvider.class); private transient final Logger log = LoggerFactory.getLogger(LdapProfileProvider.class);
@Autowired
public LdapProfileProvider(LdapConfig cfg, MatrixConfig mxCfg) { public LdapProfileProvider(LdapConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }
@Override
public boolean isEnabled() {
return getCfg().isEnabled();
}
@Override @Override
public Optional<String> getDisplayName(_MatrixID userId) { public Optional<String> getDisplayName(_MatrixID userId) {
String uid = buildUidFromMatrixId(userId); String uid = buildUidFromMatrixId(userId);
@@ -69,11 +60,11 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
bind(conn); bind(conn);
String searchQuery = buildOrQueryWithFilter(getCfg().getProfile().getFilter(), uid, getUidAtt()); String searchQuery = buildOrQueryWithFilter(getCfg().getProfile().getFilter(), uid, getUidAtt());
log.debug("Base DN: {}", getBaseDn());
log.debug("Query: {}", searchQuery); log.debug("Query: {}", searchQuery);
try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, getAt().getName())) { for (String baseDN : getBaseDNs()) {
log.debug("Base DN: {}", baseDN);
try (EntryCursor cursor = conn.search(baseDN, searchQuery, SearchScope.SUBTREE, getAt().getName())) {
while (cursor.next()) { while (cursor.next()) {
Entry entry = cursor.get(); Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName()); log.info("Found possible match, DN: {}", entry.getDn().getName());
@@ -92,9 +83,10 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
return v; return v;
} }
} }
}
} catch (CursorLdapReferralException e) { } catch (CursorLdapReferralException e) {
log.warn("An entry is only available via referral, skipping"); log.warn("An entry is only available via referral, skipping");
}
}
} catch (IOException | LdapException | CursorException e) { } catch (IOException | LdapException | CursorException e) {
throw new InternalServerError(e); throw new InternalServerError(e);
} }
@@ -111,7 +103,6 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
try (LdapConnection conn = getConn()) { try (LdapConnection conn = getConn()) {
bind(conn); bind(conn);
log.debug("Base DN: {}", getBaseDn());
getCfg().getAttribute().getThreepid().forEach((medium, attributes) -> { getCfg().getAttribute().getThreepid().forEach((medium, attributes) -> {
String[] attArray = new String[attributes.size()]; String[] attArray = new String[attributes.size()];
attributes.toArray(attArray); attributes.toArray(attArray);
@@ -120,7 +111,9 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
log.debug("Query for 3PID {}: {}", medium, searchQuery); log.debug("Query for 3PID {}: {}", medium, searchQuery);
try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, attArray)) { for (String baseDN : getBaseDNs()) {
log.debug("Base DN: {}", baseDN);
try (EntryCursor cursor = conn.search(baseDN, searchQuery, SearchScope.SUBTREE, attArray)) {
while (cursor.next()) { while (cursor.next()) {
Entry entry = cursor.get(); Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName()); log.info("Found possible match, DN: {}", entry.getDn().getName());
@@ -137,11 +130,11 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
} }
} catch (CursorLdapReferralException e) { } catch (CursorLdapReferralException e) {
log.warn("An entry is only available via referral, skipping"); log.warn("An entry is only available via referral, skipping");
} catch (IOException | LdapException | CursorException e) { } catch (LdapException | IOException | CursorException e) {
throw new InternalServerError(e); throw new InternalServerError(e);
} }
}
}); });
} catch (IOException | LdapException e) { } catch (IOException | LdapException e) {
throw new InternalServerError(e); throw new InternalServerError(e);
} }

View File

@@ -0,0 +1,47 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.ldap;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class LdapStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getLdap().isEnabled()) {
AuthProviders.register(() -> new LdapAuthProvider(cfg.getLdap(), cfg.getMatrix()));
DirectoryProviders.register(() -> new LdapDirectoryProvider(cfg.getLdap(), cfg.getMatrix()));
ThreePidProviders.register(() -> new LdapThreePidProvider(cfg.getLdap(), cfg.getMatrix()));
ProfileProviders.register(() -> new LdapProfileProvider(cfg.getLdap(), cfg.getMatrix()));
}
}
}

View File

@@ -37,27 +37,20 @@ 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.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
@Component
public class LdapThreePidProvider extends LdapBackend implements IThreePidProvider { public class LdapThreePidProvider extends LdapBackend implements IThreePidProvider {
private Logger log = LoggerFactory.getLogger(LdapThreePidProvider.class); private transient final Logger log = LoggerFactory.getLogger(LdapThreePidProvider.class);
public LdapThreePidProvider(LdapConfig cfg, MatrixConfig mxCfg) { public LdapThreePidProvider(LdapConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }
@Override
public boolean isEnabled() {
return getCfg().isEnabled();
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;
@@ -78,12 +71,13 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
// we merge 3PID specific query with global/specific filter, if one exists. // we merge 3PID specific query with global/specific filter, if one exists.
String tPidQuery = tPidQueryOpt.get().replaceAll(getCfg().getIdentity().getToken(), value); String tPidQuery = tPidQueryOpt.get().replaceAll(getCfg().getIdentity().getToken(), value);
String searchQuery = buildWithFilter(tPidQuery, getCfg().getIdentity().getFilter()); String searchQuery = buildWithFilter(tPidQuery, getCfg().getIdentity().getFilter());
log.debug("Base DN: {}", getBaseDn());
log.debug("Query: {}", searchQuery); log.debug("Query: {}", searchQuery);
log.debug("Attributes: {}", GsonUtil.build().toJson(getUidAtt())); log.debug("Attributes: {}", GsonUtil.build().toJson(getUidAtt()));
try (EntryCursor cursor = conn.search(getBaseDn(), searchQuery, SearchScope.SUBTREE, getUidAtt())) { for (String baseDN : getBaseDNs()) {
log.debug("Base DN: {}", baseDN);
try (EntryCursor cursor = conn.search(baseDN, searchQuery, SearchScope.SUBTREE, getUidAtt())) {
while (cursor.next()) { while (cursor.next()) {
Entry entry = cursor.get(); Entry entry = cursor.get();
log.info("Found possible match, DN: {}", entry.getDn().getName()); log.info("Found possible match, DN: {}", entry.getDn().getName());
@@ -101,6 +95,7 @@ public class LdapThreePidProvider extends LdapBackend implements IThreePidProvid
} catch (IOException | LdapException | CursorException e) { } catch (IOException | LdapException | CursorException e) {
throw new InternalServerError(e); throw new InternalServerError(e);
} }
}
return Optional.empty(); return Optional.empty();
} }

View File

@@ -23,9 +23,7 @@ package io.kamax.mxisd.backend.ldap.netiq;
import io.kamax.mxisd.backend.ldap.LdapAuthProvider; import io.kamax.mxisd.backend.ldap.LdapAuthProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig; import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig;
import org.springframework.stereotype.Component;
@Component
public class NetIqLdapAuthProvider extends LdapAuthProvider { public class NetIqLdapAuthProvider extends LdapAuthProvider {
public NetIqLdapAuthProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) { public NetIqLdapAuthProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) {

View File

@@ -23,9 +23,7 @@ package io.kamax.mxisd.backend.ldap.netiq;
import io.kamax.mxisd.backend.ldap.LdapDirectoryProvider; import io.kamax.mxisd.backend.ldap.LdapDirectoryProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig; import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig;
import org.springframework.stereotype.Component;
@Component
public class NetIqLdapDirectoryProvider extends LdapDirectoryProvider { public class NetIqLdapDirectoryProvider extends LdapDirectoryProvider {
public NetIqLdapDirectoryProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) { public NetIqLdapDirectoryProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) {

View File

@@ -24,13 +24,9 @@ import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.backend.ldap.LdapProfileProvider; import io.kamax.mxisd.backend.ldap.LdapProfileProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig; import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class NetIqLdapProfileProvider extends LdapProfileProvider { public class NetIqLdapProfileProvider extends LdapProfileProvider {
@Autowired
public NetIqLdapProfileProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) { public NetIqLdapProfileProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }

View File

@@ -0,0 +1,47 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.ldap.netiq;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class NetIqLdapStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getNetiq().isEnabled()) {
AuthProviders.register(() -> new NetIqLdapAuthProvider(cfg.getNetiq(), cfg.getMatrix()));
DirectoryProviders.register(() -> new NetIqLdapDirectoryProvider(cfg.getNetiq(), cfg.getMatrix()));
ThreePidProviders.register(() -> new NetIqLdapThreePidProvider(cfg.getNetiq(), cfg.getMatrix()));
ProfileProviders.register(() -> new NetIqLdapProfileProvider(cfg.getNetiq(), cfg.getMatrix()));
}
}
}

View File

@@ -23,9 +23,7 @@ package io.kamax.mxisd.backend.ldap.netiq;
import io.kamax.mxisd.backend.ldap.LdapThreePidProvider; import io.kamax.mxisd.backend.ldap.LdapThreePidProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig; import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig;
import org.springframework.stereotype.Component;
@Component
public class NetIqLdapThreePidProvider extends LdapThreePidProvider { public class NetIqLdapThreePidProvider extends LdapThreePidProvider {
public NetIqLdapThreePidProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) { public NetIqLdapThreePidProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) {

View File

@@ -31,8 +31,8 @@ import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.memory.MemoryIdentityConfig; import io.kamax.mxisd.config.memory.MemoryIdentityConfig;
import io.kamax.mxisd.config.memory.MemoryStoreConfig; import io.kamax.mxisd.config.memory.MemoryStoreConfig;
import io.kamax.mxisd.config.memory.MemoryThreePid; import io.kamax.mxisd.config.memory.MemoryThreePid;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.directory.IDirectoryProvider; import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
@@ -41,8 +41,6 @@ import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -51,15 +49,13 @@ import java.util.Optional;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate; import java.util.function.Predicate;
@Component public class MemoryIdentityStore implements AuthenticatorProvider, DirectoryProvider, IThreePidProvider, ProfileProvider {
public class MemoryIdentityStore implements AuthenticatorProvider, IDirectoryProvider, IThreePidProvider, ProfileProvider {
private final Logger logger = LoggerFactory.getLogger(MemoryIdentityStore.class); private transient final Logger logger = LoggerFactory.getLogger(MemoryIdentityStore.class);
private final MatrixConfig mxCfg; private final MatrixConfig mxCfg;
private final MemoryStoreConfig cfg; private final MemoryStoreConfig cfg;
@Autowired
public MemoryIdentityStore(MatrixConfig mxCfg, MemoryStoreConfig cfg) { public MemoryIdentityStore(MatrixConfig mxCfg, MemoryStoreConfig cfg) {
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
this.cfg = cfg; this.cfg = cfg;

View File

@@ -0,0 +1,51 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.memory;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
import java.util.function.Supplier;
public class MemoryIdentityStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getMemory().isEnabled()) {
Supplier<MemoryIdentityStore> supplier = () -> new MemoryIdentityStore(cfg.getMatrix(), cfg.getMemory());
AuthProviders.register(supplier);
DirectoryProviders.register(supplier);
ThreePidProviders.register(supplier);
ProfileProviders.register(supplier);
}
}
}

View File

@@ -27,15 +27,11 @@ import io.kamax.mxisd.config.rest.RestBackendConfig;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
@Component
public class RestAuthProvider extends RestProvider implements AuthenticatorProvider { public class RestAuthProvider extends RestProvider implements AuthenticatorProvider {
@Autowired
public RestAuthProvider(RestBackendConfig cfg) { public RestAuthProvider(RestBackendConfig cfg) {
super(cfg); super(cfg);
} }

View File

@@ -23,21 +23,18 @@ package io.kamax.mxisd.backend.rest;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.rest.RestBackendConfig; import io.kamax.mxisd.config.rest.RestBackendConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.http.io.UserDirectorySearchRequest;
import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.CloseableHttpResponse;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
@Component public class RestDirectoryProvider extends RestProvider implements DirectoryProvider {
public class RestDirectoryProvider extends RestProvider implements IDirectoryProvider {
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
@@ -46,11 +43,6 @@ public class RestDirectoryProvider extends RestProvider implements IDirectoryPro
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled() && StringUtils.isNotBlank(cfg.getEndpoints().getDirectory());
}
private UserDirectorySearchResult search(String by, String query) { private UserDirectorySearchResult search(String by, String query) {
UserDirectorySearchRequest request = new UserDirectorySearchRequest(query); UserDirectorySearchRequest request = new UserDirectorySearchRequest(query);
request.setBy(by); request.setBy(by);

View File

@@ -0,0 +1,140 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.rest;
import com.google.gson.JsonObject;
import com.google.gson.JsonSyntaxException;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.matrix.json.InvalidJsonException;
import io.kamax.mxisd.config.rest.RestBackendConfig;
import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.profile.JsonProfileRequest;
import io.kamax.mxisd.profile.JsonProfileResult;
import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;
public class RestProfileProvider extends RestProvider implements ProfileProvider {
private transient final Logger log = LoggerFactory.getLogger(RestProfileProvider.class);
public RestProfileProvider(RestBackendConfig cfg) {
super(cfg);
}
private <T> Optional<T> doRequest(
_MatrixID userId,
Function<RestBackendConfig.ProfileEndpoints, Optional<String>> endpoint,
Function<JsonProfileResult, Optional<T>> value
) {
return cfg.getEndpoints().getProfile()
// We get the endpoint
.flatMap(endpoint)
// We only continue if there is a value
.filter(StringUtils::isNotBlank)
// We use the endpoint
.flatMap(url -> {
try {
URIBuilder builder = new URIBuilder(url);
HttpPost req = new HttpPost(builder.build());
req.setEntity(new StringEntity(GsonUtil.get().toJson(new JsonProfileRequest(userId)), ContentType.APPLICATION_JSON));
try (CloseableHttpResponse res = client.execute(req)) {
int sc = res.getStatusLine().getStatusCode();
if (sc == 404) {
log.info("Got 404 - No result found");
return Optional.empty();
}
if (sc != 200) {
throw new InternalServerError("Unexpected backed status code: " + sc);
}
String body = IOUtils.toString(res.getEntity().getContent(), StandardCharsets.UTF_8);
if (StringUtils.isBlank(body)) {
log.warn("Backend response body is empty/blank, expected JSON object with profile key");
return Optional.empty();
}
Optional<JsonObject> pJson = GsonUtil.findObj(GsonUtil.parseObj(body), "profile");
if (!pJson.isPresent()) {
log.warn("Backend response body is invalid, expected JSON object with profile key");
return Optional.empty();
}
JsonProfileResult profile = gson.fromJson(pJson.get(), JsonProfileResult.class);
return value.apply(profile);
}
} catch (JsonSyntaxException | InvalidJsonException e) {
log.error("Unable to parse backend response as JSON", e);
throw new InternalServerError(e);
} catch (URISyntaxException e) {
log.error("Unable to build a valid request URL", e);
throw new InternalServerError(e);
} catch (IOException e) {
log.error("I/O Error during backend request", e);
throw new InternalServerError();
}
});
}
@Override
public Optional<String> getDisplayName(_MatrixID userId) {
return doRequest(userId, p -> Optional.ofNullable(p.getDisplayName()), profile -> Optional.ofNullable(profile.getDisplayName()));
}
@Override
public List<_ThreePid> getThreepids(_MatrixID userId) {
return doRequest(userId, p -> Optional.ofNullable(p.getThreepids()), profile -> {
List<_ThreePid> t = new ArrayList<>();
if (Objects.nonNull(profile.getThreepids())) {
t.addAll(profile.getThreepids());
}
return Optional.of(t);
}).orElseGet(Collections::emptyList);
}
@Override
public List<String> getRoles(_MatrixID userId) {
return doRequest(userId, p -> Optional.ofNullable(p.getRoles()), profile -> {
List<String> t = new ArrayList<>();
if (Objects.nonNull(profile.getRoles())) {
t.addAll(profile.getRoles());
}
return Optional.of(t);
}).orElseGet(Collections::emptyList);
}
}

View File

@@ -0,0 +1,47 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.rest;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class RestStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getRest().isEnabled()) {
AuthProviders.register(() -> new RestAuthProvider(cfg.getRest()));
DirectoryProviders.register(() -> new RestDirectoryProvider(cfg.getRest(), cfg.getMatrix()));
ThreePidProviders.register(() -> new RestThreePidProvider(cfg.getRest(), cfg.getMatrix()));
ProfileProviders.register(() -> new RestProfileProvider(cfg.getRest()));
}
}
}

View File

@@ -35,8 +35,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.client.methods.HttpUriRequest;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
@@ -44,14 +42,12 @@ import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Component
public class RestThreePidProvider extends RestProvider implements IThreePidProvider { public class RestThreePidProvider extends RestProvider implements IThreePidProvider {
private Logger log = LoggerFactory.getLogger(RestThreePidProvider.class); private transient final Logger log = LoggerFactory.getLogger(RestThreePidProvider.class);
private MatrixConfig mxCfg; // FIXME should be done in the lookup manager private MatrixConfig mxCfg; // FIXME should be done in the lookup manager
@Autowired
public RestThreePidProvider(RestBackendConfig cfg, MatrixConfig mxCfg) { public RestThreePidProvider(RestBackendConfig cfg, MatrixConfig mxCfg) {
super(cfg); super(cfg);
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
@@ -66,11 +62,6 @@ public class RestThreePidProvider extends RestProvider implements IThreePidProvi
} }
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;

View File

@@ -0,0 +1,55 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2019 Kamax Sàrl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.sql;
import org.apache.commons.lang3.StringUtils;
public class BuiltInDriverLoader implements DriverLoader {
@Override
public void accept(String s) {
String className = null;
if (StringUtils.equals("sqlite", s)) {
className = "org.sqlite.JDBC";
}
if (StringUtils.equals("postgresql", s)) {
className = "org.postgresql.Driver";
}
if (StringUtils.equals("mariadb", s)) {
className = "org.mariadb.jdbc.Driver";
}
if (StringUtils.equals("mysql", s)) {
className = "org.mariadb.jdbc.Driver";
}
if (StringUtils.isNotEmpty(className)) {
try {
Class.forName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
}

View File

@@ -0,0 +1,26 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2019 Kamax Sàrl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.sql;
import java.util.function.Consumer;
public interface DriverLoader extends Consumer<String> {
}

View File

@@ -1,6 +1,6 @@
/* /*
* mxisd - Matrix Identity Server Daemon * mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Kamax Sarl * Copyright (C) 2019 Kamax Sàrl
* *
* https://www.kamax.io/ * https://www.kamax.io/
* *
@@ -18,16 +18,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package io.kamax.mxisd; package io.kamax.mxisd.backend.sql;
import org.springframework.boot.SpringApplication; import java.util.Objects;
import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.ServiceLoader;
@SpringBootApplication public class Drivers {
public class MatrixIdentityServerApplication {
public static void main(String[] args) { private static ServiceLoader<DriverLoader> svcLoader;
SpringApplication.run(MatrixIdentityServerApplication.class, args);
public static void load(String type) {
if (Objects.isNull(svcLoader)) {
svcLoader = ServiceLoader.load(DriverLoader.class);
}
svcLoader.iterator().forEachRemaining(drv -> drv.accept(type));
} }
} }

View File

@@ -37,11 +37,15 @@ public class SqlConnectionPool {
private ComboPooledDataSource ds; private ComboPooledDataSource ds;
public SqlConnectionPool(SqlConfig cfg) { public SqlConnectionPool(SqlConfig cfg) {
Drivers.load(cfg.getType());
ds = new ComboPooledDataSource(); ds = new ComboPooledDataSource();
ds.setJdbcUrl("jdbc:" + cfg.getType() + ":" + cfg.getConnection()); ds.setJdbcUrl("jdbc:" + cfg.getType() + ":" + cfg.getConnection());
ds.setMinPoolSize(1); ds.setMinPoolSize(1);
ds.setMaxPoolSize(10); ds.setMaxPoolSize(10);
ds.setAcquireIncrement(2); ds.setAcquireIncrement(2);
ds.setAcquireRetryAttempts(10);
ds.setAcquireRetryDelay(1000);
} }
public Connection get() throws SQLException { public Connection get() throws SQLException {

View File

@@ -39,7 +39,7 @@ import java.util.Optional;
public abstract class SqlProfileProvider implements ProfileProvider { public abstract class SqlProfileProvider implements ProfileProvider {
private Logger log = LoggerFactory.getLogger(SqlProfileProvider.class); private transient final Logger log = LoggerFactory.getLogger(SqlProfileProvider.class);
private SqlConfig.Profile cfg; private SqlConfig.Profile cfg;
@@ -50,11 +50,6 @@ public abstract class SqlProfileProvider implements ProfileProvider {
this.pool = new SqlConnectionPool(cfg); this.pool = new SqlConnectionPool(cfg);
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
@Override @Override
public Optional<String> getDisplayName(_MatrixID user) { public Optional<String> getDisplayName(_MatrixID user) {
String stmtSql = cfg.getDisplayName().getQuery(); String stmtSql = cfg.getDisplayName().getQuery();

View File

@@ -41,7 +41,7 @@ import java.util.Optional;
public abstract class SqlThreePidProvider implements IThreePidProvider { public abstract class SqlThreePidProvider implements IThreePidProvider {
private Logger log = LoggerFactory.getLogger(SqlThreePidProvider.class); private transient final Logger log = LoggerFactory.getLogger(SqlThreePidProvider.class);
private SqlConfig cfg; private SqlConfig cfg;
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
@@ -54,11 +54,6 @@ public abstract class SqlThreePidProvider implements IThreePidProvider {
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return cfg.isEnabled();
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;

View File

@@ -27,20 +27,19 @@ import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import io.kamax.mxisd.invitation.InvitationManager; import io.kamax.mxisd.invitation.InvitationManager;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class GenericSqlAuthProvider implements AuthenticatorProvider { public class GenericSqlAuthProvider implements AuthenticatorProvider {
private Logger log = LoggerFactory.getLogger(GenericSqlAuthProvider.class); private transient final Logger log = LoggerFactory.getLogger(GenericSqlAuthProvider.class);
@Autowired
private GenericSqlProviderConfig cfg; private GenericSqlProviderConfig cfg;
@Autowired
private InvitationManager invMgr; private InvitationManager invMgr;
public GenericSqlAuthProvider(GenericSqlProviderConfig cfg, InvitationManager invMgr) {
this.cfg = cfg;
this.invMgr = invMgr;
}
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return cfg.getAuth().isEnabled(); return cfg.getAuth().isEnabled();

View File

@@ -25,9 +25,9 @@ import io.kamax.mxisd.backend.sql.SqlConnectionPool;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.sql.SqlConfig; import io.kamax.mxisd.config.sql.SqlConfig;
import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig; import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -38,11 +38,11 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Optional; import java.util.Optional;
import static io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult.Result; import static io.kamax.mxisd.http.io.UserDirectorySearchResult.Result;
public abstract class GenericSqlDirectoryProvider implements IDirectoryProvider { public class GenericSqlDirectoryProvider implements DirectoryProvider {
private Logger log = LoggerFactory.getLogger(GenericSqlDirectoryProvider.class); private transient final Logger log = LoggerFactory.getLogger(GenericSqlDirectoryProvider.class);
protected SqlConfig cfg; protected SqlConfig cfg;
protected MatrixConfig mxCfg; protected MatrixConfig mxCfg;
@@ -55,11 +55,6 @@ public abstract class GenericSqlDirectoryProvider implements IDirectoryProvider
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return cfg.getDirectory().isEnabled();
}
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException { protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) { for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) {
stmt.setString(i, searchTerm); stmt.setString(i, searchTerm);

View File

@@ -22,9 +22,7 @@ package io.kamax.mxisd.backend.sql.generic;
import io.kamax.mxisd.backend.sql.SqlProfileProvider; import io.kamax.mxisd.backend.sql.SqlProfileProvider;
import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig; import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import org.springframework.stereotype.Component;
@Component
public class GenericSqlProfileProvider extends SqlProfileProvider { public class GenericSqlProfileProvider extends SqlProfileProvider {
public GenericSqlProfileProvider(GenericSqlProviderConfig cfg) { public GenericSqlProfileProvider(GenericSqlProviderConfig cfg) {

View File

@@ -0,0 +1,51 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.sql.generic;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class GenericSqlStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
if (mxisd.getConfig().getSql().getAuth().isEnabled()) {
AuthProviders.register(() -> new GenericSqlAuthProvider(mxisd.getConfig().getSql(), mxisd.getInvitationManager()));
}
if (mxisd.getConfig().getSql().getDirectory().isEnabled()) {
DirectoryProviders.register(() -> new GenericSqlDirectoryProvider(mxisd.getConfig().getSql(), mxisd.getConfig().getMatrix()));
}
if (mxisd.getConfig().getSql().getIdentity().isEnabled()) {
ThreePidProviders.register(() -> new GenericSqlThreePidProvider(mxisd.getConfig().getSql(), mxisd.getConfig().getMatrix()));
}
if (mxisd.getConfig().getSql().getProfile().isEnabled()) {
ProfileProviders.register(() -> new GenericSqlProfileProvider(mxisd.getConfig().getSql()));
}
}
}

View File

@@ -23,13 +23,9 @@ package io.kamax.mxisd.backend.sql.generic;
import io.kamax.mxisd.backend.sql.SqlThreePidProvider; import io.kamax.mxisd.backend.sql.SqlThreePidProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig; import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class GenericSqlThreePidProvider extends SqlThreePidProvider { public class GenericSqlThreePidProvider extends SqlThreePidProvider {
@Autowired
public GenericSqlThreePidProvider(GenericSqlProviderConfig cfg, MatrixConfig mxCfg) { public GenericSqlThreePidProvider(GenericSqlProviderConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }

View File

@@ -22,19 +22,15 @@ package io.kamax.mxisd.backend.sql.synapse;
import io.kamax.mxisd.backend.sql.SqlConnectionPool; import io.kamax.mxisd.backend.sql.SqlConnectionPool;
import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig; import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.Optional; import java.util.Optional;
@Component
public class Synapse { public class Synapse {
private SqlConnectionPool pool; private SqlConnectionPool pool;
@Autowired
public Synapse(SynapseSqlProviderConfig sqlCfg) { public Synapse(SynapseSqlProviderConfig sqlCfg) {
this.pool = new SqlConnectionPool(sqlCfg); this.pool = new SqlConnectionPool(sqlCfg);
} }

View File

@@ -24,32 +24,15 @@ import io.kamax.mxisd.backend.sql.generic.GenericSqlDirectoryProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig; import io.kamax.mxisd.config.sql.generic.GenericSqlProviderConfig;
import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig; import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Objects; import java.util.Objects;
@Component
public class SynapseSqlDirectoryProvider extends GenericSqlDirectoryProvider { public class SynapseSqlDirectoryProvider extends GenericSqlDirectoryProvider {
@Autowired
public SynapseSqlDirectoryProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) { public SynapseSqlDirectoryProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
}
@Override
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
stmt.setString(1, "%" + searchTerm + "%");
}
@PostConstruct
public void build() {
if (!isEnabled()) {
return;
}
GenericSqlProviderConfig.Type queries = cfg.getDirectory().getQuery(); GenericSqlProviderConfig.Type queries = cfg.getDirectory().getQuery();
if (Objects.isNull(queries.getName().getValue())) { if (Objects.isNull(queries.getName().getValue())) {
@@ -60,4 +43,9 @@ public class SynapseSqlDirectoryProvider extends GenericSqlDirectoryProvider {
} }
} }
@Override
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
stmt.setString(1, "%" + searchTerm + "%");
}
} }

View File

@@ -22,13 +22,9 @@ package io.kamax.mxisd.backend.sql.synapse;
import io.kamax.mxisd.backend.sql.SqlProfileProvider; import io.kamax.mxisd.backend.sql.SqlProfileProvider;
import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig; import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SynapseSqlProfileProvider extends SqlProfileProvider { public class SynapseSqlProfileProvider extends SqlProfileProvider {
@Autowired
public SynapseSqlProfileProvider(SynapseSqlProviderConfig cfg) { public SynapseSqlProfileProvider(SynapseSqlProviderConfig cfg) {
super(cfg); super(cfg);
} }

View File

@@ -0,0 +1,51 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.sql.synapse;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MxisdConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
import io.kamax.mxisd.profile.ProfileProviders;
public class SynapseSqlStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd mxisd) {
accept(mxisd.getConfig());
}
public void accept(MxisdConfig cfg) {
if (cfg.getSynapseSql().getDirectory().isEnabled()) {
DirectoryProviders.register(() -> new SynapseSqlDirectoryProvider(cfg.getSynapseSql(), cfg.getMatrix()));
}
if (cfg.getSynapseSql().getIdentity().isEnabled()) {
ThreePidProviders.register(() -> new SynapseSqlThreePidProvider(cfg.getSynapseSql(), cfg.getMatrix()));
}
if (cfg.getSynapseSql().getProfile().isEnabled()) {
ProfileProviders.register(() -> new SynapseSqlProfileProvider(cfg.getSynapseSql()));
}
}
}

View File

@@ -23,13 +23,9 @@ package io.kamax.mxisd.backend.sql.synapse;
import io.kamax.mxisd.backend.sql.SqlThreePidProvider; import io.kamax.mxisd.backend.sql.SqlThreePidProvider;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig; import io.kamax.mxisd.config.sql.synapse.SynapseSqlProviderConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SynapseSqlThreePidProvider extends SqlThreePidProvider { public class SynapseSqlThreePidProvider extends SqlThreePidProvider {
@Autowired
public SynapseSqlThreePidProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) { public SynapseSqlThreePidProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
} }

View File

@@ -28,17 +28,13 @@ import io.kamax.mxisd.auth.provider.BackendAuthResult;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class WordpressAuthProvider implements AuthenticatorProvider { public class WordpressAuthProvider implements AuthenticatorProvider {
private final Logger log = LoggerFactory.getLogger(WordpressAuthProvider.class); private transient final Logger log = LoggerFactory.getLogger(WordpressAuthProvider.class);
private WordpressRestBackend wordpress; private WordpressRestBackend wordpress;
@Autowired
public WordpressAuthProvider(WordpressRestBackend wordpress) { public WordpressAuthProvider(WordpressRestBackend wordpress) {
this.wordpress = wordpress; this.wordpress = wordpress;
} }

View File

@@ -23,13 +23,11 @@ package io.kamax.mxisd.backend.wordpress;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.wordpress.WordpressConfig; import io.kamax.mxisd.config.wordpress.WordpressConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.directory.DirectoryProvider;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.http.io.UserDirectorySearchResult;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@@ -37,27 +35,20 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Optional; import java.util.Optional;
@Component public class WordpressDirectoryProvider implements DirectoryProvider {
public class WordpressDirectoryProvider implements IDirectoryProvider {
private final Logger log = LoggerFactory.getLogger(WordpressDirectoryProvider.class); private transient final Logger log = LoggerFactory.getLogger(WordpressDirectoryProvider.class);
private WordpressConfig cfg; private WordpressConfig cfg;
private WordressSqlBackend wordpress; private WordressSqlBackend wordpress;
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
@Autowired
public WordpressDirectoryProvider(WordpressConfig cfg, WordressSqlBackend wordpress, MatrixConfig mxCfg) { public WordpressDirectoryProvider(WordpressConfig cfg, WordressSqlBackend wordpress, MatrixConfig mxCfg) {
this.cfg = cfg; this.cfg = cfg;
this.wordpress = wordpress; this.wordpress = wordpress;
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
} }
@Override
public boolean isEnabled() {
return wordpress.isEnabled();
}
protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException { protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) { for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) {
stmt.setString(i, "%" + searchTerm + "%"); stmt.setString(i, "%" + searchTerm + "%");

View File

@@ -34,15 +34,12 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils; import org.apache.http.util.EntityUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.IOException; import java.io.IOException;
@Component
public class WordpressRestBackend { public class WordpressRestBackend {
private final Logger log = LoggerFactory.getLogger(WordpressRestBackend.class); private transient final Logger log = LoggerFactory.getLogger(WordpressRestBackend.class);
private final String jsonPath = "/wp-json"; private final String jsonPath = "/wp-json";
private final String jwtPath = "/jwt-auth/v1"; private final String jwtPath = "/jwt-auth/v1";
@@ -54,7 +51,6 @@ public class WordpressRestBackend {
private String token; private String token;
@Autowired
public WordpressRestBackend(WordpressConfig cfg, CloseableHttpClient client) { public WordpressRestBackend(WordpressConfig cfg, CloseableHttpClient client) {
this.cfg = cfg; this.cfg = cfg;
this.client = client; this.client = client;

View File

@@ -0,0 +1,48 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.backend.wordpress;
import io.kamax.mxisd.Mxisd;
import io.kamax.mxisd.auth.AuthProviders;
import io.kamax.mxisd.backend.IdentityStoreSupplier;
import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.wordpress.WordpressConfig;
import io.kamax.mxisd.directory.DirectoryProviders;
import io.kamax.mxisd.lookup.ThreePidProviders;
public class WordpressStoreSupplier implements IdentityStoreSupplier {
@Override
public void accept(Mxisd m) {
WordpressConfig wpCfg = m.getConfig().getWordpress();
MatrixConfig mxCfg = m.getConfig().getMatrix();
if (m.getConfig().getWordpress().isEnabled()) {
WordpressRestBackend restBackend = new WordpressRestBackend(wpCfg, m.getHttpClient());
WordressSqlBackend sqlBackend = new WordressSqlBackend(wpCfg);
AuthProviders.register(() -> new WordpressAuthProvider(restBackend));
DirectoryProviders.register(() -> new WordpressDirectoryProvider(wpCfg, sqlBackend, mxCfg));
ThreePidProviders.register(() -> new WordpressThreePidProvider(mxCfg, wpCfg, sqlBackend));
}
}
}

View File

@@ -31,8 +31,6 @@ import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider; import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
@@ -42,27 +40,20 @@ import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Optional; import java.util.Optional;
@Component
public class WordpressThreePidProvider implements IThreePidProvider { public class WordpressThreePidProvider implements IThreePidProvider {
private final Logger log = LoggerFactory.getLogger(WordpressThreePidProvider.class); private transient final Logger log = LoggerFactory.getLogger(WordpressThreePidProvider.class);
private MatrixConfig mxCfg; private MatrixConfig mxCfg;
private WordpressConfig cfg; private WordpressConfig cfg;
private WordressSqlBackend wordpress; private WordressSqlBackend wordpress;
@Autowired
public WordpressThreePidProvider(MatrixConfig mxCfg, WordpressConfig cfg, WordressSqlBackend wordpress) { public WordpressThreePidProvider(MatrixConfig mxCfg, WordpressConfig cfg, WordressSqlBackend wordpress) {
this.mxCfg = mxCfg; this.mxCfg = mxCfg;
this.cfg = cfg; this.cfg = cfg;
this.wordpress = wordpress; this.wordpress = wordpress;
} }
@Override
public boolean isEnabled() {
return wordpress.isEnabled();
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;

View File

@@ -24,22 +24,17 @@ import com.mchange.v2.c3p0.ComboPooledDataSource;
import io.kamax.mxisd.config.wordpress.WordpressConfig; import io.kamax.mxisd.config.wordpress.WordpressConfig;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
@Component
public class WordressSqlBackend { public class WordressSqlBackend {
private Logger log = LoggerFactory.getLogger(WordressSqlBackend.class); private transient final Logger log = LoggerFactory.getLogger(WordressSqlBackend.class);
private WordpressConfig cfg; private WordpressConfig cfg;
private ComboPooledDataSource ds; private ComboPooledDataSource ds;
@Autowired
public WordressSqlBackend(WordpressConfig cfg) { public WordressSqlBackend(WordpressConfig cfg) {
this.cfg = cfg; this.cfg = cfg;

View File

@@ -0,0 +1,103 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2018 Kamax Sarl
*
* https://www.kamax.io/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package io.kamax.mxisd.config;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
public class AuthenticationConfig {
public static class Rule {
private String regex;
private transient Pattern pattern;
private String medium;
public String getRegex() {
return regex;
}
public void setRegex(String regex) {
this.regex = regex;
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
public String getMedium() {
return medium;
}
public void setMedium(String medium) {
this.medium = medium;
}
}
public static class User {
private List<Rule> rules = new ArrayList<>();
public List<Rule> getRules() {
return rules;
}
public void setRules(List<Rule> mappings) {
this.rules = mappings;
}
}
public static class Rewrite {
private User user = new User();
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
private Rewrite rewrite = new Rewrite();
public Rewrite getRewrite() {
return rewrite;
}
public void setRewrite(Rewrite rewrite) {
this.rewrite = rewrite;
}
public void build() {
getRewrite().getUser().getRules().forEach(mapping -> mapping.setPattern(Pattern.compile(mapping.getRegex())));
}
}

View File

@@ -20,14 +20,8 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.Objects; import java.util.Objects;
@Configuration
@ConfigurationProperties(prefix = "lookup.bulk")
public class BulkLookupConfig { public class BulkLookupConfig {
private Boolean enabled; private Boolean enabled;
@@ -40,7 +34,6 @@ public class BulkLookupConfig {
this.enabled = enabled; this.enabled = enabled;
} }
@PostConstruct
public void build() { public void build() {
if (Objects.isNull(enabled)) { if (Objects.isNull(enabled)) {
enabled = true; enabled = true;

View File

@@ -22,16 +22,10 @@ package io.kamax.mxisd.config;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
@ConfigurationProperties("directory")
public class DirectoryConfig { public class DirectoryConfig {
private final transient Logger log = LoggerFactory.getLogger(DnsOverwriteConfig.class); private final static Logger log = LoggerFactory.getLogger(DirectoryConfig.class);
public static class Exclude { public static class Exclude {
@@ -67,8 +61,7 @@ public class DirectoryConfig {
this.exclude = exclude; this.exclude = exclude;
} }
@PostConstruct public void build() {
public void buid() {
log.info("--- Directory config ---"); log.info("--- Directory config ---");
log.info("Exclude:"); log.info("Exclude:");
log.info("\tHomeserver: {}", getExclude().getHomeserver()); log.info("\tHomeserver: {}", getExclude().getHomeserver());

View File

@@ -24,18 +24,13 @@ import com.google.gson.Gson;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Configuration
@ConfigurationProperties("dns.overwrite")
public class DnsOverwriteConfig { public class DnsOverwriteConfig {
private Logger log = LoggerFactory.getLogger(DnsOverwriteConfig.class); private transient final Logger log = LoggerFactory.getLogger(DnsOverwriteConfig.class);
public static class Entry { public static class Entry {
@@ -93,7 +88,6 @@ public class DnsOverwriteConfig {
this.homeserver = homeserver; this.homeserver = homeserver;
} }
@PostConstruct
public void build() { public void build() {
Gson gson = GsonUtil.build(); Gson gson = GsonUtil.build();
log.info("--- DNS Overwrite config ---"); log.info("--- DNS Overwrite config ---");

View File

@@ -21,14 +21,9 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import java.util.*; import java.util.*;
@Configuration
@ConfigurationProperties("exec")
public class ExecConfig { public class ExecConfig {
public class IO { public class IO {
@@ -516,8 +511,7 @@ public class ExecConfig {
this.profile = profile; this.profile = profile;
} }
@PostConstruct public ExecConfig build() {
public ExecConfig compute() {
if (Objects.isNull(getAuth().isEnabled())) { if (Objects.isNull(getAuth().isEnabled())) {
getAuth().setEnabled(isEnabled()); getAuth().setEnabled(isEnabled());
} }

View File

@@ -20,27 +20,12 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.backend.firebase.GoogleFirebaseAuthenticator;
import io.kamax.mxisd.backend.firebase.GoogleFirebaseProvider;
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
@ConfigurationProperties("firebase")
public class FirebaseConfig { public class FirebaseConfig {
private Logger log = LoggerFactory.getLogger(FirebaseConfig.class); private transient final Logger log = LoggerFactory.getLogger(FirebaseConfig.class);
@Autowired
private MatrixConfig mxCfg;
private boolean enabled; private boolean enabled;
private String credentials; private String credentials;
@@ -70,7 +55,6 @@ public class FirebaseConfig {
this.database = database; this.database = database;
} }
@PostConstruct
public void build() { public void build() {
log.info("--- Firebase configuration ---"); log.info("--- Firebase configuration ---");
log.info("Enabled: {}", isEnabled()); log.info("Enabled: {}", isEnabled());
@@ -80,14 +64,4 @@ public class FirebaseConfig {
} }
} }
@Bean
public AuthenticatorProvider getAuthProvider() {
return new GoogleFirebaseAuthenticator(enabled, credentials, database);
}
@Bean
public IThreePidProvider getLookupProvider() {
return new GoogleFirebaseProvider(enabled, credentials, database, mxCfg.getDomain());
}
} }

View File

@@ -20,14 +20,9 @@
package io.kamax.mxisd.config; package io.kamax.mxisd.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@Configuration
@ConfigurationProperties(prefix = "forward")
public class ForwardConfig { public class ForwardConfig {
private List<String> servers = new ArrayList<>(); private List<String> servers = new ArrayList<>();
@@ -40,4 +35,8 @@ public class ForwardConfig {
this.servers = servers; this.servers = servers;
} }
public void build() {
// no-op
}
} }

View File

@@ -23,21 +23,15 @@ package io.kamax.mxisd.config;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
@Configuration
@ConfigurationProperties("invite")
public class InvitationConfig { public class InvitationConfig {
private final Logger log = LoggerFactory.getLogger(InvitationConfig.class); private transient final Logger log = LoggerFactory.getLogger(InvitationConfig.class);
public static class Resolution { public static class Resolution {
private boolean recursive; private boolean recursive = true;
private long timer; private long timer = 1;
public boolean isRecursive() { public boolean isRecursive() {
return recursive; return recursive;
@@ -57,7 +51,7 @@ public class InvitationConfig {
} }
private Resolution resolution; private Resolution resolution = new Resolution();
public Resolution getResolution() { public Resolution getResolution() {
return resolution; return resolution;
@@ -67,7 +61,6 @@ public class InvitationConfig {
this.resolution = resolution; this.resolution = resolution;
} }
@PostConstruct
public void build() { public void build() {
log.info("--- Invite config ---"); log.info("--- Invite config ---");
log.info("Resolution: {}", GsonUtil.build().toJson(resolution)); log.info("Resolution: {}", GsonUtil.build().toJson(resolution));

Some files were not shown because too many files have changed in this diff Show More