diff --git a/build.gradle b/build.gradle
index 793a5e98..428719d5 100644
--- a/build.gradle
+++ b/build.gradle
@@ -119,6 +119,9 @@ dependencies {
// PostgreSQL
compile 'org.postgresql:postgresql:42.1.4'
+ // MariaDB/MySQL
+ compile 'org.mariadb.jdbc:mariadb-java-client:2.1.2'
+
// Twilio SDK for SMS
compile 'com.twilio.sdk:twilio:7.14.5'
diff --git a/docs/README.md b/docs/README.md
index c951e3aa..32201b0d 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -17,6 +17,7 @@
- [SQL](backends/sql.md)
- [REST](backends/rest.md)
- [Google Firebase](backends/firebase.md)
+ - [Wordpress](backends/wordpress.md)
- Notifications
- Handlers
- [Basic](threepids/notifications/basic-handler.md)
diff --git a/docs/backends/README.md b/docs/backends/README.md
index 0dbc07b2..e6930e47 100644
--- a/docs/backends/README.md
+++ b/docs/backends/README.md
@@ -2,4 +2,5 @@
- [Samba / Active Directory / LDAP](ldap.md)
- [SQL Databases](sql.md)
- [Website / Web service / Web app](rest.md)
-- [Google Firebase](firebase.md)
\ No newline at end of file
+- [Google Firebase](firebase.md)
+- [Wordpress](wordpress.md)
\ No newline at end of file
diff --git a/docs/backends/wordpress.md b/docs/backends/wordpress.md
new file mode 100644
index 00000000..fc3ef209
--- /dev/null
+++ b/docs/backends/wordpress.md
@@ -0,0 +1,55 @@
+# Wordpress
+This Identity store allows you to use user accounts registered on your Wordpress setup.
+Two types of connections are required for full support:
+- [REST API](https://developer.wordpress.org/rest-api/) with JWT authentication
+- Direct SQL access
+
+This Identity store supports the following features:
+- [Authentication](../features/authentication.md)
+- [Directory](../features/directory-users.md)
+- [Identity](../features/identity.md)
+
+## Requirements
+- [Wordpress](https://wordpress.org/download/) >= 4.4
+- Permalink structure set to `Post Name`
+- [JWT Auth plugin for REST API](https://wordpress.org/plugins/jwt-authentication-for-wp-rest-api/)
+- SQL Credentials to the Wordpress Database
+
+## Configuration
+### Wordpress
+#### JWT Auth
+Set a JWT secret into `wp-config.php` like so:
+```
+define('JWT_AUTH_SECRET_KEY', 'your-top-secret-key');
+```
+`your-top-secret-key` should be set to a randomly generated value which is kept secret.
+
+#### Rewrite of `index.php`
+Wordpress is normally configured with rewrite of `index.php` so it does not appear in URLs.
+If this is not the case for your installation, the mxisd URL will need to be appended with `/index.php`
+
+### mxisd
+Enable in the configuration:
+```
+wordpress.enabled: true
+```
+Configure the URL to your Wordpress installation - see above about added `/index.php`:
+```
+wordpress.rest.base: 'http://localhost:8080'
+```
+Configure the SQL connection to your Wordpress database:
+```
+wordpress.sql.connection: '//127.0.0.1/wordpress?user=root&password=example'
+```
+
+---
+
+By default, MySQL database is expected. If you use another database, use:
+```
+wordpress.sql.type: 'jdbc-scheme'
+```
+With possible values:
+- `mysql`
+- `mariadb`
+- `postgresql`
+- `sqlite`
diff --git a/docs/features/authentication.md b/docs/features/authentication.md
index 4297a15c..3586cdd9 100644
--- a/docs/features/authentication.md
+++ b/docs/features/authentication.md
@@ -115,8 +115,8 @@ Steps of user authentication using a 3PID:
- Homeserver
- Compatible Identity backends:
- LDAP
- - SQL
- REST
+ - Wordpress
### Configuration
@@ -160,12 +160,3 @@ value is the base internal URL of the Homeserver, without any /_matrix/.. or tra
#### Backends
The Backends should be configured as described in the documentation of the [Directory User](directory-users.md) feature.
-
-
-
-
-
-
-
-
-
diff --git a/docs/features/directory-users.md b/docs/features/directory-users.md
index e6b090f8..01b9b5aa 100644
--- a/docs/features/directory-users.md
+++ b/docs/features/directory-users.md
@@ -219,6 +219,9 @@ For each query, `type` can be used to tell mxisd how to process the ID column:
#### REST
See the [dedicated document](../backends/rest.md)
+#### Wordpress
+See the [dedicated document](../backends/wordpress.md)
+
## Next steps
### Homeserver results
You can configure if the Homeserver should be queried at all when doing a directory search.
diff --git a/docs/getting-started.md b/docs/getting-started.md
index bb799144..ecfe1982 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -143,3 +143,4 @@ Use your Identity stores:
- [SQL Database](backends/sql.md)
- [Website / Web service / Web app](backends/rest.md)
- [Google Firebase](backends/firebase.md)
+- [Wordpress](backends/wordpress.md)
diff --git a/src/main/java/io/kamax/mxisd/auth/provider/BackendAuthResult.java b/src/main/java/io/kamax/mxisd/auth/provider/BackendAuthResult.java
index be112f51..7c0bd0bd 100644
--- a/src/main/java/io/kamax/mxisd/auth/provider/BackendAuthResult.java
+++ b/src/main/java/io/kamax/mxisd/auth/provider/BackendAuthResult.java
@@ -66,7 +66,6 @@ public static BackendAuthResult success(String id, String type, String displayNa
public void succeed(String id, String type, String displayName) {
this.success = true;
this.id = new UserID(type, id);
- this.profile = new BackendAuthProfile();
this.profile.displayName = displayName;
}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthData.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthData.java
new file mode 100644
index 00000000..34c7733b
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthData.java
@@ -0,0 +1,62 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+public class WordpressAuthData {
+
+ public String token;
+ private String userEmail;
+ private String userNicename;
+ private String userDisplayName;
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+
+ public String getUserEmail() {
+ return userEmail;
+ }
+
+ public void setUserEmail(String userEmail) {
+ this.userEmail = userEmail;
+ }
+
+ public String getUserNicename() {
+ return userNicename;
+ }
+
+ public void setUserNicename(String userNicename) {
+ this.userNicename = userNicename;
+ }
+
+ public String getUserDisplayName() {
+ return userDisplayName;
+ }
+
+ public void setUserDisplayName(String userDisplayName) {
+ this.userDisplayName = userDisplayName;
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthProvider.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthProvider.java
new file mode 100644
index 00000000..2ea550d6
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressAuthProvider.java
@@ -0,0 +1,68 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+import io.kamax.matrix._MatrixID;
+import io.kamax.mxisd.ThreePid;
+import io.kamax.mxisd.UserIdType;
+import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
+import io.kamax.mxisd.auth.provider.BackendAuthResult;
+import org.apache.commons.lang.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+@Component
+public class WordpressAuthProvider implements AuthenticatorProvider {
+
+ private final Logger log = LoggerFactory.getLogger(WordpressAuthProvider.class);
+
+ private WordpressRestBackend wordpress;
+
+ @Autowired
+ public WordpressAuthProvider(WordpressRestBackend wordpress) {
+ this.wordpress = wordpress;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return wordpress.isEnabled();
+ }
+
+ @Override
+ public BackendAuthResult authenticate(_MatrixID mxid, String password) {
+ try {
+ WordpressAuthData data = wordpress.authenticate(mxid.getLocalPart(), password);
+ BackendAuthResult result = new BackendAuthResult();
+ if (StringUtils.isNotBlank(data.getUserEmail())) {
+ result.withThreePid(new ThreePid("email", data.getUserEmail()));
+ }
+ result.succeed(mxid.getId(), UserIdType.MatrixID.getId(), data.getUserDisplayName());
+ return result;
+ } catch (IllegalArgumentException e) {
+ log.error("Authentication failed for {}: {}", mxid.getId(), e.getMessage());
+ return BackendAuthResult.failure();
+ }
+
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressDirectoryProvider.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressDirectoryProvider.java
new file mode 100644
index 00000000..4caf77c1
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressDirectoryProvider.java
@@ -0,0 +1,112 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+import io.kamax.matrix.MatrixID;
+import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.wordpress.WordpressConfig;
+import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
+import io.kamax.mxisd.directory.IDirectoryProvider;
+import io.kamax.mxisd.exception.InternalServerError;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Optional;
+
+@Component
+public class WordpressDirectoryProvider implements IDirectoryProvider {
+
+ private final Logger log = LoggerFactory.getLogger(WordpressDirectoryProvider.class);
+
+ private WordpressConfig cfg;
+ private WordressSqlBackend wordpress;
+ private MatrixConfig mxCfg;
+
+ @Autowired
+ public WordpressDirectoryProvider(WordpressConfig cfg, WordressSqlBackend wordpress, MatrixConfig mxCfg) {
+ this.cfg = cfg;
+ this.wordpress = wordpress;
+ this.mxCfg = mxCfg;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return wordpress.isEnabled();
+ }
+
+ protected void setParameters(PreparedStatement stmt, String searchTerm) throws SQLException {
+ for (int i = 1; i <= stmt.getParameterMetaData().getParameterCount(); i++) {
+ stmt.setString(i, "%" + searchTerm + "%");
+ }
+ }
+
+ protected Optional processRow(ResultSet rSet) throws SQLException {
+ UserDirectorySearchResult.Result item = new UserDirectorySearchResult.Result();
+ item.setUserId(rSet.getString(1));
+ item.setDisplayName(rSet.getString(2));
+ return Optional.of(item);
+ }
+
+ public UserDirectorySearchResult search(String searchTerm, String query) {
+ try (Connection conn = wordpress.getConnection()) {
+ log.info("Will execute query: {}", query);
+ try (PreparedStatement stmt = conn.prepareStatement(query)) {
+ setParameters(stmt, searchTerm);
+
+ try (ResultSet rSet = stmt.executeQuery()) {
+ UserDirectorySearchResult result = new UserDirectorySearchResult();
+ result.setLimited(false);
+
+ while (rSet.next()) {
+ processRow(rSet).ifPresent(e -> {
+ e.setUserId(MatrixID.from(e.getUserId(), mxCfg.getDomain()).valid().getId());
+ result.addResult(e);
+ });
+ }
+
+ return result;
+ }
+ }
+ } catch (SQLException e) {
+ e.printStackTrace();
+ throw new InternalServerError(e);
+ }
+ }
+
+ @Override
+ public UserDirectorySearchResult searchByDisplayName(String searchTerm) {
+ log.info("Searching users by display name using '{}'", searchTerm);
+ return search(searchTerm, cfg.getSql().getQuery().getDirectory().get("name"));
+ }
+
+ @Override
+ public UserDirectorySearchResult searchBy3pid(String searchTerm) {
+ log.info("Searching users by 3PID using '{}'", searchTerm);
+ return search(searchTerm, cfg.getSql().getQuery().getDirectory().get("threepid"));
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressRestBackend.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressRestBackend.java
new file mode 100644
index 00000000..57c592d6
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressRestBackend.java
@@ -0,0 +1,143 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+import com.google.gson.JsonObject;
+import io.kamax.matrix.json.GsonUtil;
+import io.kamax.matrix.json.InvalidJsonException;
+import io.kamax.mxisd.config.wordpress.WordpressConfig;
+import io.kamax.mxisd.util.RestClientUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.client.methods.HttpRequestBase;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.util.EntityUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+
+@Component
+public class WordpressRestBackend {
+
+ private final Logger log = LoggerFactory.getLogger(WordpressRestBackend.class);
+ private final String jsonPath = "/wp-json";
+ private final String jwtPath = "/jwt-auth/v1";
+
+ private WordpressConfig cfg;
+ private CloseableHttpClient client;
+
+ private String jsonEndpoint;
+ private String jwtEndpoint;
+
+ private String token;
+
+ @Autowired
+ public WordpressRestBackend(WordpressConfig cfg, CloseableHttpClient client) {
+ this.cfg = cfg;
+ this.client = client;
+
+ if (!cfg.isEnabled()) {
+ return;
+ }
+
+ jsonEndpoint = cfg.getRest().getBase() + jsonPath;
+ jwtEndpoint = jsonEndpoint + jwtPath;
+ validateConfig();
+ }
+
+ private void validateConfig() {
+ log.info("Validating JWT auth endpoint");
+ try (CloseableHttpResponse res = client.execute(new HttpGet(jwtEndpoint))) {
+ int status = res.getStatusLine().getStatusCode();
+ if (status != 200) {
+ log.warn("JWT auth endpoint check failed: Got status code {}", status);
+ return;
+ }
+
+ String data = EntityUtils.toString(res.getEntity());
+ if (StringUtils.isBlank(data)) {
+ log.warn("JWT auth endpoint check failed: Got no/empty body data");
+ }
+
+ JsonObject body = GsonUtil.parseObj(data);
+ if (!body.has("namespace")) {
+ log.warn("JWT auth endpoint check failed: invalid namespace");
+ }
+
+ log.info("JWT auth endpoint check succeeded");
+ } catch (InvalidJsonException e) {
+ log.warn("JWT auth endpoint check failed: Invalid JSON response: {}", e.getMessage());
+ } catch (IOException e) {
+ log.warn("JWT auth endpoint check failed: Could not read API endpoint: {}", e.getMessage());
+ }
+ }
+
+ public boolean isEnabled() {
+ return cfg.isEnabled();
+ }
+
+ protected WordpressAuthData authenticate(String username, String password) {
+ JsonObject body = new JsonObject();
+ body.addProperty("username", username);
+ body.addProperty("password", password);
+ HttpPost req = RestClientUtils.post(jwtEndpoint + "/token", body);
+ try (CloseableHttpResponse res = client.execute(req)) {
+ int status = res.getStatusLine().getStatusCode();
+ String bodyRes = EntityUtils.toString(res.getEntity());
+ if (status != 200) {
+ throw new IllegalArgumentException(bodyRes);
+ }
+
+ return GsonUtil.get().fromJson(bodyRes, WordpressAuthData.class);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ protected void authenticate() {
+ WordpressAuthData data = authenticate(
+ cfg.getRest().getCredential().getUsername(),
+ cfg.getRest().getCredential().getPassword());
+ log.info("Internal authentication: success, logged in as " + data.getUserNicename());
+ token = data.getToken();
+ }
+
+ protected CloseableHttpResponse runRequest(HttpRequestBase request) throws IOException {
+ request.setHeader("Authorization", "Bearer " + token);
+ return client.execute(request);
+ }
+
+ public CloseableHttpResponse withAuthentication(HttpRequestBase request) throws IOException {
+ CloseableHttpResponse response = runRequest(request);
+ if (response.getStatusLine().getStatusCode() == 403) { //FIXME we should check the JWT expiration time
+ authenticate();
+ response = runRequest(request);
+ }
+
+ return response;
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressThreePidProvider.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressThreePidProvider.java
new file mode 100644
index 00000000..10cbfd6c
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordpressThreePidProvider.java
@@ -0,0 +1,114 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+import io.kamax.matrix.MatrixID;
+import io.kamax.matrix._MatrixID;
+import io.kamax.mxisd.ThreePid;
+import io.kamax.mxisd.config.MatrixConfig;
+import io.kamax.mxisd.config.wordpress.WordpressConfig;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+@Component
+public class WordpressThreePidProvider implements IThreePidProvider {
+
+ private final Logger log = LoggerFactory.getLogger(WordpressThreePidProvider.class);
+
+ private MatrixConfig mxCfg;
+ private WordpressConfig cfg;
+ private WordressSqlBackend wordpress;
+
+ @Autowired
+ public WordpressThreePidProvider(MatrixConfig mxCfg, WordpressConfig cfg, WordressSqlBackend wordpress) {
+ this.mxCfg = mxCfg;
+ this.cfg = cfg;
+ this.wordpress = wordpress;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return wordpress.isEnabled();
+ }
+
+ @Override
+ public boolean isLocal() {
+ return true;
+ }
+
+ @Override
+ public int getPriority() {
+ return 15;
+ }
+
+ protected Optional<_MatrixID> find(ThreePid tpid) {
+ String query = cfg.getSql().getQuery().getThreepid().get(tpid.getMedium());
+ if (Objects.isNull(query)) {
+ return Optional.empty();
+ }
+
+ try (Connection conn = wordpress.getConnection()) {
+ PreparedStatement stmt = conn.prepareStatement(query);
+ stmt.setString(1, tpid.getAddress());
+
+ try (ResultSet rSet = stmt.executeQuery()) {
+ while (rSet.next()) {
+ String uid = rSet.getString("uid");
+ log.info("Found match: {}", uid);
+ return Optional.of(MatrixID.from(uid, mxCfg.getDomain()).valid());
+ }
+
+ log.info("No match found in Wordpress");
+ return Optional.empty();
+ }
+ } catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public Optional find(SingleLookupRequest request) {
+ return find(new ThreePid(request.getType(), request.getThreePid())).map(mxid -> new SingleLookupReply(request, mxid));
+ }
+
+ @Override
+ public List populate(List mappings) {
+ for (ThreePidMapping tpidMap : mappings) {
+ find(new ThreePid(tpidMap.getMedium(), tpidMap.getValue())).ifPresent(mxid -> tpidMap.setMxid(mxid.getId()));
+ }
+ return mappings;
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/backend/wordpress/WordressSqlBackend.java b/src/main/java/io/kamax/mxisd/backend/wordpress/WordressSqlBackend.java
new file mode 100644
index 00000000..8ada21fa
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/backend/wordpress/WordressSqlBackend.java
@@ -0,0 +1,61 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.backend.wordpress;
+
+import com.mchange.v2.c3p0.ComboPooledDataSource;
+import io.kamax.mxisd.config.wordpress.WordpressConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+@Component
+public class WordressSqlBackend {
+
+ private Logger log = LoggerFactory.getLogger(WordressSqlBackend.class);
+
+ private WordpressConfig cfg;
+
+ private ComboPooledDataSource ds;
+
+ @Autowired
+ public WordressSqlBackend(WordpressConfig cfg) {
+ this.cfg = cfg;
+
+ ds = new ComboPooledDataSource();
+ ds.setJdbcUrl("jdbc:" + cfg.getSql().getType() + ":" + cfg.getSql().getConnection());
+ ds.setMinPoolSize(1);
+ ds.setMaxPoolSize(10);
+ ds.setAcquireIncrement(2);
+ }
+
+ public boolean isEnabled() {
+ return cfg.isEnabled();
+ }
+
+ public Connection getConnection() throws SQLException {
+ return ds.getConnection();
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/config/wordpress/WordpressConfig.java b/src/main/java/io/kamax/mxisd/config/wordpress/WordpressConfig.java
new file mode 100644
index 00000000..d4ce42ae
--- /dev/null
+++ b/src/main/java/io/kamax/mxisd/config/wordpress/WordpressConfig.java
@@ -0,0 +1,175 @@
+/*
+ * mxisd - Matrix Identity Server Daemon
+ * Copyright (C) 2018 Kamax Sàrl
+ *
+ * https://www.kamax.io/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package io.kamax.mxisd.config.wordpress;
+
+import io.kamax.mxisd.exception.ConfigurationException;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+import java.util.Map;
+
+@Configuration
+@ConfigurationProperties("wordpress")
+public class WordpressConfig {
+
+ public static class Credential {
+
+ private String username;
+ private String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ }
+
+ public static class Rest {
+
+ private Credential credential = new Credential();
+ private String base;
+
+ public String getBase() {
+ return base;
+ }
+
+ public void setBase(String base) {
+ this.base = base;
+ }
+
+ public Credential getCredential() {
+ return credential;
+ }
+
+ public void setCredential(Credential credential) {
+ this.credential = credential;
+ }
+
+ }
+
+ public static class Query {
+
+ private Map threepid;
+ private Map directory;
+
+ public Map getThreepid() {
+ return threepid;
+ }
+
+ public void setThreepid(Map threepid) {
+ this.threepid = threepid;
+ }
+
+ public Map getDirectory() {
+ return directory;
+ }
+
+ public void setDirectory(Map directory) {
+ this.directory = directory;
+ }
+
+ }
+
+ public static class Sql {
+
+ private String type;
+ private String connection;
+ private Query query;
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getConnection() {
+ return connection;
+ }
+
+ public void setConnection(String connection) {
+ this.connection = connection;
+ }
+
+ public Query getQuery() {
+ return query;
+ }
+
+ public void setQuery(Query query) {
+ this.query = query;
+ }
+
+ }
+
+ private boolean enabled;
+ private Rest rest = new Rest();
+ private Sql sql = new Sql();
+
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ public void setEnabled(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ public Rest getRest() {
+ return rest;
+ }
+
+ public void setRest(Rest rest) {
+ this.rest = rest;
+ }
+
+ public Sql getSql() {
+ return sql;
+ }
+
+ public void setSql(Sql sql) {
+ this.sql = sql;
+ }
+
+ @PostConstruct
+ public void build() {
+ if (!isEnabled()) {
+ return;
+ }
+
+ if (StringUtils.isBlank(getRest().getBase())) {
+ throw new ConfigurationException("wordpress.rest.base");
+ }
+ }
+
+}
diff --git a/src/main/java/io/kamax/mxisd/util/RestClientUtils.java b/src/main/java/io/kamax/mxisd/util/RestClientUtils.java
index 1c23a83b..2b1e42a9 100644
--- a/src/main/java/io/kamax/mxisd/util/RestClientUtils.java
+++ b/src/main/java/io/kamax/mxisd/util/RestClientUtils.java
@@ -20,9 +20,7 @@
package io.kamax.mxisd.util;
-import com.google.gson.FieldNamingPolicy;
import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
@@ -31,7 +29,7 @@
public class RestClientUtils {
- private static Gson gson = new GsonBuilder().setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES).create();
+ private static Gson gson = GsonUtil.build();
public static HttpPost post(String url, String body) {
StringEntity entity = new StringEntity(body, StandardCharsets.UTF_8);
diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml
index 4168fef4..9ecc5cc7 100644
--- a/src/main/resources/application.yaml
+++ b/src/main/resources/application.yaml
@@ -156,6 +156,17 @@ synapseSql:
enabled: false
type: 'sqlite'
+wordpress:
+ enabled: false
+ sql:
+ type: 'mysql'
+ query:
+ threepid:
+ email: 'SELECT user_login as uid FROM wp_users WHERE user_email = ?'
+ directory:
+ name: "SELECT DISTINCT user_login, display_name FROM wp_users u LEFT JOIN wp_usermeta m ON m.user_id = u.id WHERE u.display_name LIKE ? OR (m.meta_key = 'nickname' AND m.meta_value = ?) OR (m.meta_key = 'first_name' AND m.meta_value = ?) OR (m.meta_key = 'last_name' AND m.meta_value = ?);"
+ threepid: 'SELECT DISTINCT user_login, display_name FROM wp_users WHERE user_email LIKE ?'
+
forward:
servers:
- 'https://matrix.org'