Compare commits
9 Commits
v1.2.0-bet
...
v1.2.0
Author | SHA1 | Date | |
---|---|---|---|
|
99b7d9f27d | ||
|
ded5e3db5e | ||
|
b892d19023 | ||
|
026a2e82d9 | ||
|
b881f73798 | ||
|
99d793b5ed | ||
|
cb02f62b9d | ||
|
bd9161ec9b | ||
|
544cab816c |
21
build.gradle
21
build.gradle
@@ -41,17 +41,25 @@ def debBuildDataPath = "${debBuildBasePath}${debDataPath}"
|
||||
def debBuildSystemdPath = "${debBuildBasePath}${debSystemdPath}"
|
||||
|
||||
def dockerImageName = "kamax/mxisd"
|
||||
def dockerImageTag = "${dockerImageName}:${gitVersion()}"
|
||||
def dockerImageTag = "${dockerImageName}:${mxisdVersion()}"
|
||||
|
||||
String mxisdVersion() {
|
||||
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
|
||||
|
||||
String version = System.getenv('MXISD_BUILD_VERSION')
|
||||
if (version == null || version.size() == 0) {
|
||||
version = gitVersion()
|
||||
}
|
||||
return versionPattern.matcher(version).matches() ? version.substring(1) : version
|
||||
}
|
||||
|
||||
String gitVersion() {
|
||||
def versionPattern = Pattern.compile("v(\\d+\\.)?(\\d+\\.)?(\\d+)(-.*)?")
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream()
|
||||
exec {
|
||||
commandLine = ['git', 'describe', '--tags', '--always', '--dirty']
|
||||
standardOutput = out
|
||||
}
|
||||
def v = out.toString().replace(System.lineSeparator(), '')
|
||||
return versionPattern.matcher(v).matches() ? v.substring(1) : v
|
||||
return out.toString().replace(System.lineSeparator(), '');
|
||||
}
|
||||
|
||||
buildscript {
|
||||
@@ -126,6 +134,9 @@ dependencies {
|
||||
// SendGrid SDK to send emails from GCE
|
||||
compile 'com.sendgrid:sendgrid-java:2.2.2'
|
||||
|
||||
// ZT-Exec for exec identity store
|
||||
compile 'org.zeroturnaround:zt-exec:1.10'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'com.github.tomakehurst:wiremock:2.8.0'
|
||||
}
|
||||
@@ -151,7 +162,7 @@ processResources {
|
||||
|
||||
task buildDeb(dependsOn: build) {
|
||||
doLast {
|
||||
def v = gitVersion()
|
||||
def v = mxisdVersion()
|
||||
println "Version for package: ${v}"
|
||||
mkdir distDir
|
||||
mkdir debBuildBasePath
|
||||
|
@@ -19,8 +19,17 @@ matrix:
|
||||
localpart: 'appservice-mxisd'
|
||||
token:
|
||||
hs: 'HS_TOKEN_CHANGE_ME'
|
||||
|
||||
synapseSql:
|
||||
enabled: false ## Do not use this line if Synapse is used as an Identity Store
|
||||
type: '<DB TYPE>'
|
||||
connection: '<DB CONNECTION URL>'
|
||||
```
|
||||
|
||||
The `synapseSql` section is used to retrieve display names which are not directly accessible in this mode.
|
||||
For details about `type` and `connection`, see the [relevant documentation](../../stores/synapse.md).
|
||||
If you do not configure it, some placeholders will not be available in the notification, like the Room name.
|
||||
|
||||
You can also change the default template of the notification using the `generic.matrixId` template option.
|
||||
See [the Template generator documentation](../../threepids/notification/template-generator.md) for more info.
|
||||
|
||||
|
@@ -1,4 +1,7 @@
|
||||
# Debian package
|
||||
## Requirements
|
||||
- Any distribution that supports Java 8
|
||||
|
||||
## Install
|
||||
1. Download the [latest release](https://github.com/kamax-matrix/mxisd/releases/latest)
|
||||
2. Run:
|
||||
|
@@ -1,7 +1,8 @@
|
||||
# Identity Stores
|
||||
- [Synapse](synapse.md)
|
||||
- [LDAP-based](ldap.md)
|
||||
- [SQL Databases](sql.md)
|
||||
- [Website / Web service / Web app](rest.md)
|
||||
- [Google Firebase](firebase.md)
|
||||
- [Wordpress](wordpress.md)
|
||||
- [Synapse](synapse.md) - Turn your SynapseDB into a self-contained Identity store
|
||||
- [LDAP-based](ldap.md) - Any LDAP-based product like Active Directory, Samba, NetIQ, OpenLDAP
|
||||
- [SQL Databases](sql.md) - Most common databases like MariaDB, MySQL, PostgreSQL, SQLite
|
||||
- [Website / Web service / Web app](rest.md) - Arbitrary REST endpoints
|
||||
- [Executables](exec.md) - Run arbitrary executables with configurable stdin, arguments, environment and stdout
|
||||
- [Wordpress](wordpress.md) - Connect your Wordpress-powered website DB
|
||||
- [Google Firebase](firebase.md) - Use your Firebase users (with experimental SSO support!)
|
||||
|
470
docs/stores/exec.md
Normal file
470
docs/stores/exec.md
Normal file
@@ -0,0 +1,470 @@
|
||||
# Exec Identity Store
|
||||
- [Features](#features)
|
||||
- [Overview](#overview)
|
||||
- [Configuration](#configuration)
|
||||
- [Global](#global)
|
||||
- [Tokens](#tokens)
|
||||
- [Executable](#executable)
|
||||
- [Input](#input)
|
||||
- [Output](#output)
|
||||
- [Examples](#examples)
|
||||
- [Per-Feature](#per-feature)
|
||||
- [Authentication](#authentication)
|
||||
- [Tokens](#tokens-1)
|
||||
- [Input](#input-1)
|
||||
- [Output](#output-1)
|
||||
- [Directory](#directory)
|
||||
- [Tokens](#tokens-2)
|
||||
- [Input](#input-2)
|
||||
- [Output](#output-2)
|
||||
- [Identity](#identity)
|
||||
- [Single Lookup](#single-lookup)
|
||||
- [Tokens](#tokens-3)
|
||||
- [Input](#input-3)
|
||||
- [Output](#output-3)
|
||||
- [Bulk Lookup](#bulk-lookup)
|
||||
- [Tokens](#tokens-4)
|
||||
- [Input](#input-4)
|
||||
- [Output](#output-4)
|
||||
- [Profile](#profile)
|
||||
- [Tokens](#tokens-5)
|
||||
- [Input](#input-5)
|
||||
- [Output](#output-5)
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
| Name | Supported |
|
||||
|-------------------------------------------------|-----------|
|
||||
| [Authentication](../features/authentication.md) | Yes |
|
||||
| [Directory](../features/directory.md) | Yes |
|
||||
| [Identity](../features/identity.md) | Yes |
|
||||
| [Profile](#profile) | Yes |
|
||||
|
||||
This Identity Store lets you run arbitrary commands to handle the various requests in each support feature.
|
||||
It is the most versatile Identity store of mxisd, allowing you to connect any kind of logic with any executable/script.
|
||||
|
||||
## Overview
|
||||
Each request can be mapping to a fully customizable command configuration.
|
||||
The various parameters can be provided via any combination of:
|
||||
- [Standard Input](https://en.wikipedia.org/wiki/Standard_streams#Standard_input_(stdin))
|
||||
- [Command-line arguments](https://en.wikipedia.org/wiki/Command-line_interface#Arguments)
|
||||
- [Environment variables](https://en.wikipedia.org/wiki/Environment_variable)
|
||||
|
||||
Each of those supports a set of customizable token which will be replaced prior to running the command, allowing to
|
||||
provide the input values in any number of ways.
|
||||
|
||||
Success and data will be provided via any combination of:
|
||||
- [Exit status](https://en.wikipedia.org/wiki/Exit_status)
|
||||
- [Standard Output](https://en.wikipedia.org/wiki/Standard_streams#Standard_output_(stdout))
|
||||
|
||||
Each of those supports a set of configuration item to decide how to process the value and/or in which format.
|
||||
|
||||
All values, inputs and outputs are UTF-8 encoded.
|
||||
|
||||
## Configuration
|
||||
Each feature comes with a set of possible lookup/action which is mapped to a generic configuration item block.
|
||||
We will use the term `Executable` for each lookup/action and `Processor` for each configuration block.
|
||||
|
||||
### Global
|
||||
```yaml
|
||||
exec.enabled: <boolean>
|
||||
```
|
||||
Enable/disable the Identity store at a global/default level. Each feature can still be individually enabled/disabled.
|
||||
|
||||
#### Tokens
|
||||
The following options allow to globally set tokens for value replacement across all features and processors config.
|
||||
Not all features use all tokens, and each feature might also have its own specific tokens. See each feature documentation.
|
||||
|
||||
They can be set within the following scope:
|
||||
|
||||
```yaml
|
||||
exec.token.<token>: '<value>'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The following tokens and default values are available:
|
||||
```yaml
|
||||
localpart: '{localpart}'
|
||||
```
|
||||
Localpart of Matrix User IDs
|
||||
|
||||
```yaml
|
||||
domain: '{domain}'
|
||||
```
|
||||
Domain of Matrix User IDs
|
||||
|
||||
```yaml
|
||||
mxid: '{mxid}'
|
||||
```
|
||||
Full representation of Matrix User IDs
|
||||
|
||||
```yaml
|
||||
medium: '{medium}'
|
||||
```
|
||||
Medium of 3PIDs
|
||||
|
||||
```yaml
|
||||
address: '{address}'
|
||||
```
|
||||
Address of 3PIDs
|
||||
|
||||
```yaml
|
||||
type: '{type}'
|
||||
```
|
||||
Type of query
|
||||
|
||||
```yaml
|
||||
query: '{query}'
|
||||
```
|
||||
Query value
|
||||
|
||||
### Executable
|
||||
*Executable*s have the following options:
|
||||
```yaml
|
||||
command: '/path/to/executableOrScript'
|
||||
|
||||
```
|
||||
Set the executable (relative or absolute) path to be executed. If no command is given, the action will return a "neutral"
|
||||
result if possible or be skipped altogether.
|
||||
|
||||
---
|
||||
|
||||
Command line arguments can be given via a list via both YAML formats:
|
||||
```yaml
|
||||
args:
|
||||
- '-t'
|
||||
- '{token}'
|
||||
- '-v'
|
||||
- 'value'
|
||||
```
|
||||
or
|
||||
```yaml
|
||||
args: ['-t', '{token}', '-v', 'value]
|
||||
```
|
||||
Each argument will be processed for token replacement.
|
||||
|
||||
---
|
||||
|
||||
Environment variables can be given as key/value pairs:
|
||||
```yaml
|
||||
env:
|
||||
ENV_VAR_1: 'value'
|
||||
ENV_VAR_2: '{token}'
|
||||
```
|
||||
Each variable value will be processed for token replacement.
|
||||
|
||||
#### Input
|
||||
Standard input can be configured in the namespaces `input` with:
|
||||
- `type`: The format to use
|
||||
- `template`: The full or partial template with tokens to be used when generating the input
|
||||
|
||||
Not all features and *Executable*s allow for a template to be provided.
|
||||
Templates for listed-based input are not supported at this time.
|
||||
Default templates may be provided per *Executable*.
|
||||
|
||||
The following types are available:
|
||||
- `json`: Use JSON format, shared with the [REST Identity Store](rest.md)
|
||||
- `plain`: Use a custom multi-lines, optionally tab-separated input
|
||||
|
||||
#### Output
|
||||
Standard output can be configured in the namespaces `output` with:
|
||||
- `type`: The format to use
|
||||
- `template`: The full or partial template with tokens to be used when processing the output
|
||||
|
||||
Not all features and *Executable*s allow for a template to be provided.
|
||||
Templates for listed-based output are not supported at this time.
|
||||
Default templates may be provided per *Executable*.
|
||||
|
||||
The following types are available:
|
||||
- `json`: Use JSON format, shared with the [REST Identity Store](rest.md)
|
||||
- `plain`: Use a custom multi-lines, optionally tab-separated output
|
||||
|
||||
### Examples
|
||||
#### Basic
|
||||
```yaml
|
||||
exec.auth.enabled: true
|
||||
exec.auth.command: '/opt/mxisd-exec/auth.sh'
|
||||
exec.auth.args: ['{localpart}']
|
||||
exec.auth.input.type: 'plain'
|
||||
exec.auth.input.template: '{password}'
|
||||
exec.auth.env:
|
||||
DOMAIN: '{domain}'
|
||||
```
|
||||
With Authentication enabled, run `/opt/mxisd-exec/auth.sh` when validating credentials, providing:
|
||||
- A single command-line argument to provide the `localoart` as username
|
||||
- A plain text string with the password token for standard input, which will be replaced by the password to check
|
||||
- A single environment variable `DOMAIN` containing Matrix ID domain, if given
|
||||
|
||||
The command will use the default values for:
|
||||
- Success exit status of `0`
|
||||
- Failure exit status of `1`
|
||||
- Any other exit status considered as error
|
||||
- The standard output processing as not processed
|
||||
|
||||
#### Advanced
|
||||
Given the fictional `placeholder` feature:
|
||||
```yaml
|
||||
exec.enabled: true
|
||||
exec.token.mxid: '{matrixId}'
|
||||
|
||||
exec.placeholder.token.localpart: '{username}'
|
||||
exec.placeholder.command: '/path/to/executable'
|
||||
exec.placeholder.args:
|
||||
- '-u'
|
||||
- '{username}'
|
||||
exec.placeholder.env:
|
||||
MATRIX_DOMAIN: '{domain}'
|
||||
MATRIX_USER_ID: '{matrixId}'
|
||||
|
||||
exec.placeholder.output.type: 'json'
|
||||
exec.placeholder.exit.success: [0, 128]
|
||||
exec.placeholder.exit.failure: [1, 129]
|
||||
```
|
||||
With:
|
||||
- The Identity store enabled for all features
|
||||
- A global specific token `{matrixId}` for Matrix User IDs, replacing the default `{mxid}`
|
||||
|
||||
Running `/path/to/executable` providing:
|
||||
- A custom token for localpart, `{username}`, used as a 2nd command-line argument
|
||||
- An extracted Matrix User ID `localpart` provided as the second command line argument, the first one being `-u`
|
||||
- A password, the extracted Matrix `domain` and the full User ID as arbitrary environment variables, respectively
|
||||
`PASSWORD`, `MATRIX_DOMAIN` and `MATRIX_USER_ID`
|
||||
|
||||
After execution:
|
||||
- Process stdout as [JSON](https://en.wikipedia.org/wiki/JSON)
|
||||
- Consider exit status `0` and `128` as success and try to process the stdout for data
|
||||
- Consider exit status `1` and `129` as failure and try to process the stdout for error code and message
|
||||
|
||||
### Per Feature
|
||||
See each dedicated [Feature](#features) section.
|
||||
|
||||
## Authentication
|
||||
The Authentication feature can be enabled/disabled using:
|
||||
```yaml
|
||||
exec.auth.enabled: <true/false>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
This feature provides a single *Executable* under the namespace:
|
||||
```yaml
|
||||
exec.auth:
|
||||
...
|
||||
```
|
||||
|
||||
### Tokens
|
||||
The following tokens/default values are specific to this feature:
|
||||
```yaml
|
||||
password: '{password}'
|
||||
```
|
||||
The provided password
|
||||
|
||||
### Input
|
||||
Supported input types and default templates:
|
||||
|
||||
#### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
#### Plain (`plain`)
|
||||
Default template:
|
||||
```
|
||||
{localpart}
|
||||
{domain}
|
||||
{mxid}
|
||||
{password}
|
||||
```
|
||||
|
||||
### Output
|
||||
Supported output types and default templates:
|
||||
|
||||
#### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
#### Plain (`plain`)
|
||||
**NOTE:** This has limited support. Use the JSON type for full support.
|
||||
|
||||
Default template:
|
||||
```
|
||||
[success status, true or 1 are interpreted as success]
|
||||
[display name of the user]
|
||||
```
|
||||
|
||||
## Directory
|
||||
The Directory feature can be enabled/disabled using:
|
||||
```yaml
|
||||
exec.directory.enabled: <true/false>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Two search types configuration namespace are available, using the same input/output formats and templates:
|
||||
|
||||
By name:
|
||||
```yaml
|
||||
exec.directory.search.byName:
|
||||
...
|
||||
```
|
||||
By 3PID:
|
||||
```yaml
|
||||
exec.directory.search.byThreepid:
|
||||
...
|
||||
```
|
||||
|
||||
#### Tokens
|
||||
No specific tokens are available.
|
||||
|
||||
#### Input
|
||||
Supported input types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
##### Plain (`plain`)
|
||||
Default template:
|
||||
```
|
||||
[type of search, following the REST Identity store format]
|
||||
[query string]
|
||||
```
|
||||
|
||||
#### Output
|
||||
Supported output types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
##### Plain (`plain`)
|
||||
**Not supported at this time.** Use the JSON type.
|
||||
|
||||
## Identity
|
||||
The Identity feature can be enabled/disabled using:
|
||||
```yaml
|
||||
exec.identity.enabled: <true/false>
|
||||
```
|
||||
|
||||
### Single lookup
|
||||
Configuration namespace:
|
||||
```yaml
|
||||
exec.identity.lookup.single:
|
||||
...
|
||||
```
|
||||
|
||||
#### Tokens
|
||||
No specific tokens are available.
|
||||
|
||||
#### Input
|
||||
Supported input types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
##### Plain (`plain`)
|
||||
Default template:
|
||||
```
|
||||
{medium}
|
||||
{address}
|
||||
```
|
||||
|
||||
#### Output
|
||||
Supported output types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
##### Plain (`plain`)
|
||||
Default template:
|
||||
```
|
||||
[User ID type, as documented in the REST Identity Store]
|
||||
[User ID value]
|
||||
```
|
||||
|
||||
The User ID type will default to `localpart` if:
|
||||
- Only one line is returned
|
||||
- The first line is empty
|
||||
|
||||
### Bulk lookup
|
||||
Configuration namespace:
|
||||
```yaml
|
||||
exec.identity.lookup.bulk:
|
||||
...
|
||||
```
|
||||
|
||||
#### Tokens
|
||||
No specific tokens are available.
|
||||
|
||||
#### Input
|
||||
Supported input types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
**NOTE:** Custom Templates are not supported.
|
||||
|
||||
Same as the [REST Identity Store](rest.md).
|
||||
|
||||
##### Plain (`plain`)
|
||||
**Not supported at this time.** Use the JSON type.
|
||||
|
||||
#### Output
|
||||
Supported output types and default templates:
|
||||
|
||||
##### JSON (`json`)
|
||||
**NOTE:** Custom Templates are not supported.
|
||||
|
||||
Same as the [REST Identity Store](rest.md).
|
||||
|
||||
##### Plain (`plain`)
|
||||
**Not supported at this time.** Use the JSON type.
|
||||
|
||||
## Profile
|
||||
The Profile feature can be enabled/disabled using:
|
||||
```yaml
|
||||
exec.profile.enabled: <true/false>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
The following *Executable*s namespace are available, share the same input/output formats and templates:
|
||||
|
||||
Get Display name:
|
||||
```yaml
|
||||
exec.profile.displayName:
|
||||
...
|
||||
```
|
||||
|
||||
Get 3PIDs:
|
||||
```yaml
|
||||
exec.profile.threePid:
|
||||
...
|
||||
```
|
||||
|
||||
Get Roles:
|
||||
```yaml
|
||||
exec.profile.role:
|
||||
...
|
||||
```
|
||||
|
||||
|
||||
### Tokens
|
||||
No specific tokens are available.
|
||||
|
||||
### Input
|
||||
Supported input types and default templates:
|
||||
|
||||
#### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
#### Plain (`plain`)
|
||||
Default template:
|
||||
```
|
||||
{localpart}
|
||||
{domain}
|
||||
{mxid}
|
||||
```
|
||||
### Output
|
||||
Supported output types and default templates:
|
||||
|
||||
#### JSON (`json`)
|
||||
Same as the [REST Identity Store](rest.md);
|
||||
|
||||
#### Plain (`plain`)
|
||||
**Not supported at this time.** Use the JSON type.
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2017 Maxime Dor
|
||||
* Copyright (C) 2017 Kamax Sarl
|
||||
*
|
||||
* https://max.kamax.io/
|
||||
* 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
|
||||
@@ -30,6 +30,10 @@ public class UserID {
|
||||
// stub for (de)serialization
|
||||
}
|
||||
|
||||
public UserID(UserIdType type, String value) {
|
||||
this(type.getId(), value);
|
||||
}
|
||||
|
||||
public UserID(String type, String value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
|
@@ -79,7 +79,12 @@ public class AppServiceHandler {
|
||||
log.info("Got invite for {}", id);
|
||||
|
||||
boolean wasSent = false;
|
||||
for (_ThreePid tpid : profiler.getThreepids(mxid)) {
|
||||
List<_ThreePid> tpids = profiler.getThreepids(mxid);
|
||||
if (tpids.isEmpty()) {
|
||||
log.info("No email found in identity stores for {}", id);
|
||||
}
|
||||
|
||||
for (_ThreePid tpid : tpids) {
|
||||
if (!StringUtils.equals("email", tpid.getMedium())) {
|
||||
continue;
|
||||
}
|
||||
@@ -87,7 +92,12 @@ public class AppServiceHandler {
|
||||
log.info("Found an email address to notify about room invitation: {}", tpid.getAddress());
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
profiler.getDisplayName(sender).ifPresent(name -> properties.put("sender_display_name", name));
|
||||
synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name));
|
||||
try {
|
||||
synapse.getRoomName(roomId).ifPresent(name -> properties.put("room_name", name));
|
||||
} catch (RuntimeException e) {
|
||||
log.warn("Unable to fetch room name - Did you provide synapse DB information as documented?");
|
||||
log.warn("Underlying error:", e);
|
||||
}
|
||||
|
||||
IMatrixIdInvite inv = new MatrixIdInvite(roomId, sender, mxid, tpid.getMedium(), tpid.getAddress(), properties);
|
||||
notif.sendForInvite(inv);
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2017 Maxime Dor
|
||||
* Copyright (C) 2017 Kamax Sarl
|
||||
*
|
||||
* https://max.kamax.io/
|
||||
* 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
|
||||
@@ -59,9 +59,10 @@ public class AuthManager {
|
||||
continue;
|
||||
}
|
||||
|
||||
log.info("Attempting authentication with store {}", provider.getClass().getSimpleName());
|
||||
|
||||
BackendAuthResult result = provider.authenticate(mxid, password);
|
||||
if (result.isSuccess()) {
|
||||
|
||||
String mxId;
|
||||
if (UserIdType.Localpart.is(result.getId().getType())) {
|
||||
mxId = MatrixID.from(result.getId().getValue(), mxCfg.getDomain()).acceptable().getId();
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* mxisd - Matrix Identity Server Daemon
|
||||
* Copyright (C) 2017 Maxime Dor
|
||||
* Copyright (C) 2017 Kamax Sarl
|
||||
*
|
||||
* https://max.kamax.io/
|
||||
* 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
|
||||
@@ -38,6 +38,10 @@ public class BackendAuthResult {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public Set<ThreePid> getThreePids() {
|
||||
return threePids;
|
||||
}
|
||||
@@ -73,6 +77,10 @@ public class BackendAuthResult {
|
||||
private UserID id;
|
||||
private BackendAuthProfile profile = new BackendAuthProfile();
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public Boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
@@ -81,6 +89,10 @@ public class BackendAuthResult {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UserID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public BackendAuthProfile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.auth.provider.BackendAuthResult;
|
||||
|
||||
public class ExecAuthResult extends BackendAuthResult {
|
||||
|
||||
private int exitStatus;
|
||||
|
||||
public int getExitStatus() {
|
||||
return exitStatus;
|
||||
}
|
||||
|
||||
public void setExitStatus(int exitStatus) {
|
||||
this.exitStatus = exitStatus;
|
||||
}
|
||||
|
||||
}
|
129
src/main/java/io/kamax/mxisd/backend/exec/ExecAuthStore.java
Normal file
129
src/main/java/io/kamax/mxisd/backend/exec/ExecAuthStore.java
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.UserID;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
|
||||
import io.kamax.mxisd.backend.rest.RestAuthRequestJson;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
|
||||
|
||||
private ExecConfig.Auth cfg;
|
||||
|
||||
@Autowired
|
||||
public ExecAuthStore(ExecConfig cfg) {
|
||||
this.cfg = Objects.requireNonNull(cfg.getAuth());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExecAuthResult authenticate(_MatrixID uId, String password) {
|
||||
Objects.requireNonNull(uId);
|
||||
Objects.requireNonNull(password);
|
||||
|
||||
log.info("Performing authentication for {}", uId.getId());
|
||||
|
||||
ExecAuthResult result = new ExecAuthResult();
|
||||
result.setId(new UserID(UserIdType.Localpart, uId.getLocalPart()));
|
||||
|
||||
Processor<ExecAuthResult> p = new Processor<>(cfg);
|
||||
|
||||
p.addTokenMapper(cfg.getToken().getLocalpart(), uId::getLocalPart);
|
||||
p.addTokenMapper(cfg.getToken().getDomain(), uId::getDomain);
|
||||
p.addTokenMapper(cfg.getToken().getMxid(), uId::getId);
|
||||
p.addTokenMapper(cfg.getToken().getPassword(), () -> password);
|
||||
|
||||
p.addJsonInputTemplate(tokens -> {
|
||||
RestAuthRequestJson json = new RestAuthRequestJson();
|
||||
json.setLocalpart(tokens.getLocalpart());
|
||||
json.setDomain(tokens.getDomain());
|
||||
json.setMxid(tokens.getMxid());
|
||||
json.setPassword(tokens.getPassword());
|
||||
return json;
|
||||
});
|
||||
p.addInputTemplate(PlainType, tokens -> tokens.getLocalpart() + System.lineSeparator() +
|
||||
tokens.getDomain() + System.lineSeparator() +
|
||||
tokens.getMxid() + System.lineSeparator() +
|
||||
tokens.getPassword() + System.lineSeparator()
|
||||
);
|
||||
|
||||
p.withExitHandler(pr -> result.setExitStatus(pr.getExitValue()));
|
||||
|
||||
p.withSuccessHandler(pr -> result.setSuccess(true));
|
||||
p.withSuccessDefault(o -> result);
|
||||
p.addSuccessMapper(JsonType, output -> {
|
||||
JsonObject data = GsonUtil.getObj(GsonUtil.parseObj(output), "auth");
|
||||
GsonUtil.findPrimitive(data, "success")
|
||||
.map(JsonPrimitive::getAsBoolean)
|
||||
.ifPresent(result::setSuccess);
|
||||
GsonUtil.findObj(data, "profile")
|
||||
.flatMap(profile -> GsonUtil.findString(profile, "display_name"))
|
||||
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
||||
|
||||
return result;
|
||||
});
|
||||
p.addSuccessMapper(PlainType, output -> {
|
||||
String[] lines = output.split("\\R");
|
||||
if (lines.length > 2) {
|
||||
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
||||
}
|
||||
|
||||
result.setSuccess(Optional.ofNullable(StringUtils.isEmpty(lines[0]) ? null : lines[0])
|
||||
.map(v -> StringUtils.equalsAnyIgnoreCase(v, "true", "1"))
|
||||
.orElse(result.isSuccess()));
|
||||
|
||||
if (lines.length == 2) {
|
||||
Optional.ofNullable(StringUtils.isEmpty(lines[1]) ? null : lines[1])
|
||||
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
p.withFailureHandler(pr -> result.setSuccess(false));
|
||||
p.withFailureDefault(o -> result);
|
||||
|
||||
return p.execute();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.matrix.MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||
import io.kamax.mxisd.directory.IDirectoryProvider;
|
||||
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 IDirectoryProvider {
|
||||
|
||||
private ExecConfig.Directory cfg;
|
||||
private MatrixConfig mxCfg;
|
||||
|
||||
@Autowired
|
||||
public ExecDirectoryStore(ExecConfig cfg, MatrixConfig mxCfg) {
|
||||
this(cfg.getDirectory(), mxCfg);
|
||||
}
|
||||
|
||||
public ExecDirectoryStore(ExecConfig.Directory cfg, MatrixConfig mxCfg) {
|
||||
this.cfg = cfg;
|
||||
this.mxCfg = mxCfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled();
|
||||
}
|
||||
|
||||
private UserDirectorySearchResult search(ExecConfig.Process cfg, UserDirectorySearchRequest request) {
|
||||
if (StringUtils.isEmpty(cfg.getCommand())) {
|
||||
return UserDirectorySearchResult.empty();
|
||||
}
|
||||
|
||||
Processor<UserDirectorySearchResult> p = new Processor<>(cfg);
|
||||
|
||||
p.addJsonInputTemplate(tokens -> new UserDirectorySearchRequest(tokens.getType(), tokens.getQuery()));
|
||||
p.addInputTemplate(PlainType, tokens -> tokens.getType() + System.lineSeparator() + tokens.getQuery());
|
||||
|
||||
p.addTokenMapper(cfg.getToken().getType(), request::getBy);
|
||||
p.addTokenMapper(cfg.getToken().getQuery(), request::getSearchTerm);
|
||||
|
||||
p.addSuccessMapper(JsonType, output -> {
|
||||
if (StringUtils.isBlank(output)) {
|
||||
return UserDirectorySearchResult.empty();
|
||||
}
|
||||
|
||||
UserDirectorySearchResult response = GsonUtil.get().fromJson(output, UserDirectorySearchResult.class);
|
||||
for (UserDirectorySearchResult.Result result : response.getResults()) {
|
||||
result.setUserId(MatrixID.asAcceptable(result.getUserId(), mxCfg.getDomain()).getId());
|
||||
}
|
||||
return response;
|
||||
});
|
||||
p.withFailureDefault(output -> new UserDirectorySearchResult());
|
||||
|
||||
return p.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchByDisplayName(String query) {
|
||||
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("name", query));
|
||||
}
|
||||
|
||||
@Override
|
||||
public UserDirectorySearchResult searchBy3pid(String query) {
|
||||
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("threepid", query));
|
||||
}
|
||||
|
||||
}
|
209
src/main/java/io/kamax/mxisd/backend/exec/ExecIdentityStore.java
Normal file
209
src/main/java/io/kamax/mxisd/backend/exec/ExecIdentityStore.java
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonParseException;
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.matrix.ThreePid;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.UserID;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
import io.kamax.mxisd.backend.rest.LookupBulkResponseJson;
|
||||
import io.kamax.mxisd.backend.rest.LookupSingleResponseJson;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
||||
import io.kamax.mxisd.lookup.ThreePidMapping;
|
||||
import io.kamax.mxisd.lookup.provider.IThreePidProvider;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ExecIdentityStore.class);
|
||||
|
||||
private final ExecConfig.Identity cfg;
|
||||
private final MatrixConfig mxCfg;
|
||||
|
||||
@Autowired
|
||||
public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) {
|
||||
this(cfg.getIdentity(), mxCfg);
|
||||
}
|
||||
|
||||
public ExecIdentityStore(ExecConfig.Identity cfg, MatrixConfig mxCfg) {
|
||||
this.cfg = cfg;
|
||||
this.mxCfg = mxCfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLocal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPriority() {
|
||||
return cfg.getPriority();
|
||||
}
|
||||
|
||||
private ExecConfig.Process getSingleCfg() {
|
||||
return cfg.getLookup().getSingle();
|
||||
}
|
||||
|
||||
private _MatrixID getUserId(UserID id) {
|
||||
if (Objects.isNull(id)) {
|
||||
throw new JsonParseException("User id key is not present");
|
||||
}
|
||||
|
||||
if (UserIdType.Localpart.is(id.getType())) {
|
||||
return MatrixID.asAcceptable(id.getValue(), mxCfg.getDomain());
|
||||
}
|
||||
|
||||
if (UserIdType.MatrixID.is(id.getType())) {
|
||||
return MatrixID.asAcceptable(id.getValue());
|
||||
}
|
||||
|
||||
throw new InternalServerError("Unknown user type: " + id.getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
||||
Processor<Optional<SingleLookupReply>> p = new Processor<>();
|
||||
p.withConfig(cfg.getLookup().getSingle());
|
||||
|
||||
p.addTokenMapper(getSingleCfg().getToken().getMedium(), request::getType);
|
||||
p.addTokenMapper(getSingleCfg().getToken().getAddress(), request::getThreePid);
|
||||
|
||||
p.addJsonInputTemplate(tokens -> new ThreePid(tokens.getMedium(), tokens.getAddress()));
|
||||
p.addInputTemplate(PlainType, tokens -> tokens.getMedium()
|
||||
+ System.lineSeparator()
|
||||
+ tokens.getAddress()
|
||||
);
|
||||
|
||||
p.addSuccessMapper(JsonType, output -> {
|
||||
if (StringUtils.isBlank(output)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return GsonUtil.findObj(GsonUtil.parseObj(output), "lookup")
|
||||
.filter(obj -> !obj.entrySet().isEmpty())
|
||||
.map(json -> GsonUtil.get().fromJson(json, LookupSingleResponseJson.class))
|
||||
.map(lookup -> getUserId(lookup.getId()))
|
||||
.map(mxId -> new SingleLookupReply(request, mxId));
|
||||
});
|
||||
|
||||
p.addSuccessMapper(PlainType, output -> {
|
||||
String[] lines = output.split("\\R");
|
||||
if (lines.length > 2) {
|
||||
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
||||
}
|
||||
|
||||
if (lines.length == 1 && StringUtils.isBlank(lines[0])) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
String type = StringUtils.trimToEmpty(lines.length == 1 ? UserIdType.Localpart.getId() : lines[0]);
|
||||
String value = StringUtils.trimToEmpty(lines.length == 2 ? lines[1] : lines[0]);
|
||||
|
||||
if (UserIdType.Localpart.is(type)) {
|
||||
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value, mxCfg.getDomain())));
|
||||
}
|
||||
|
||||
if (UserIdType.MatrixID.is(type)) {
|
||||
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value)));
|
||||
}
|
||||
|
||||
throw new InternalServerError("Invalid user type: " + type);
|
||||
});
|
||||
|
||||
p.withFailureDefault(o -> Optional.empty());
|
||||
|
||||
return p.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) {
|
||||
Processor<List<ThreePidMapping>> p = new Processor<>();
|
||||
p.withConfig(cfg.getLookup().getBulk());
|
||||
|
||||
p.addInput(JsonType, () -> {
|
||||
JsonArray tpids = GsonUtil.asArray(mappings.stream()
|
||||
.map(mapping -> GsonUtil.get().toJsonTree(new ThreePid(mapping.getMedium(), mapping.getValue())))
|
||||
.collect(Collectors.toList()));
|
||||
return GsonUtil.get().toJson(GsonUtil.makeObj("lookup", tpids));
|
||||
});
|
||||
p.addInput(PlainType, () -> {
|
||||
StringBuilder input = new StringBuilder();
|
||||
for (ThreePidMapping mapping : mappings) {
|
||||
input.append(mapping.getMedium()).append("\t").append(mapping.getValue()).append(System.lineSeparator());
|
||||
}
|
||||
return input.toString();
|
||||
});
|
||||
|
||||
p.addSuccessMapper(JsonType, output -> {
|
||||
if (StringUtils.isBlank(output)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
LookupBulkResponseJson response = GsonUtil.get().fromJson(output, LookupBulkResponseJson.class);
|
||||
return response.getLookup().stream().map(item -> {
|
||||
ThreePidMapping mapping = new ThreePidMapping();
|
||||
mapping.setMedium(item.getMedium());
|
||||
mapping.setValue(item.getAddress());
|
||||
|
||||
if (UserIdType.Localpart.is(item.getId().getType())) {
|
||||
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue(), mxCfg.getDomain()).getId());
|
||||
return mapping;
|
||||
}
|
||||
|
||||
if (UserIdType.MatrixID.is(item.getId().getType())) {
|
||||
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue()).getId());
|
||||
return mapping;
|
||||
}
|
||||
|
||||
throw new InternalServerError("Invalid user type: " + item.getId().getType());
|
||||
}).collect(Collectors.toList());
|
||||
});
|
||||
|
||||
p.withFailureDefault(output -> Collections.emptyList());
|
||||
|
||||
return p.execute();
|
||||
}
|
||||
|
||||
}
|
103
src/main/java/io/kamax/mxisd/backend/exec/ExecProfileStore.java
Normal file
103
src/main/java/io/kamax/mxisd/backend/exec/ExecProfileStore.java
Normal 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.backend.exec;
|
||||
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.matrix._ThreePid;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.profile.JsonProfileRequest;
|
||||
import io.kamax.mxisd.profile.JsonProfileResult;
|
||||
import io.kamax.mxisd.profile.ProfileProvider;
|
||||
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.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ExecProfileStore extends ExecStore implements ProfileProvider {
|
||||
|
||||
private ExecConfig.Profile cfg;
|
||||
|
||||
@Autowired
|
||||
public ExecProfileStore(ExecConfig cfg) {
|
||||
this(cfg.getProfile());
|
||||
}
|
||||
|
||||
public ExecProfileStore(ExecConfig.Profile cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return cfg.isEnabled();
|
||||
}
|
||||
|
||||
private Optional<JsonProfileResult> getFull(_MatrixID userId, ExecConfig.Process cfg) {
|
||||
Processor<Optional<JsonProfileResult>> p = new Processor<>(cfg);
|
||||
|
||||
p.addJsonInputTemplate(tokens -> new JsonProfileRequest(tokens.getLocalpart(), tokens.getDomain(), tokens.getMxid()));
|
||||
p.addInputTemplate(PlainType, tokens -> tokens.getLocalpart() + System.lineSeparator()
|
||||
+ tokens.getDomain() + System.lineSeparator()
|
||||
+ tokens.getMxid() + System.lineSeparator()
|
||||
);
|
||||
|
||||
p.addTokenMapper(cfg.getToken().getLocalpart(), userId::getLocalPart);
|
||||
p.addTokenMapper(cfg.getToken().getDomain(), userId::getDomain);
|
||||
p.addTokenMapper(cfg.getToken().getMxid(), userId::getId);
|
||||
|
||||
p.withFailureDefault(v -> Optional.empty());
|
||||
|
||||
p.addSuccessMapper(JsonType, output -> {
|
||||
if (StringUtils.isBlank(output)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
return GsonUtil.findObj(GsonUtil.parseObj(output), "profile")
|
||||
.map(obj -> GsonUtil.get().fromJson(obj, JsonProfileResult.class));
|
||||
});
|
||||
|
||||
return p.execute();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<String> getDisplayName(_MatrixID userId) {
|
||||
return getFull(userId, cfg.getDisplayName()).map(JsonProfileResult::getDisplayName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<_ThreePid> getThreepids(_MatrixID userId) {
|
||||
return getFull(userId, cfg.getThreePid())
|
||||
.map(p -> Collections.<_ThreePid>unmodifiableList(p.getThreepids()))
|
||||
.orElseGet(Collections::emptyList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getRoles(_MatrixID userId) {
|
||||
return getFull(userId, cfg.getRole())
|
||||
.map(JsonProfileResult::getRoles)
|
||||
.orElseGet(Collections::emptyList);
|
||||
}
|
||||
|
||||
}
|
252
src/main/java/io/kamax/mxisd/backend/exec/ExecStore.java
Normal file
252
src/main/java/io/kamax/mxisd/backend/exec/ExecStore.java
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.zeroturnaround.exec.ProcessExecutor;
|
||||
import org.zeroturnaround.exec.ProcessResult;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class ExecStore {
|
||||
|
||||
public static final String JsonType = "json";
|
||||
public static final String PlainType = "plain";
|
||||
|
||||
protected static String toJson(Object o) {
|
||||
return GsonUtil.get().toJson(o);
|
||||
}
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(ExecStore.class);
|
||||
|
||||
private Supplier<ProcessExecutor> executorSupplier = () -> new ProcessExecutor().readOutput(true);
|
||||
|
||||
public void setExecutorSupplier(Supplier<ProcessExecutor> supplier) {
|
||||
executorSupplier = supplier;
|
||||
}
|
||||
|
||||
public class Processor<V> {
|
||||
|
||||
private ExecConfig.Process cfg;
|
||||
|
||||
private Supplier<Optional<String>> inputSupplier;
|
||||
private Function<String, String> inputTypeMapper;
|
||||
private Function<String, String> inputUnknownTypeMapper;
|
||||
private Map<String, Supplier<String>> inputTypeSuppliers;
|
||||
|
||||
private Map<String, Function<ExecConfig.TokenOverride, String>> inputTypeTemplates;
|
||||
private Supplier<String> inputTypeNoTemplateHandler;
|
||||
private Map<String, Supplier<String>> tokenMappers;
|
||||
private Function<String, String> tokenHandler;
|
||||
|
||||
private Consumer<ProcessResult> onExitHandler;
|
||||
private Consumer<ProcessResult> successHandler;
|
||||
private Map<String, Function<String, V>> successMappers;
|
||||
private Function<String, V> successDefault;
|
||||
private Consumer<ProcessResult> failureHandler;
|
||||
private Map<String, Function<String, V>> failureMappers;
|
||||
private Function<String, V> failureDefault;
|
||||
private Consumer<ProcessResult> unknownHandler;
|
||||
private Map<String, Function<String, V>> unknownMappers;
|
||||
private Function<String, V> unknownDefault;
|
||||
|
||||
public Processor(ExecConfig.Process cfg) {
|
||||
this();
|
||||
withConfig(cfg);
|
||||
}
|
||||
|
||||
public Processor() {
|
||||
tokenMappers = new HashMap<>();
|
||||
inputTypeSuppliers = new HashMap<>();
|
||||
inputTypeTemplates = new HashMap<>();
|
||||
|
||||
withTokenHandler(tokenHandler = input -> {
|
||||
for (Map.Entry<String, Supplier<String>> entry : tokenMappers.entrySet()) {
|
||||
input = input.replace(entry.getKey(), entry.getValue().get());
|
||||
}
|
||||
return input;
|
||||
});
|
||||
|
||||
inputTypeNoTemplateHandler = () -> cfg.getInput().getType()
|
||||
.map(type -> inputTypeTemplates.get(type).apply(cfg.getToken()))
|
||||
.orElse("");
|
||||
|
||||
inputUnknownTypeMapper = type -> tokenHandler.apply(cfg.getInput().getTemplate().orElseGet(inputTypeNoTemplateHandler));
|
||||
|
||||
inputTypeMapper = type -> {
|
||||
if (!inputTypeSuppliers.containsKey(type)) {
|
||||
return inputUnknownTypeMapper.apply(type);
|
||||
}
|
||||
|
||||
return inputTypeSuppliers.get(type).get();
|
||||
};
|
||||
|
||||
inputSupplier = () -> cfg.getInput().getType().map(type -> inputTypeMapper.apply(type));
|
||||
|
||||
withExitHandler(pr -> {
|
||||
});
|
||||
|
||||
successHandler = pr -> {
|
||||
};
|
||||
successMappers = new HashMap<>();
|
||||
successDefault = output -> {
|
||||
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||
throw new InternalServerError("Exec command has no success handler configured. This is a bug. Please report.");
|
||||
};
|
||||
|
||||
failureHandler = pr -> {
|
||||
};
|
||||
failureMappers = new HashMap<>();
|
||||
failureDefault = output -> {
|
||||
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||
throw new InternalServerError("Exec command has no failure handler configured. This is a bug. Please report.");
|
||||
};
|
||||
|
||||
unknownHandler = pr -> log.warn("Unexpected exit status: {}", pr.getExitValue());
|
||||
unknownMappers = new HashMap<>();
|
||||
withUnknownDefault(output -> {
|
||||
log.error("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||
throw new InternalServerError("Exec command returned with unexpected exit status");
|
||||
});
|
||||
}
|
||||
|
||||
public void withConfig(ExecConfig.Process cfg) {
|
||||
this.cfg = cfg;
|
||||
}
|
||||
|
||||
public void addTokenMapper(String token, Supplier<String> data) {
|
||||
tokenMappers.put(token, data);
|
||||
}
|
||||
|
||||
public void withTokenHandler(Function<String, String> handler) {
|
||||
tokenHandler = handler;
|
||||
}
|
||||
|
||||
public void addInput(String type, Supplier<String> handler) {
|
||||
inputTypeSuppliers.put(type, handler);
|
||||
}
|
||||
|
||||
protected void addInputTemplate(String type, Function<ExecConfig.TokenOverride, String> template) {
|
||||
inputTypeTemplates.put(type, template);
|
||||
}
|
||||
|
||||
public void addJsonInputTemplate(Function<ExecConfig.TokenOverride, Object> template) {
|
||||
inputTypeTemplates.put(JsonType, token -> GsonUtil.get().toJson(template.apply(token)));
|
||||
}
|
||||
|
||||
public void withExitHandler(Consumer<ProcessResult> handler) {
|
||||
onExitHandler = handler;
|
||||
}
|
||||
|
||||
public void withSuccessHandler(Consumer<ProcessResult> handler) {
|
||||
successHandler = handler;
|
||||
}
|
||||
|
||||
public void addSuccessMapper(String type, Function<String, V> mapper) {
|
||||
successMappers.put(type, mapper);
|
||||
}
|
||||
|
||||
public void withSuccessDefault(Function<String, V> mapper) {
|
||||
successDefault = mapper;
|
||||
}
|
||||
|
||||
public void withFailureHandler(Consumer<ProcessResult> handler) {
|
||||
failureHandler = handler;
|
||||
}
|
||||
|
||||
public void addFailureMapper(String type, Function<String, V> mapper) {
|
||||
failureMappers.put(type, mapper);
|
||||
}
|
||||
|
||||
public void withFailureDefault(Function<String, V> mapper) {
|
||||
failureDefault = mapper;
|
||||
}
|
||||
|
||||
public void addUnknownMapper(String type, Function<String, V> mapper) {
|
||||
unknownMappers.put(type, mapper);
|
||||
}
|
||||
|
||||
public void withUnknownDefault(Function<String, V> mapper) {
|
||||
unknownDefault = mapper;
|
||||
}
|
||||
|
||||
public V execute() {
|
||||
log.info("Executing {}", cfg.getCommand());
|
||||
|
||||
try {
|
||||
ProcessExecutor psExec = executorSupplier.get();
|
||||
|
||||
List<String> args = new ArrayList<>();
|
||||
args.add(tokenHandler.apply(cfg.getCommand()));
|
||||
args.addAll(cfg.getArgs().stream().map(arg -> tokenHandler.apply(arg)).collect(Collectors.toList()));
|
||||
psExec.command(args);
|
||||
|
||||
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream()
|
||||
.peek(e -> e.setValue(tokenHandler.apply(e.getValue())))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
|
||||
inputSupplier.get().ifPresent(input -> psExec.redirectInput(IOUtils.toInputStream(input, StandardCharsets.UTF_8)));
|
||||
|
||||
ProcessResult psResult = psExec.execute();
|
||||
String output = psResult.outputUTF8();
|
||||
onExitHandler.accept(psResult);
|
||||
|
||||
if (cfg.getExit().getSuccess().contains(psResult.getExitValue())) {
|
||||
successHandler.accept(psResult);
|
||||
|
||||
return cfg.getOutput().getType()
|
||||
.map(type -> successMappers.getOrDefault(type, successDefault).apply(output))
|
||||
.orElseGet(() -> successDefault.apply(output));
|
||||
} else if (cfg.getExit().getFailure().contains(psResult.getExitValue())) {
|
||||
failureHandler.accept(psResult);
|
||||
|
||||
return cfg.getOutput().getType()
|
||||
.map(type -> failureMappers.getOrDefault(type, failureDefault).apply(output))
|
||||
.orElseGet(() -> failureDefault.apply(output));
|
||||
} else {
|
||||
unknownHandler.accept(psResult);
|
||||
|
||||
return cfg.getOutput().getType()
|
||||
.map(type -> unknownMappers.getOrDefault(type, unknownDefault).apply(output))
|
||||
.orElseGet(() -> unknownDefault.apply(output));
|
||||
}
|
||||
} catch (RuntimeException | IOException | InterruptedException | TimeoutException e) {
|
||||
log.error("Failed to execute {}", cfg.getCommand());
|
||||
log.debug("Internal exception:", e);
|
||||
throw new InternalServerError(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@@ -62,10 +62,13 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
|
||||
|
||||
@Override
|
||||
public Optional<String> getDisplayName(_MatrixID userId) {
|
||||
String uid = buildUidFromMatrixId(userId);
|
||||
log.info("Searching for display name of {}:", uid);
|
||||
|
||||
try (LdapConnection conn = getConn()) {
|
||||
bind(conn);
|
||||
|
||||
String searchQuery = buildOrQueryWithFilter(getCfg().getProfile().getFilter(), buildUidFromMatrixId(userId), getUidAtt());
|
||||
String searchQuery = buildOrQueryWithFilter(getCfg().getProfile().getFilter(), uid, getUidAtt());
|
||||
|
||||
log.debug("Base DN: {}", getBaseDn());
|
||||
log.debug("Query: {}", searchQuery);
|
||||
@@ -74,7 +77,7 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
|
||||
while (cursor.next()) {
|
||||
Entry entry = cursor.get();
|
||||
log.info("Found possible match, DN: {}", entry.getDn().getName());
|
||||
Optional<String> v = getAttribute(entry, getAt().getName()).flatMap(uid -> {
|
||||
Optional<String> v = getAttribute(entry, getAt().getName()).flatMap(id -> {
|
||||
log.info("DN {} is a valid match", entry.getDn().getName());
|
||||
try {
|
||||
return getAttribute(entry, getAt().getName());
|
||||
@@ -102,7 +105,7 @@ public class LdapProfileProvider extends LdapBackend implements ProfileProvider
|
||||
@Override
|
||||
public List<_ThreePid> getThreepids(_MatrixID userId) {
|
||||
String uid = buildUidFromMatrixId(userId);
|
||||
log.info("Looking for display name of {}", uid);
|
||||
log.info("Searching for 3PIDs of {}:", uid);
|
||||
|
||||
List<_ThreePid> threePids = new ArrayList<>();
|
||||
try (LdapConnection conn = getConn()) {
|
||||
|
@@ -23,7 +23,7 @@ package io.kamax.mxisd.backend.ldap.netiq;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.mxisd.backend.ldap.LdapProfileProvider;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import io.kamax.mxisd.config.ldap.LdapConfig;
|
||||
import io.kamax.mxisd.config.ldap.netiq.NetIqLdapConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -31,7 +31,7 @@ import org.springframework.stereotype.Component;
|
||||
public class NetIqLdapProfileProvider extends LdapProfileProvider {
|
||||
|
||||
@Autowired
|
||||
public NetIqLdapProfileProvider(LdapConfig cfg, MatrixConfig mxCfg) {
|
||||
public NetIqLdapProfileProvider(NetIqLdapConfig cfg, MatrixConfig mxCfg) {
|
||||
super(cfg, mxCfg);
|
||||
}
|
||||
|
||||
|
@@ -20,6 +20,7 @@
|
||||
|
||||
package io.kamax.mxisd.backend.rest;
|
||||
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.mxisd.UserID;
|
||||
|
||||
public class LookupSingleResponseJson {
|
||||
@@ -32,12 +33,28 @@ public class LookupSingleResponseJson {
|
||||
return medium;
|
||||
}
|
||||
|
||||
public void setMedium(String medium) {
|
||||
this.medium = medium;
|
||||
}
|
||||
|
||||
public void setMedium(ThreePidMedium medium) {
|
||||
setMedium(medium.getId());
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public UserID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(UserID id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
}
|
||||
|
540
src/main/java/io/kamax/mxisd/config/ExecConfig.java
Normal file
540
src/main/java/io/kamax/mxisd/config/ExecConfig.java
Normal file
@@ -0,0 +1,540 @@
|
||||
/*
|
||||
* 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 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.*;
|
||||
|
||||
@Configuration
|
||||
@ConfigurationProperties("exec")
|
||||
public class ExecConfig {
|
||||
|
||||
public class IO {
|
||||
|
||||
private String type;
|
||||
private String template;
|
||||
|
||||
public Optional<String> getType() {
|
||||
return Optional.ofNullable(type);
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Optional<String> getTemplate() {
|
||||
return Optional.ofNullable(template);
|
||||
}
|
||||
|
||||
public void setTemplate(String template) {
|
||||
this.template = template;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Exit {
|
||||
|
||||
private List<Integer> success = Collections.singletonList(0);
|
||||
private List<Integer> failure = Collections.singletonList(1);
|
||||
|
||||
public List<Integer> getSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public void setSuccess(List<Integer> success) {
|
||||
this.success = success;
|
||||
}
|
||||
|
||||
public List<Integer> getFailure() {
|
||||
return failure;
|
||||
}
|
||||
|
||||
public void setFailure(List<Integer> failure) {
|
||||
this.failure = failure;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class TokenOverride {
|
||||
|
||||
private String localpart;
|
||||
private String domain;
|
||||
private String mxid;
|
||||
private String password;
|
||||
private String medium;
|
||||
private String address;
|
||||
private String type;
|
||||
private String query;
|
||||
|
||||
public String getLocalpart() {
|
||||
return StringUtils.defaultIfEmpty(localpart, getToken().getLocalpart());
|
||||
}
|
||||
|
||||
public void setLocalpart(String localpart) {
|
||||
this.localpart = localpart;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return StringUtils.defaultIfEmpty(domain, getToken().getDomain());
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getMxid() {
|
||||
return StringUtils.defaultIfEmpty(mxid, getToken().getMxid());
|
||||
}
|
||||
|
||||
public void setMxid(String mxid) {
|
||||
this.mxid = mxid;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return StringUtils.defaultIfEmpty(password, getToken().getPassword());
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getMedium() {
|
||||
return StringUtils.defaultIfEmpty(medium, getToken().getMedium());
|
||||
}
|
||||
|
||||
public void setMedium(String medium) {
|
||||
this.medium = medium;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return StringUtils.defaultIfEmpty(address, getToken().getAddress());
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return StringUtils.defaultIfEmpty(type, getToken().getType());
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return StringUtils.defaultIfEmpty(query, getToken().getQuery());
|
||||
}
|
||||
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Token {
|
||||
|
||||
private String localpart = "{localpart}";
|
||||
private String domain = "{domain}";
|
||||
private String mxid = "{mxid}";
|
||||
private String password = "{password}";
|
||||
private String medium = "{medium}";
|
||||
private String address = "{address}";
|
||||
private String type = "{type}";
|
||||
private String query = "{query}";
|
||||
|
||||
public String getLocalpart() {
|
||||
return localpart;
|
||||
}
|
||||
|
||||
public void setLocalpart(String localpart) {
|
||||
this.localpart = localpart;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getMxid() {
|
||||
return mxid;
|
||||
}
|
||||
|
||||
public void setMxid(String mxid) {
|
||||
this.mxid = mxid;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getMedium() {
|
||||
return medium;
|
||||
}
|
||||
|
||||
public void setMedium(String medium) {
|
||||
this.medium = medium;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getQuery() {
|
||||
return query;
|
||||
}
|
||||
|
||||
public void setQuery(String query) {
|
||||
this.query = query;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Process {
|
||||
|
||||
private TokenOverride token = new TokenOverride();
|
||||
private String command;
|
||||
|
||||
private List<String> args = new ArrayList<>();
|
||||
private Map<String, String> env = new HashMap<>();
|
||||
private IO input = new IO();
|
||||
|
||||
private Exit exit = new Exit();
|
||||
private IO output = new IO();
|
||||
|
||||
public TokenOverride getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(TokenOverride token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getCommand() {
|
||||
return command;
|
||||
}
|
||||
|
||||
public void setCommand(String command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
public List<String> getArgs() {
|
||||
return args;
|
||||
}
|
||||
|
||||
public void setArgs(List<String> args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Map<String, String> getEnv() {
|
||||
return env;
|
||||
}
|
||||
|
||||
public void setEnv(Map<String, String> env) {
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public void addEnv(String key, String value) {
|
||||
this.env.put(key, value);
|
||||
}
|
||||
|
||||
public IO getInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
public void setInput(IO input) {
|
||||
this.input = input;
|
||||
}
|
||||
|
||||
public Exit getExit() {
|
||||
return exit;
|
||||
}
|
||||
|
||||
public void setExit(Exit exit) {
|
||||
this.exit = exit;
|
||||
}
|
||||
|
||||
public IO getOutput() {
|
||||
return output;
|
||||
}
|
||||
|
||||
public void setOutput(IO output) {
|
||||
this.output = output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Auth extends Process {
|
||||
|
||||
private Boolean enabled;
|
||||
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Directory {
|
||||
|
||||
public class Search {
|
||||
|
||||
private Process byName = new Process();
|
||||
private Process byThreepid = new Process();
|
||||
|
||||
public Process getByName() {
|
||||
return byName;
|
||||
}
|
||||
|
||||
public void setByName(Process byName) {
|
||||
this.byName = byName;
|
||||
}
|
||||
|
||||
public Process getByThreepid() {
|
||||
return byThreepid;
|
||||
}
|
||||
|
||||
public void setByThreepid(Process byThreepid) {
|
||||
this.byThreepid = byThreepid;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Boolean enabled;
|
||||
private Search search = new Search();
|
||||
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Search getSearch() {
|
||||
return search;
|
||||
}
|
||||
|
||||
public void setSearch(Search search) {
|
||||
this.search = search;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Lookup {
|
||||
|
||||
private Process single = new Process();
|
||||
private Process bulk = new Process();
|
||||
|
||||
public Process getSingle() {
|
||||
return single;
|
||||
}
|
||||
|
||||
public void setSingle(Process single) {
|
||||
this.single = single;
|
||||
}
|
||||
|
||||
public Process getBulk() {
|
||||
return bulk;
|
||||
}
|
||||
|
||||
public void setBulk(Process bulk) {
|
||||
this.bulk = bulk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Identity {
|
||||
|
||||
private Boolean enabled;
|
||||
private int priority;
|
||||
private Lookup lookup = new Lookup();
|
||||
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public void setPriority(int priority) {
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
public Lookup getLookup() {
|
||||
return lookup;
|
||||
}
|
||||
|
||||
public void setLookup(Lookup lookup) {
|
||||
this.lookup = lookup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class Profile {
|
||||
|
||||
private Boolean enabled;
|
||||
private Process displayName = new Process();
|
||||
private Process threePid = new Process();
|
||||
private Process role = new Process();
|
||||
|
||||
public Boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(Boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Process getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(Process displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public Process getThreePid() {
|
||||
return threePid;
|
||||
}
|
||||
|
||||
public void setThreePid(Process threePid) {
|
||||
this.threePid = threePid;
|
||||
}
|
||||
|
||||
public Process getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public void setRoles(Process role) {
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private boolean enabled;
|
||||
private Token token = new Token();
|
||||
private Auth auth = new Auth();
|
||||
private Directory directory = new Directory();
|
||||
private Identity identity = new Identity();
|
||||
private Profile profile = new Profile();
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
public Token getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(Token token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public Auth getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setAuth(Auth auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public Directory getDirectory() {
|
||||
return directory;
|
||||
}
|
||||
|
||||
public void setDirectory(Directory directory) {
|
||||
this.directory = directory;
|
||||
}
|
||||
|
||||
public Identity getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
|
||||
public void setIdentity(Identity identity) {
|
||||
this.identity = identity;
|
||||
}
|
||||
|
||||
public Profile getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void setProfile(Profile profile) {
|
||||
this.profile = profile;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public ExecConfig compute() {
|
||||
if (Objects.isNull(getAuth().isEnabled())) {
|
||||
getAuth().setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
if (Objects.isNull(getDirectory().isEnabled())) {
|
||||
getDirectory().setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
if (Objects.isNull(getIdentity().isEnabled())) {
|
||||
getIdentity().setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
if (Objects.isNull(getProfile().isEnabled())) {
|
||||
getProfile().setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
@@ -29,6 +29,11 @@ public class UserDirectorySearchRequest {
|
||||
setSearchTerm(searchTerm);
|
||||
}
|
||||
|
||||
public UserDirectorySearchRequest(String type, String searchTerm) {
|
||||
setBy(type);
|
||||
setSearchTerm(searchTerm);
|
||||
}
|
||||
|
||||
public String getBy() {
|
||||
return by;
|
||||
}
|
||||
|
@@ -25,6 +25,10 @@ import java.util.Set;
|
||||
|
||||
public class UserDirectorySearchResult {
|
||||
|
||||
public static UserDirectorySearchResult empty() {
|
||||
return new UserDirectorySearchResult();
|
||||
}
|
||||
|
||||
public static class Result {
|
||||
|
||||
private String displayName;
|
||||
|
67
src/main/java/io/kamax/mxisd/profile/JsonProfileRequest.java
Normal file
67
src/main/java/io/kamax/mxisd/profile/JsonProfileRequest.java
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* 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.profile;
|
||||
|
||||
import io.kamax.matrix._MatrixID;
|
||||
|
||||
public class JsonProfileRequest {
|
||||
|
||||
private String localpart;
|
||||
private String domain;
|
||||
private String mxid;
|
||||
|
||||
public JsonProfileRequest(_MatrixID mxId) {
|
||||
this.localpart = mxId.getLocalPart();
|
||||
this.domain = mxId.getDomain();
|
||||
this.mxid = mxId.getId();
|
||||
}
|
||||
|
||||
public JsonProfileRequest(String localpart, String domain, String mxId) {
|
||||
this.localpart = localpart;
|
||||
this.domain = domain;
|
||||
this.mxid = mxId;
|
||||
}
|
||||
|
||||
public String getLocalpart() {
|
||||
return localpart;
|
||||
}
|
||||
|
||||
public void setLocalpart(String localpart) {
|
||||
this.localpart = localpart;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
public String getMxid() {
|
||||
return mxid;
|
||||
}
|
||||
|
||||
public void setMxid(String mxid) {
|
||||
this.mxid = mxid;
|
||||
}
|
||||
|
||||
}
|
69
src/main/java/io/kamax/mxisd/profile/JsonProfileResult.java
Normal file
69
src/main/java/io/kamax/mxisd/profile/JsonProfileResult.java
Normal 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.profile;
|
||||
|
||||
import io.kamax.matrix.ThreePid;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class JsonProfileResult {
|
||||
|
||||
private String displayName;
|
||||
private List<ThreePid> threepids;
|
||||
private List<String> roles;
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public List<ThreePid> getThreepids() {
|
||||
return threepids;
|
||||
}
|
||||
|
||||
public void setThreepids(List<ThreePid> threepids) {
|
||||
this.threepids = threepids;
|
||||
}
|
||||
|
||||
public void addThreepid(ThreePid threepid) {
|
||||
if (Objects.isNull(threepids)) threepids = new ArrayList<>();
|
||||
threepids.add(threepid);
|
||||
}
|
||||
|
||||
public List<String> getRoles() {
|
||||
return roles;
|
||||
}
|
||||
|
||||
public void setRoles(List<String> roles) {
|
||||
this.roles = roles;
|
||||
}
|
||||
|
||||
public void addRole(String role) {
|
||||
if (Objects.isNull(roles)) roles = new ArrayList<>();
|
||||
roles.add(role);
|
||||
}
|
||||
|
||||
}
|
@@ -48,12 +48,13 @@ public class ProfileManager {
|
||||
|
||||
@PostConstruct
|
||||
public void build() {
|
||||
providers = providers.stream()
|
||||
.filter(ProfileProvider::isEnabled)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("--- Profile providers ---");
|
||||
this.providers.forEach(pp -> log.info("\t- {}", pp.getClass().getSimpleName()));
|
||||
providers = providers.stream()
|
||||
.filter(pp -> {
|
||||
log.info("\t- {} - Is enabled? {}", pp.getClass().getSimpleName(), pp.isEnabled());
|
||||
return pp.isEnabled();
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public <T> List<T> getList(Function<ProfileProvider, List<T>> function) {
|
||||
|
28
src/main/java/io/kamax/mxisd/util/TriFunction.java
Normal file
28
src/main/java/io/kamax/mxisd/util/TriFunction.java
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
@FunctionalInterface
|
||||
public interface TriFunction<T, U, V, R> {
|
||||
|
||||
R apply(T t, U u, V v);
|
||||
|
||||
}
|
202
src/test/java/io/kamax/mxisd/backend/exec/ExecAuthStoreTest.java
Normal file
202
src/test/java/io/kamax/mxisd/backend/exec/ExecAuthStoreTest.java
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* 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.matrix.MatrixID;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import org.apache.commons.lang3.RandomStringUtils;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public abstract class ExecAuthStoreTest {
|
||||
|
||||
protected final ExecConfig cfg;
|
||||
protected final ExecAuthStore p;
|
||||
protected final String requiredPass = Long.toString(System.currentTimeMillis());
|
||||
protected final String localpart = "user";
|
||||
protected final String domain = "domain.tld";
|
||||
protected final _MatrixID uId = MatrixID.from(localpart, domain).valid();
|
||||
|
||||
protected final String LocalpartToken = "{localpart}";
|
||||
protected final String DomainToken = "{domain}";
|
||||
protected final String MxidToken = "{mxid}";
|
||||
protected final String PassToken = "{password}";
|
||||
|
||||
protected final String LocalpartInvalid = "@:";
|
||||
protected final String DomainInvalid = "[.]:";
|
||||
protected final String MxidInvalid = LocalpartInvalid + DomainInvalid;
|
||||
protected final String PassInvalid = RandomStringUtils.randomAscii(20);
|
||||
|
||||
protected abstract void setValidCommand();
|
||||
|
||||
protected void setValidEnv() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected void setValidArgs() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected void setValidInput() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
protected void setValidExit() {
|
||||
cfg.getAuth().getExit().setSuccess(Collections.singletonList(0));
|
||||
cfg.getAuth().getExit().setFailure(Arrays.asList(1, 10, 11, 12, 20, 21, 22));
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setValidConfig() {
|
||||
setValidCommand();
|
||||
setValidEnv();
|
||||
setValidArgs();
|
||||
setValidInput();
|
||||
setValidExit();
|
||||
|
||||
cfg.getAuth().addEnv("WITH_LOCALPART", "1");
|
||||
cfg.getAuth().addEnv("REQ_LOCALPART", uId.getLocalPart());
|
||||
cfg.getAuth().addEnv("WITH_DOMAIN", "1");
|
||||
cfg.getAuth().addEnv("REQ_DOMAIN", uId.getDomain());
|
||||
cfg.getAuth().addEnv("WITH_MXID", "1");
|
||||
cfg.getAuth().addEnv("REQ_MXID", uId.getId());
|
||||
cfg.getAuth().addEnv("REQ_PASS", requiredPass);
|
||||
}
|
||||
|
||||
public ExecAuthStoreTest() {
|
||||
cfg = new ExecConfig();
|
||||
p = new ExecAuthStore(cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validPassword() {
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(true, res.isSuccess());
|
||||
assertEquals(0, res.getExitStatus());
|
||||
assertEquals(UserIdType.Localpart.getId(), res.getId().getType());
|
||||
assertEquals(uId.getLocalPart(), res.getId().getValue());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void invalidPassword() {
|
||||
ExecAuthResult res = p.authenticate(uId, PassInvalid);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(1, res.getExitStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptyPassword() {
|
||||
ExecAuthResult res = p.authenticate(uId, "");
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(1, res.getExitStatus());
|
||||
}
|
||||
|
||||
@Test(expected = NullPointerException.class)
|
||||
public void nullPassword() {
|
||||
p.authenticate(uId, null);
|
||||
}
|
||||
|
||||
protected abstract void setEmptyLocalpartConfig();
|
||||
|
||||
@Test
|
||||
public void emptyLocalpartConfig() {
|
||||
setEmptyLocalpartConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(10, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
public abstract void setWrongLocalpartConfig();
|
||||
|
||||
@Test
|
||||
public void wrongLocalpartConfig() {
|
||||
setWrongLocalpartConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(20, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
protected abstract void setEmptyDomainConfig();
|
||||
|
||||
@Test
|
||||
public void emptyDomainConfig() {
|
||||
setEmptyDomainConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(11, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
public abstract void setWrongDomainConfig();
|
||||
|
||||
@Test
|
||||
public void wrongDomainConfig() {
|
||||
setWrongDomainConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(21, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
protected abstract void setEmptyMxidConfig();
|
||||
|
||||
@Test
|
||||
public void emptyMxidConfig() {
|
||||
setEmptyMxidConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(12, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
public abstract void setWrongMxidConfig();
|
||||
|
||||
@Test
|
||||
public void wrongMxidConfig() {
|
||||
setWrongMxidConfig();
|
||||
|
||||
ExecAuthResult res = p.authenticate(uId, requiredPass);
|
||||
assertEquals(false, res.isSuccess());
|
||||
assertEquals(22, res.getExitStatus());
|
||||
|
||||
setValidConfig();
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.matrix.MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class ExecDirectoryStoreTest extends ExecStoreTest {
|
||||
|
||||
public ExecDirectoryStoreTest() {
|
||||
executables.put("byNameSuccessEmptyResult", () ->
|
||||
make(0, () ->
|
||||
GsonUtil.get().toJson(UserDirectorySearchResult.empty())
|
||||
)
|
||||
);
|
||||
|
||||
executables.put("byNameSuccessSingleResult", () -> make(0, () -> {
|
||||
UserDirectorySearchResult.Result resultIo = new UserDirectorySearchResult.Result();
|
||||
resultIo.setUserId(user1Localpart);
|
||||
resultIo.setDisplayName(user1Name);
|
||||
UserDirectorySearchResult io = new UserDirectorySearchResult();
|
||||
io.setLimited(false);
|
||||
io.setResults(Collections.singleton(resultIo));
|
||||
return GsonUtil.get().toJson(io);
|
||||
}));
|
||||
}
|
||||
|
||||
private ExecConfig.Directory getCfg() {
|
||||
ExecConfig.Directory cfg = new ExecConfig().compute().getDirectory();
|
||||
assertFalse(cfg.isEnabled());
|
||||
cfg.setEnabled(true);
|
||||
assertTrue(cfg.isEnabled());
|
||||
cfg.getSearch().getByName().getOutput().setType(ExecStore.JsonType);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private ExecDirectoryStore getStore(ExecConfig.Directory cfg) {
|
||||
ExecDirectoryStore store = new ExecDirectoryStore(cfg, getMatrixCfg());
|
||||
store.setExecutorSupplier(this::build);
|
||||
assertTrue(store.isEnabled());
|
||||
return store;
|
||||
}
|
||||
|
||||
private ExecDirectoryStore getStore(String command) {
|
||||
ExecConfig.Directory cfg = getCfg();
|
||||
cfg.getSearch().getByName().setCommand(command);
|
||||
cfg.getSearch().getByThreepid().setCommand(command);
|
||||
return getStore(cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameNoCommandDefined() {
|
||||
ExecConfig.Directory cfg = getCfg();
|
||||
assertTrue(StringUtils.isEmpty(cfg.getSearch().getByName().getCommand()));
|
||||
ExecDirectoryStore store = getStore(cfg);
|
||||
|
||||
UserDirectorySearchResult result = store.searchByDisplayName("user");
|
||||
assertFalse(result.isLimited());
|
||||
assertTrue(result.getResults().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameSuccessNoOutput() {
|
||||
UserDirectorySearchResult result = getStore(sno).searchByDisplayName("user");
|
||||
assertFalse(result.isLimited());
|
||||
assertTrue(result.getResults().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameSuccessEmptyResult() {
|
||||
UserDirectorySearchResult output = getStore("byNameSuccessEmptyResult").searchByDisplayName("user");
|
||||
assertFalse(output.isLimited());
|
||||
assertTrue(output.getResults().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameSuccessSingleResult() {
|
||||
UserDirectorySearchResult output = getStore("byNameSuccessSingleResult").searchByDisplayName("user");
|
||||
|
||||
assertFalse(output.isLimited());
|
||||
assertEquals(1, output.getResults().size());
|
||||
UserDirectorySearchResult.Result result = output.getResults().iterator().next();
|
||||
assertEquals(MatrixID.from(user1Localpart, domain).acceptable().getId(), result.getUserId());
|
||||
assertEquals(user1Name, result.getDisplayName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void byNameFailureNoOutput() {
|
||||
UserDirectorySearchResult result = getStore(fno).searchByDisplayName("user");
|
||||
assertFalse(result.isLimited());
|
||||
assertTrue(result.getResults().isEmpty());
|
||||
}
|
||||
|
||||
@Test(expected = InternalServerError.class)
|
||||
public void byNameUnknownNoOutput() {
|
||||
getStore(uno).searchByDisplayName("user");
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* 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 com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.UserID;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
import io.kamax.mxisd.backend.rest.LookupSingleResponseJson;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.exception.InternalServerError;
|
||||
import io.kamax.mxisd.lookup.SingleLookupReply;
|
||||
import io.kamax.mxisd.lookup.SingleLookupRequest;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class ExecIdentityStoreTest extends ExecStoreTest {
|
||||
|
||||
public ExecIdentityStoreTest() {
|
||||
executables.put("singleSuccessEmpty", () -> make(0, () ->
|
||||
GsonUtil.get().toJson(GsonUtil.makeObj("lookup", new JsonObject()))));
|
||||
|
||||
executables.put("singleSuccessData", () -> makeJson(0, () -> {
|
||||
LookupSingleResponseJson json = new LookupSingleResponseJson();
|
||||
json.setMedium(ThreePidMedium.Email);
|
||||
json.setAddress(user1Email);
|
||||
json.setId(new UserID(UserIdType.Localpart, user1Localpart));
|
||||
return GsonUtil.makeObj("lookup", GsonUtil.get().toJsonTree(json));
|
||||
}));
|
||||
|
||||
executables.put("singleSuccessEmptyFromInvalidOutput", () -> makeJson(0, () -> {
|
||||
JsonObject lookup = new JsonObject();
|
||||
lookup.addProperty("medium", "");
|
||||
return GsonUtil.makeObj("lookup", lookup);
|
||||
}));
|
||||
}
|
||||
|
||||
private ExecConfig.Identity getCfg() {
|
||||
ExecConfig.Identity cfg = new ExecConfig().compute().getIdentity();
|
||||
assertFalse(cfg.isEnabled());
|
||||
cfg.setEnabled(true);
|
||||
assertTrue(cfg.isEnabled());
|
||||
cfg.getLookup().getSingle().getOutput().setType(ExecStore.JsonType);
|
||||
cfg.getLookup().getBulk().getOutput().setType(ExecStore.JsonType);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private ExecIdentityStore getStore(ExecConfig.Identity cfg) {
|
||||
ExecIdentityStore store = new ExecIdentityStore(cfg, getMatrixCfg());
|
||||
store.setExecutorSupplier(this::build);
|
||||
assertTrue(store.isEnabled());
|
||||
return store;
|
||||
}
|
||||
|
||||
private ExecIdentityStore getStore(String command) {
|
||||
ExecConfig.Identity cfg = getCfg();
|
||||
cfg.getLookup().getSingle().setCommand(command);
|
||||
cfg.getLookup().getBulk().setCommand(command);
|
||||
return getStore(cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleSuccessNoOutput() {
|
||||
ExecIdentityStore store = getStore(sno);
|
||||
|
||||
SingleLookupRequest req = new SingleLookupRequest();
|
||||
req.setType(ThreePidMedium.Email.getId());
|
||||
req.setThreePid(user1Email);
|
||||
Optional<SingleLookupReply> lookup = store.find(req);
|
||||
assertFalse(lookup.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleSuccessEmpty() {
|
||||
ExecIdentityStore store = getStore("singleSuccessEmpty");
|
||||
|
||||
SingleLookupRequest req = new SingleLookupRequest();
|
||||
req.setType(ThreePidMedium.Email.getId());
|
||||
req.setThreePid(user1Email);
|
||||
Optional<SingleLookupReply> lookup = store.find(req);
|
||||
assertFalse(lookup.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void singleSuccessData() {
|
||||
SingleLookupRequest req = new SingleLookupRequest();
|
||||
req.setType(ThreePidMedium.Email.getId());
|
||||
req.setThreePid(user1Email);
|
||||
|
||||
Optional<SingleLookupReply> lookup = getStore("singleSuccessData").find(req);
|
||||
assertTrue(lookup.isPresent());
|
||||
SingleLookupReply reply = lookup.get();
|
||||
assertEquals(MatrixID.asAcceptable(user1Localpart, domain), reply.getMxid());
|
||||
}
|
||||
|
||||
@Test(expected = InternalServerError.class)
|
||||
public void singleSuccessEmptyFromInvalidOutput() {
|
||||
SingleLookupRequest req = new SingleLookupRequest();
|
||||
req.setType(ThreePidMedium.Email.getId());
|
||||
req.setThreePid(user1Email);
|
||||
getStore("singleSuccessEmptyFromInvalidOutput").find(req);
|
||||
}
|
||||
|
||||
}
|
@@ -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.exec;
|
||||
|
||||
import com.google.gson.JsonObject;
|
||||
import io.kamax.matrix.MatrixID;
|
||||
import io.kamax.matrix.ThreePid;
|
||||
import io.kamax.matrix.ThreePidMedium;
|
||||
import io.kamax.matrix._ThreePid;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.UserIdType;
|
||||
import io.kamax.mxisd.config.ExecConfig;
|
||||
import io.kamax.mxisd.profile.JsonProfileResult;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class ExecProfileStoreTest extends ExecStoreTest {
|
||||
|
||||
private final String seo = "successEmptyOutput";
|
||||
private final String sn = "successName";
|
||||
private final String sst = "successSingleThreepid";
|
||||
private final String smt = "successMultiThreepid";
|
||||
private final String user1Msisdn = Long.toString(System.currentTimeMillis());
|
||||
|
||||
public ExecProfileStoreTest() {
|
||||
executables.put(seo, () -> make(0, () -> "{}"));
|
||||
executables.put(sn, () -> makeJson(0, () -> {
|
||||
JsonObject profile = new JsonObject();
|
||||
profile.addProperty("display_name", user1Name);
|
||||
return GsonUtil.makeObj("profile", profile);
|
||||
}));
|
||||
executables.put(sst, () -> makeJson(0, () -> {
|
||||
JsonProfileResult profile = new JsonProfileResult();
|
||||
profile.addThreepid(new ThreePid(ThreePidMedium.Email.getId(), user1Email));
|
||||
return GsonUtil.makeObj("profile", profile);
|
||||
}));
|
||||
|
||||
executables.put(smt, () -> makeJson(0, () -> {
|
||||
JsonProfileResult profile = new JsonProfileResult();
|
||||
profile.addThreepid(new ThreePid(ThreePidMedium.Email.getId(), user1Email));
|
||||
profile.addThreepid(new ThreePid(ThreePidMedium.PhoneNumber.getId(), user1Msisdn));
|
||||
return GsonUtil.makeObj("profile", profile);
|
||||
}));
|
||||
|
||||
}
|
||||
|
||||
private ExecConfig.Profile getCfg() {
|
||||
ExecConfig.Profile cfg = new ExecConfig().compute().getProfile();
|
||||
assertFalse(cfg.isEnabled());
|
||||
cfg.setEnabled(true);
|
||||
assertTrue(cfg.isEnabled());
|
||||
cfg.getDisplayName().getOutput().setType(ExecStore.JsonType);
|
||||
cfg.getThreePid().getOutput().setType(ExecStore.JsonType);
|
||||
cfg.getRole().getOutput().setType(ExecStore.JsonType);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
private ExecProfileStore getStore(ExecConfig.Profile cfg) {
|
||||
ExecProfileStore store = new ExecProfileStore(cfg);
|
||||
store.setExecutorSupplier(this::build);
|
||||
assertTrue(store.isEnabled());
|
||||
return store;
|
||||
}
|
||||
|
||||
private ExecProfileStore getStore(String command) {
|
||||
ExecConfig.Profile cfg = getCfg();
|
||||
cfg.getDisplayName().setCommand(command);
|
||||
cfg.getThreePid().setCommand(command);
|
||||
cfg.getRole().setCommand(command);
|
||||
return getStore(cfg);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameSuccessNoOutput() {
|
||||
Optional<String> name = getStore(sno).getDisplayName(MatrixID.asAcceptable(user1Localpart, domain));
|
||||
assertFalse(name.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameSuccessEmptyOutput() {
|
||||
Optional<String> name = getStore(seo).getDisplayName(MatrixID.asAcceptable(user1Localpart, domain));
|
||||
assertFalse(name.isPresent());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getNameSuccess() {
|
||||
Optional<String> name = getStore(sn).getDisplayName(user1Id);
|
||||
assertTrue(name.isPresent());
|
||||
assertEquals(user1Name, name.get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSingleThreePidSuccess() {
|
||||
List<_ThreePid> tpids = getStore(sst).getThreepids(user1Id);
|
||||
assertEquals(1, tpids.size());
|
||||
|
||||
_ThreePid tpid = tpids.get(0);
|
||||
assertEquals(UserIdType.Email.getId(), tpid.getMedium());
|
||||
assertEquals(user1Email, tpid.getAddress());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMultiThreePidSuccess() {
|
||||
List<_ThreePid> tpids = getStore(smt).getThreepids(user1Id);
|
||||
assertEquals(2, tpids.size());
|
||||
|
||||
_ThreePid firstTpid = tpids.get(0);
|
||||
assertEquals(ThreePidMedium.Email.getId(), firstTpid.getMedium());
|
||||
assertEquals(user1Email, firstTpid.getAddress());
|
||||
|
||||
_ThreePid secondTpid = tpids.get(1);
|
||||
assertEquals(ThreePidMedium.PhoneNumber.getId(), secondTpid.getMedium());
|
||||
assertEquals(user1Msisdn, secondTpid.getAddress());
|
||||
}
|
||||
|
||||
}
|
98
src/test/java/io/kamax/mxisd/backend/exec/ExecStoreTest.java
Normal file
98
src/test/java/io/kamax/mxisd/backend/exec/ExecStoreTest.java
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* 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.matrix.MatrixID;
|
||||
import io.kamax.matrix._MatrixID;
|
||||
import io.kamax.matrix.json.GsonUtil;
|
||||
import io.kamax.mxisd.config.MatrixConfig;
|
||||
import org.zeroturnaround.exec.ProcessExecutor;
|
||||
import org.zeroturnaround.exec.ProcessResult;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ExecStoreTest {
|
||||
|
||||
protected final String sno = "successNoOutput";
|
||||
protected final String fno = "failureNoOutput";
|
||||
protected final String uno = "unknownNoOutput";
|
||||
|
||||
protected final String domain = "domain.tld";
|
||||
protected final String userLocalpart = "user";
|
||||
protected final String user1Localpart = userLocalpart + "1";
|
||||
protected final String user1Name = "User 1";
|
||||
protected final String user2Localpart = userLocalpart + "2";
|
||||
protected final String user2Name = "User 2";
|
||||
protected final _MatrixID user1Id = MatrixID.asAcceptable(user1Localpart, domain);
|
||||
protected final String user1Email = user1Localpart + "@" + domain;
|
||||
|
||||
protected Map<String, Supplier<ProcessResult>> executables = new HashMap<>();
|
||||
|
||||
public ExecStoreTest() {
|
||||
executables.put(sno, () -> make(0, () -> ""));
|
||||
executables.put(fno, () -> make(1, () -> ""));
|
||||
executables.put(uno, () -> make(Integer.MAX_VALUE, () -> ""));
|
||||
}
|
||||
|
||||
protected MatrixConfig getMatrixCfg() {
|
||||
MatrixConfig mxCfg = new MatrixConfig();
|
||||
mxCfg.setDomain(domain);
|
||||
return mxCfg;
|
||||
}
|
||||
|
||||
protected ProcessResult make(int exitCode, Supplier<String> supplier) {
|
||||
return new ProcessResult(exitCode, null) {
|
||||
|
||||
@Override
|
||||
public String outputUTF8() {
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
protected ProcessResult makeJson(int exitCode, Supplier<Object> supplier) {
|
||||
return make(exitCode, () -> GsonUtil.get().toJson(supplier.get()));
|
||||
}
|
||||
|
||||
protected ProcessExecutor build() {
|
||||
return new ProcessExecutor() {
|
||||
|
||||
private Function<String, RuntimeException> notFound = command ->
|
||||
new IllegalArgumentException("Command not found: " + command);
|
||||
|
||||
@Override
|
||||
public ProcessResult execute() {
|
||||
if (getCommand().size() == 0) throw new IllegalStateException();
|
||||
|
||||
String command = getCommand().get(0);
|
||||
return executables.getOrDefault(command, () -> {
|
||||
throw notFound.apply(command);
|
||||
}).get();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
@@ -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.backend.exec.auth.input;
|
||||
|
||||
import io.kamax.mxisd.backend.exec.ExecAuthStoreTest;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ExecAuthArgsTest extends ExecAuthStoreTest {
|
||||
|
||||
@Override
|
||||
protected void setValidCommand() {
|
||||
cfg.getAuth().setCommand("src/test/resources/store/exec/input/argsTest.sh");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValidArgs() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartToken, DomainToken, MxidToken, PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyLocalpartConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList("", DomainToken, MxidToken, PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongLocalpartConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartInvalid, DomainToken, MxidToken, PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyDomainConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartToken, "", MxidToken, PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongDomainConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartToken, DomainInvalid, MxidToken, PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyMxidConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartToken, DomainToken, "", PassToken));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongMxidConfig() {
|
||||
cfg.getAuth().setArgs(Arrays.asList(LocalpartToken, DomainToken, MxidInvalid, PassToken));
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.auth.input;
|
||||
|
||||
import io.kamax.mxisd.backend.exec.ExecAuthStoreTest;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ExecAuthEnvTest extends ExecAuthStoreTest {
|
||||
|
||||
private final String LocalpartEnv = "LOCALPART";
|
||||
private final String DomainEnv = "DOMAIN";
|
||||
private final String MxidEnv = "MXID";
|
||||
|
||||
@Override
|
||||
protected void setValidCommand() {
|
||||
cfg.getAuth().setCommand("src/test/resources/store/exec/input/envTest.sh");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValidEnv() {
|
||||
cfg.getAuth().setEnv(new HashMap<>());
|
||||
cfg.getAuth().addEnv(LocalpartEnv, LocalpartToken);
|
||||
cfg.getAuth().addEnv(DomainEnv, DomainToken);
|
||||
cfg.getAuth().addEnv(MxidEnv, MxidToken);
|
||||
cfg.getAuth().addEnv("PASS", PassToken);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyLocalpartConfig() {
|
||||
cfg.getAuth().addEnv(LocalpartEnv, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongLocalpartConfig() {
|
||||
cfg.getAuth().addEnv(LocalpartEnv, LocalpartInvalid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyDomainConfig() {
|
||||
cfg.getAuth().addEnv(DomainEnv, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongDomainConfig() {
|
||||
cfg.getAuth().addEnv(DomainEnv, DomainInvalid);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyMxidConfig() {
|
||||
cfg.getAuth().addEnv(MxidEnv, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongMxidConfig() {
|
||||
cfg.getAuth().addEnv(MxidEnv, MxidInvalid);
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.auth.input;
|
||||
|
||||
import io.kamax.mxisd.backend.exec.ExecAuthStoreTest;
|
||||
import io.kamax.mxisd.backend.exec.ExecStore;
|
||||
|
||||
public class ExecAuthInputMultilinesTest extends ExecAuthStoreTest {
|
||||
|
||||
@Override
|
||||
protected void setValidCommand() {
|
||||
cfg.getAuth().setCommand("src/test/resources/store/exec/input/multilinesTest.sh");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setValidInput() {
|
||||
cfg.getAuth().getInput().setType(ExecStore.PlainType);
|
||||
cfg.getAuth().getInput().setTemplate(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyLocalpartConfig() {
|
||||
cfg.getAuth().getInput().setTemplate("" + System.lineSeparator()
|
||||
+ DomainToken + System.lineSeparator()
|
||||
+ MxidToken + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongLocalpartConfig() {
|
||||
cfg.getAuth().getInput().setTemplate(LocalpartInvalid + System.lineSeparator()
|
||||
+ DomainToken + System.lineSeparator()
|
||||
+ MxidToken + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyDomainConfig() {
|
||||
cfg.getAuth().getInput().setTemplate(LocalpartToken + System.lineSeparator()
|
||||
+ "" + System.lineSeparator()
|
||||
+ MxidToken + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongDomainConfig() {
|
||||
cfg.getAuth().getInput().setTemplate(LocalpartToken + System.lineSeparator()
|
||||
+ DomainInvalid + System.lineSeparator()
|
||||
+ MxidToken + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEmptyMxidConfig() {
|
||||
cfg.getAuth().getInput().setTemplate(LocalpartToken + System.lineSeparator()
|
||||
+ DomainToken + System.lineSeparator()
|
||||
+ "" + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWrongMxidConfig() {
|
||||
cfg.getAuth().getInput().setTemplate(LocalpartToken + System.lineSeparator()
|
||||
+ DomainToken + System.lineSeparator()
|
||||
+ MxidInvalid + System.lineSeparator()
|
||||
+ PassToken + System.lineSeparator()
|
||||
);
|
||||
}
|
||||
|
||||
}
|
41
src/test/resources/store/exec/input/argsTest.sh
Executable file
41
src/test/resources/store/exec/input/argsTest.sh
Executable file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
if [ -n "$WITH_LOCALPART" ]; then
|
||||
[ -n "$1" ] || exit 10
|
||||
[ "$1" = "$REQ_LOCALPART" ] || exit 20
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_DOMAIN" ]; then
|
||||
[ -n "$1" ] || exit 11
|
||||
[ "$1" = "$REQ_DOMAIN" ] || exit 21
|
||||
shift
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_MXID" ]; then
|
||||
[ -n "$1" ] || exit 12
|
||||
[ "$1" = "$REQ_MXID" ] || exit 22
|
||||
shift
|
||||
fi
|
||||
|
||||
[ "$1" = "$REQ_PASS" ] || exit 1
|
||||
|
||||
exit 0
|
38
src/test/resources/store/exec/input/envTest.sh
Executable file
38
src/test/resources/store/exec/input/envTest.sh
Executable file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
if [ -n "$WITH_LOCALPART" ]; then
|
||||
[ -n "$LOCALPART" ] || exit 10
|
||||
[ "$LOCALPART" = "$REQ_LOCALPART" ] || exit 20
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_DOMAIN" ]; then
|
||||
[ -n "$DOMAIN" ] || exit 11
|
||||
[ "$DOMAIN" = "$REQ_DOMAIN" ] || exit 21
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_MXID" ]; then
|
||||
[ -n "$MXID" ] || exit 12
|
||||
[ "$MXID" = "$REQ_MXID" ] || exit 22
|
||||
fi
|
||||
|
||||
[ "$PASS" = "$REQ_PASS" ] || exit 1
|
||||
|
||||
exit 0
|
42
src/test/resources/store/exec/input/multilinesTest.sh
Executable file
42
src/test/resources/store/exec/input/multilinesTest.sh
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# 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/>.
|
||||
|
||||
if [ -n "$WITH_LOCALPART" ]; then
|
||||
read LOCALPART
|
||||
[ -n "$LOCALPART" ] || exit 10
|
||||
[ "$LOCALPART" = "$REQ_LOCALPART" ] || exit 20
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_DOMAIN" ]; then
|
||||
read DOMAIN
|
||||
[ -n "$DOMAIN" ] || exit 11
|
||||
[ "$DOMAIN" = "$REQ_DOMAIN" ] || exit 21
|
||||
fi
|
||||
|
||||
if [ -n "$WITH_MXID" ]; then
|
||||
read MXID
|
||||
[ -n "$MXID" ] || exit 12
|
||||
[ "$MXID" = "$REQ_MXID" ] || exit 22
|
||||
fi
|
||||
|
||||
read PASS
|
||||
[ "$PASS" = "$REQ_PASS" ] || exit 1
|
||||
|
||||
exit 0
|
Reference in New Issue
Block a user