Skip to content

Commit

Permalink
Wordpress identity store (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
Max Dor authored Mar 23, 2018
1 parent d93b546 commit 3fc8646
Show file tree
Hide file tree
Showing 17 changed files with 813 additions and 15 deletions.
3 changes: 3 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion docs/backends/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
- [Google Firebase](firebase.md)
- [Wordpress](wordpress.md)
55 changes: 55 additions & 0 deletions docs/backends/wordpress.md
Original file line number Diff line number Diff line change
@@ -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`
11 changes: 1 addition & 10 deletions docs/features/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,8 @@ Steps of user authentication using a 3PID:
- Homeserver
- Compatible Identity backends:
- LDAP
- SQL
- REST
- Wordpress

### Configuration

Expand Down Expand Up @@ -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.









3 changes: 3 additions & 0 deletions docs/features/directory-users.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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;
}

}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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();
}

}

}
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.
*/

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<UserDirectorySearchResult.Result> 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"));
}

}
Loading

0 comments on commit 3fc8646

Please sign in to comment.