Compare commits

..

8 Commits

Author SHA1 Message Date
Max Dor
a0f8af820e Fix minor regression with Auth feature and REST/Memory backend
See https://matrix.to/#/!NPRUEisLjcaMtHIzDr:kamax.io/$1523216730848820dFUZX:matrix.org
2018-04-08 22:05:36 +02:00
Max Dor
5ef145212a Support access tokens in headers (Fix #65) (#70) 2018-04-02 17:26:03 +02:00
Max Dor
91ccb75fa1 Properly handle invalid characters in identifiers for Wordpress 2018-04-02 14:36:23 +02:00
Max Dor
ac6f549618 Support 3PID in memory identity store profile 2018-03-30 18:31:22 +02:00
Max Dor
7f9c7aa76d Fix Synapse SQL directory provider class name 2018-03-25 23:19:45 +02:00
Max Dor
02688942fd Enforce host present in DNS override config to avoid request loop 2018-03-25 19:31:52 +02:00
Max Dor
48668bcd92 Support of Directory for in-memory Identity store 2018-03-25 19:30:42 +02:00
Max Dor
a9627121fa Enchanced profile management (#68)
* Proof of concept of adding 3PIDs data to user profile
* Document reverse proxy apache config
* Support for Matrix Gateway project roles' endpoint
* Fix conflicting ThreePid object defined in SDK and mxisd projects
2018-03-25 01:20:59 +01:00
50 changed files with 623 additions and 151 deletions

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

@@ -0,0 +1,12 @@
# Profile enhancement
## Configuration
### Reverse proxy
#### Apache
```
ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)$" "http://127.0.0.1:8090/_matrix/client/r0/profile/$1"
ProxyPassMatch "^/_matrix/client/r0/profile/([^/]+)/(.+)" "http://127.0.0.1:8008/_matrix/client/r0/profile/$1/$2"
```

View File

@@ -1,69 +0,0 @@
/*
* mxisd - Matrix Identity Server Daemon
* Copyright (C) 2017 Maxime Dor
*
* https://max.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;
// FIXME this should be in matrix-java-sdk
public class ThreePid {
private String medium;
private String address;
public ThreePid(ThreePid tpid) {
this(tpid.getMedium(), tpid.getAddress());
}
public ThreePid(String medium, String address) {
this.medium = medium;
this.address = address;
}
public String getMedium() {
return medium;
}
public String getAddress() {
return address;
}
@Override
public String toString() {
return getMedium() + ":" + getAddress();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ThreePid threePid = (ThreePid) o;
if (!medium.equals(threePid.medium)) return false;
return address.equals(threePid.address);
}
@Override
public int hashCode() {
int result = medium.hashCode();
result = 31 * result + address.hashCode();
return result;
}
}

View File

@@ -21,8 +21,9 @@
package io.kamax.mxisd.auth; package io.kamax.mxisd.auth;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix._ThreePid;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
@@ -72,7 +73,7 @@ public class AuthManager {
} }
UserAuthResult authResult = new UserAuthResult().success(result.getProfile().getDisplayName()); UserAuthResult authResult = new UserAuthResult().success(result.getProfile().getDisplayName());
for (ThreePid pid : result.getProfile().getThreePids()) { for (_ThreePid pid : result.getProfile().getThreePids()) {
authResult.withThreePid(pid.getMedium(), pid.getAddress()); authResult.withThreePid(pid.getMedium(), pid.getAddress());
} }
log.info("{} was authenticated by {}, publishing 3PID mappings, if any", id, provider.getClass().getSimpleName()); log.info("{} was authenticated by {}, publishing 3PID mappings, if any", id, provider.getClass().getSimpleName());

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.auth; package io.kamax.mxisd.auth;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.auth.provider; package io.kamax.mxisd.auth.provider;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.UserID; import io.kamax.mxisd.UserID;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;

View File

@@ -23,9 +23,9 @@ package io.kamax.mxisd.backend.firebase;
import com.google.firebase.auth.UserInfo; import com.google.firebase.auth.UserInfo;
import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.PhoneNumberUtil;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.ThreePid;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;

View File

@@ -22,9 +22,9 @@ package io.kamax.mxisd.backend.ldap;
import com.google.i18n.phonenumbers.NumberParseException; import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.PhoneNumberUtil;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.ThreePid;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;

View File

@@ -23,6 +23,7 @@ package io.kamax.mxisd.backend.memory;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;
@@ -30,22 +31,28 @@ import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.memory.MemoryIdentityConfig; import io.kamax.mxisd.config.memory.MemoryIdentityConfig;
import io.kamax.mxisd.config.memory.MemoryStoreConfig; import io.kamax.mxisd.config.memory.MemoryStoreConfig;
import io.kamax.mxisd.config.memory.MemoryThreePid; import io.kamax.mxisd.config.memory.MemoryThreePid;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
import io.kamax.mxisd.directory.IDirectoryProvider;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider; import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.function.Function;
import java.util.function.Predicate;
@Component @Component
public class MemoryIdentityStore implements AuthenticatorProvider, IThreePidProvider { public class MemoryIdentityStore implements AuthenticatorProvider, IDirectoryProvider, IThreePidProvider, ProfileProvider {
private final Logger logger = LoggerFactory.getLogger(MemoryIdentityStore.class); private final Logger logger = LoggerFactory.getLogger(MemoryIdentityStore.class);
@@ -59,7 +66,9 @@ public class MemoryIdentityStore implements AuthenticatorProvider, IThreePidProv
} }
public Optional<MemoryIdentityConfig> findByUsername(String username) { public Optional<MemoryIdentityConfig> findByUsername(String username) {
return cfg.getIdentities().stream().filter(id -> StringUtils.equals(id.getUsername(), username)).findFirst(); return cfg.getIdentities().stream()
.filter(id -> StringUtils.equals(id.getUsername(), username))
.findFirst();
} }
@Override @Override
@@ -67,6 +76,56 @@ public class MemoryIdentityStore implements AuthenticatorProvider, IThreePidProv
return cfg.isEnabled(); return cfg.isEnabled();
} }
private UserDirectorySearchResult search(
Predicate<MemoryIdentityConfig> predicate,
Function<MemoryIdentityConfig, UserDirectorySearchResult.Result> mapper
) {
UserDirectorySearchResult search = new UserDirectorySearchResult();
cfg.getIdentities().stream().filter(predicate).map(mapper).forEach(search::addResult);
return search;
}
@Override
public UserDirectorySearchResult searchByDisplayName(String query) {
return search(
entry -> StringUtils.containsIgnoreCase(entry.getUsername(), query),
entry -> {
UserDirectorySearchResult.Result result = new UserDirectorySearchResult.Result();
result.setUserId(MatrixID.from(entry.getUsername(), mxCfg.getDomain()).acceptable().getId());
result.setDisplayName(entry.getUsername());
return result;
}
);
}
@Override
public UserDirectorySearchResult searchBy3pid(String query) {
return search(
entry -> entry.getThreepids().stream()
.anyMatch(tpid -> StringUtils.containsIgnoreCase(tpid.getAddress(), query)),
entry -> {
UserDirectorySearchResult.Result result = new UserDirectorySearchResult.Result();
result.setUserId(MatrixID.from(entry.getUsername(), mxCfg.getDomain()).acceptable().getId());
result.setDisplayName(entry.getUsername());
return result;
}
);
}
@Override
public List<_ThreePid> getThreepids(_MatrixID mxid) {
List<_ThreePid> l = new ArrayList<>();
findByUsername(mxid.getLocalPart()).ifPresent(c -> l.addAll(c.getThreepids()));
return l;
}
@Override
public List<String> getRoles(_MatrixID mxid) {
List<String> l = new ArrayList<>();
findByUsername(mxid.getLocalPart()).ifPresent(c -> l.addAll(c.getRoles()));
return l;
}
@Override @Override
public boolean isLocal() { public boolean isLocal() {
return true; return true;
@@ -103,7 +162,10 @@ public class MemoryIdentityStore implements AuthenticatorProvider, IThreePidProv
if (!StringUtils.equals(id.getUsername(), mxid.getLocalPart())) { if (!StringUtils.equals(id.getUsername(), mxid.getLocalPart())) {
return BackendAuthResult.failure(); return BackendAuthResult.failure();
} else { } else {
return BackendAuthResult.success(mxid.getId(), UserIdType.MatrixID, ""); BackendAuthResult result = new BackendAuthResult();
id.getThreepids().forEach(tpid -> result.withThreePid(new ThreePid(tpid.getMedium(), tpid.getAddress())));
result.succeed(mxid.getId(), UserIdType.MatrixID.getId(), "");
return result;
} }
}).orElseGet(BackendAuthResult::failure); }).orElseGet(BackendAuthResult::failure);
} }

View File

@@ -21,12 +21,16 @@
package io.kamax.mxisd.backend.sql; package io.kamax.mxisd.backend.sql;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.sql.SqlConfig; import io.kamax.mxisd.config.sql.SqlConfig;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
import io.kamax.mxisd.lookup.SingleLookupRequest; import io.kamax.mxisd.lookup.SingleLookupRequest;
import io.kamax.mxisd.lookup.ThreePidMapping; import io.kamax.mxisd.lookup.ThreePidMapping;
import io.kamax.mxisd.lookup.provider.IThreePidProvider; import io.kamax.mxisd.lookup.provider.IThreePidProvider;
import io.kamax.mxisd.profile.ProfileProvider;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -36,10 +40,11 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
public abstract class SqlThreePidProvider implements IThreePidProvider { public abstract class SqlThreePidProvider implements IThreePidProvider, ProfileProvider {
private Logger log = LoggerFactory.getLogger(SqlThreePidProvider.class); private Logger log = LoggerFactory.getLogger(SqlThreePidProvider.class);
@@ -109,4 +114,31 @@ public abstract class SqlThreePidProvider implements IThreePidProvider {
return new ArrayList<>(); return new ArrayList<>();
} }
@Override
public List<_ThreePid> getThreepids(_MatrixID mxid) {
List<_ThreePid> threepids = new ArrayList<>();
String stmtSql = cfg.getProfile().getThreepid().getQuery();
try (Connection conn = pool.get()) {
PreparedStatement stmt = conn.prepareStatement(stmtSql);
stmt.setString(1, mxid.getId());
ResultSet rSet = stmt.executeQuery();
while (rSet.next()) {
String medium = rSet.getString("medium");
String address = rSet.getString("address");
threepids.add(new ThreePid(medium, address));
}
return threepids;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
@Override
public List<String> getRoles(_MatrixID mxid) {
return Collections.emptyList();
}
} }

View File

@@ -32,10 +32,10 @@ import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
@Component @Component
public class SynapseSqliteDirectoryProvider extends GenericSqlDirectoryProvider { public class SynapseSqlDirectoryProvider extends GenericSqlDirectoryProvider {
@Autowired @Autowired
public SynapseSqliteDirectoryProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) { public SynapseSqlDirectoryProvider(SynapseSqlProviderConfig cfg, MatrixConfig mxCfg) {
super(cfg, mxCfg); super(cfg, mxCfg);
if (StringUtils.equals("sqlite", cfg.getType())) { if (StringUtils.equals("sqlite", cfg.getType())) {

View File

@@ -20,8 +20,8 @@
package io.kamax.mxisd.backend.wordpress; package io.kamax.mxisd.backend.wordpress;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix._MatrixID; import io.kamax.matrix._MatrixID;
import io.kamax.mxisd.ThreePid;
import io.kamax.mxisd.UserIdType; import io.kamax.mxisd.UserIdType;
import io.kamax.mxisd.auth.provider.AuthenticatorProvider; import io.kamax.mxisd.auth.provider.AuthenticatorProvider;
import io.kamax.mxisd.auth.provider.BackendAuthResult; import io.kamax.mxisd.auth.provider.BackendAuthResult;

View File

@@ -83,8 +83,12 @@ public class WordpressDirectoryProvider implements IDirectoryProvider {
while (rSet.next()) { while (rSet.next()) {
processRow(rSet).ifPresent(e -> { processRow(rSet).ifPresent(e -> {
try {
e.setUserId(MatrixID.from(e.getUserId(), mxCfg.getDomain()).valid().getId()); e.setUserId(MatrixID.from(e.getUserId(), mxCfg.getDomain()).valid().getId());
result.addResult(e); result.addResult(e);
} catch (IllegalArgumentException ex) {
log.warn("Ignoring result {} - Invalid characters for a Matrix ID", e.getUserId());
}
}); });
} }

View File

@@ -21,8 +21,8 @@
package io.kamax.mxisd.backend.wordpress; package io.kamax.mxisd.backend.wordpress;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid;
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.MatrixConfig;
import io.kamax.mxisd.config.wordpress.WordpressConfig; import io.kamax.mxisd.config.wordpress.WordpressConfig;
import io.kamax.mxisd.lookup.SingleLookupReply; import io.kamax.mxisd.lookup.SingleLookupReply;
@@ -87,10 +87,14 @@ public class WordpressThreePidProvider implements IThreePidProvider {
while (rSet.next()) { while (rSet.next()) {
String uid = rSet.getString("uid"); String uid = rSet.getString("uid");
log.info("Found match: {}", uid); log.info("Found match: {}", uid);
try {
return Optional.of(MatrixID.from(uid, mxCfg.getDomain()).valid()); return Optional.of(MatrixID.from(uid, mxCfg.getDomain()).valid());
} catch (IllegalArgumentException ex) {
log.warn("Ignoring match {} - Invalid characters for a Matrix ID", uid);
}
} }
log.info("No match found in Wordpress"); log.info("No valid match found in Wordpress");
return Optional.empty(); return Optional.empty();
} }
} catch (SQLException e) { } catch (SQLException e) {

View File

@@ -31,6 +31,7 @@ public class MemoryIdentityConfig {
private String username; private String username;
private String password; private String password;
private List<MemoryThreePid> threepids = new ArrayList<>(); private List<MemoryThreePid> threepids = new ArrayList<>();
private List<String> roles = new ArrayList<>();
public String getUsername() { public String getUsername() {
return username; return username;
@@ -56,4 +57,12 @@ public class MemoryIdentityConfig {
this.threepids = threepids; this.threepids = threepids;
} }
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
} }

View File

@@ -20,14 +20,16 @@
package io.kamax.mxisd.config.memory; package io.kamax.mxisd.config.memory;
import io.kamax.matrix._ThreePid;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@Component @Component
public class MemoryThreePid { public class MemoryThreePid implements _ThreePid {
private String medium; private String medium;
private String address; private String address;
@Override
public String getMedium() { public String getMedium() {
return medium; return medium;
} }
@@ -36,6 +38,7 @@ public class MemoryThreePid {
this.medium = medium; this.medium = medium;
} }
@Override
public String getAddress() { public String getAddress() {
return address; return address;
} }

View File

@@ -37,22 +37,22 @@ public abstract class SqlConfig {
public static class Type { public static class Type {
private GenericSqlProviderConfig.Query name = new GenericSqlProviderConfig.Query(); private Query name = new Query();
private GenericSqlProviderConfig.Query threepid = new GenericSqlProviderConfig.Query(); private Query threepid = new Query();
public GenericSqlProviderConfig.Query getName() { public Query getName() {
return name; return name;
} }
public void setName(GenericSqlProviderConfig.Query name) { public void setName(Query name) {
this.name = name; this.name = name;
} }
public GenericSqlProviderConfig.Query getThreepid() { public Query getThreepid() {
return threepid; return threepid;
} }
public void setThreepid(GenericSqlProviderConfig.Query threepid) { public void setThreepid(Query threepid) {
this.threepid = threepid; this.threepid = threepid;
} }
@@ -75,7 +75,7 @@ public abstract class SqlConfig {
public static class Directory { public static class Directory {
private Boolean enabled; private Boolean enabled;
private GenericSqlProviderConfig.Type query = new GenericSqlProviderConfig.Type(); private Type query = new Type();
public Boolean isEnabled() { public Boolean isEnabled() {
return enabled; return enabled;
@@ -85,11 +85,11 @@ public abstract class SqlConfig {
this.enabled = enabled; this.enabled = enabled;
} }
public GenericSqlProviderConfig.Type getQuery() { public Type getQuery() {
return query; return query;
} }
public void setQuery(GenericSqlProviderConfig.Type query) { public void setQuery(Type query) {
this.query = query; this.query = query;
} }
@@ -136,12 +136,41 @@ public abstract class SqlConfig {
} }
public static class ProfileThreepids {
private String query;
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
}
public static class Profile {
private ProfileThreepids threepid = new ProfileThreepids();
public ProfileThreepids getThreepid() {
return threepid;
}
public void setThreepid(ProfileThreepids threepid) {
this.threepid = threepid;
}
}
private boolean enabled; private boolean enabled;
private String type; private String type;
private String connection; private String connection;
private GenericSqlProviderConfig.Auth auth = new GenericSqlProviderConfig.Auth(); private Auth auth = new Auth();
private GenericSqlProviderConfig.Directory directory = new GenericSqlProviderConfig.Directory(); private Directory directory = new Directory();
private GenericSqlProviderConfig.Identity identity = new GenericSqlProviderConfig.Identity(); private Identity identity = new Identity();
private Profile profile = new Profile();
public boolean isEnabled() { public boolean isEnabled() {
return enabled; return enabled;
@@ -167,30 +196,38 @@ public abstract class SqlConfig {
this.connection = connection; this.connection = connection;
} }
public GenericSqlProviderConfig.Auth getAuth() { public Auth getAuth() {
return auth; return auth;
} }
public void setAuth(GenericSqlProviderConfig.Auth auth) { public void setAuth(Auth auth) {
this.auth = auth; this.auth = auth;
} }
public GenericSqlProviderConfig.Directory getDirectory() { public Directory getDirectory() {
return directory; return directory;
} }
public void setDirectory(GenericSqlProviderConfig.Directory directory) { public void setDirectory(Directory directory) {
this.directory = directory; this.directory = directory;
} }
public GenericSqlProviderConfig.Identity getIdentity() { public Identity getIdentity() {
return identity; return identity;
} }
public void setIdentity(GenericSqlProviderConfig.Identity identity) { public void setIdentity(Identity identity) {
this.identity = identity; this.identity = identity;
} }
public Profile getProfile() {
return profile;
}
public void setProfile(Profile profile) {
this.profile = profile;
}
protected abstract String getProviderName(); protected abstract String getProviderName();
protected void doBuild() { protected void doBuild() {
@@ -222,6 +259,7 @@ public abstract class SqlConfig {
log.info("Identity type: {}", getIdentity().getType()); log.info("Identity type: {}", getIdentity().getType());
log.info("3PID mapping query: {}", getIdentity().getQuery()); log.info("3PID mapping query: {}", getIdentity().getQuery());
log.info("Identity medium queries: {}", GsonUtil.build().toJson(getIdentity().getMedium())); log.info("Identity medium queries: {}", GsonUtil.build().toJson(getIdentity().getMedium()));
log.info("Profile 3PID query: {}", getProfile().getThreepid().getQuery());
} }
} }

View File

@@ -84,8 +84,8 @@ public class DefaultExceptionHandler {
return handleGeneric(request, response, e); return handleGeneric(request, response, e);
} }
@ExceptionHandler(MatrixException.class) @ExceptionHandler(HttpMatrixException.class)
public String handleGeneric(HttpServletRequest request, HttpServletResponse response, MatrixException e) { public String handleGeneric(HttpServletRequest request, HttpServletResponse response, HttpMatrixException e) {
response.setStatus(e.getStatus()); response.setStatus(e.getStatus());
return handle(request, e.getErrorCode(), e.getError()); return handle(request, e.getErrorCode(), e.getError());
} }

View File

@@ -0,0 +1,54 @@
/*
* 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.controller;
import io.kamax.mxisd.exception.AccessTokenNotFoundException;
import io.kamax.mxisd.util.OptionalUtil;
import org.thymeleaf.util.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.util.Optional;
public class ProxyController {
private final static String headerName = "Authorization";
private final static String headerValuePrefix = "Bearer ";
private final static String parameterName = "access_token";
Optional<String> findAccessTokenInHeaders(HttpServletRequest request) {
return Optional.ofNullable(request.getHeader(headerName))
.filter(header -> StringUtils.startsWith(header, headerValuePrefix))
.map(header -> header.substring(headerValuePrefix.length()));
}
Optional<String> findAccessTokenInQuery(HttpServletRequest request) {
return Optional.ofNullable(request.getParameter(parameterName));
}
public Optional<String> findAccessToken(HttpServletRequest request) {
return OptionalUtil.findFirst(() -> findAccessTokenInHeaders(request), () -> findAccessTokenInQuery(request));
}
public String getAccessToken(HttpServletRequest request) {
return findAccessToken(request).orElseThrow(AccessTokenNotFoundException::new);
}
}

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.controller.auth.v1.io; package io.kamax.mxisd.controller.auth.v1.io;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;

View File

@@ -21,6 +21,7 @@
package io.kamax.mxisd.controller.directory.v1; package io.kamax.mxisd.controller.directory.v1;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.kamax.mxisd.controller.ProxyController;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest; import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
import io.kamax.mxisd.directory.DirectoryManager; import io.kamax.mxisd.directory.DirectoryManager;
@@ -28,7 +29,10 @@ import io.kamax.mxisd.util.GsonParser;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.io.IOException; import java.io.IOException;
@@ -37,7 +41,7 @@ import java.net.URI;
@RestController @RestController
@CrossOrigin @CrossOrigin
@RequestMapping(path = "/_matrix/client/r0/user_directory", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) @RequestMapping(path = "/_matrix/client/r0/user_directory", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class UserDirectoryController { public class UserDirectoryController extends ProxyController {
private Gson gson = GsonUtil.build(); private Gson gson = GsonUtil.build();
private GsonParser parser = new GsonParser(gson); private GsonParser parser = new GsonParser(gson);
@@ -46,7 +50,8 @@ public class UserDirectoryController {
private DirectoryManager mgr; private DirectoryManager mgr;
@RequestMapping(path = "/search", method = RequestMethod.POST) @RequestMapping(path = "/search", method = RequestMethod.POST)
public String search(HttpServletRequest request, @RequestParam("access_token") String accessToken) throws IOException { public String search(HttpServletRequest request) throws IOException {
String accessToken = getAccessToken(request);
UserDirectorySearchRequest searchQuery = parser.parse(request, UserDirectorySearchRequest.class); UserDirectorySearchRequest searchQuery = parser.parse(request, UserDirectorySearchRequest.class);
URI target = URI.create(request.getRequestURL().toString()); URI target = URI.create(request.getRequestURL().toString());
UserDirectorySearchResult result = mgr.search(target, accessToken, searchQuery.getSearchTerm()); UserDirectorySearchResult result = mgr.search(target, accessToken, searchQuery.getSearchTerm());

View File

@@ -22,8 +22,8 @@ package io.kamax.mxisd.controller.identity.v1;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
import io.kamax.mxisd.ThreePid;
import io.kamax.mxisd.config.ServerConfig; import io.kamax.mxisd.config.ServerConfig;
import io.kamax.mxisd.config.ViewConfig; import io.kamax.mxisd.config.ViewConfig;
import io.kamax.mxisd.controller.identity.v1.io.SessionEmailTokenRequestJson; import io.kamax.mxisd.controller.identity.v1.io.SessionEmailTokenRequestJson;

View File

@@ -0,0 +1,105 @@
/*
* 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.controller.profile.v1;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix._ThreePid;
import io.kamax.mxisd.controller.ProxyController;
import io.kamax.mxisd.dns.ClientDnsOverwrite;
import io.kamax.mxisd.profile.ProfileManager;
import io.kamax.mxisd.util.GsonUtil;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
@RestController
@CrossOrigin
@RequestMapping(path = "/_matrix/client/r0/profile", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class ProfileController extends ProxyController {
private final Logger log = LoggerFactory.getLogger(ProfileController.class);
private final ProfileManager mgr;
private final CloseableHttpClient client;
private final ClientDnsOverwrite dns;
private final JsonParser parser;
private final Gson gson;
@Autowired
public ProfileController(ProfileManager mgr, CloseableHttpClient client, ClientDnsOverwrite dns) {
this.mgr = mgr;
this.client = client;
this.dns = dns;
this.parser = new JsonParser();
this.gson = GsonUtil.build();
}
// FIXME do properly in the SDK (headers, check access token, etc.)
private String resolveProxyUrl(HttpServletRequest req) {
URI target = URI.create(req.getRequestURL().toString() + (Objects.isNull(req.getQueryString()) ? "" : "?" + req.getQueryString()));
URIBuilder builder = dns.transform(target);
String urlToLogin = builder.toString();
log.info("Proxy resolution: {} to {}", target.toString(), urlToLogin);
return urlToLogin;
}
@RequestMapping("/{userId:.+}")
public String getProfile(HttpServletRequest req, HttpServletResponse res, @PathVariable String userId) {
Optional<String> accessTokenOpt = findAccessToken(req);
HttpGet reqOut = new HttpGet(resolveProxyUrl(req));
accessTokenOpt.ifPresent(accessToken -> reqOut.addHeader("Authorization", "Bearer " + accessToken));
try (CloseableHttpResponse hsResponse = client.execute(reqOut)) {
res.setStatus(hsResponse.getStatusLine().getStatusCode());
JsonElement el = parser.parse(EntityUtils.toString(hsResponse.getEntity()));
List<_ThreePid> list = mgr.getThreepids(MatrixID.asAcceptable(userId));
if (!list.isEmpty() && el.isJsonObject()) {
JsonObject obj = el.getAsJsonObject();
obj.add("threepids", GsonUtil.build().toJsonTree(list));
}
return gson.toJson(el);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,58 @@
/*
* 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.controller.profile.v1;
import io.kamax.matrix.MatrixID;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix.json.GsonUtil;
import io.kamax.mxisd.profile.ProfileManager;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
@RestController
@CrossOrigin
@RequestMapping(produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public class ProfileInternalController {
private final ProfileManager mgr;
public ProfileInternalController(ProfileManager mgr) {
this.mgr = mgr;
}
@RequestMapping(method = GET, path = "/_matrix-internal/profile/v1/{userId:.+}")
public String getProfile(@PathVariable String userId) throws UnsupportedEncodingException {
userId = URLDecoder.decode(userId, StandardCharsets.UTF_8.name());
_MatrixID mxId = MatrixID.asAcceptable(userId);
return GsonUtil.get().toJson(GsonUtil.makeObj("roles", GsonUtil.asArray(mgr.getRoles(mxId))));
}
}

View File

@@ -27,8 +27,8 @@ import io.kamax.mxisd.config.DirectoryConfig;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest; import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult; import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
import io.kamax.mxisd.dns.ClientDnsOverwrite; import io.kamax.mxisd.dns.ClientDnsOverwrite;
import io.kamax.mxisd.exception.HttpMatrixException;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.exception.MatrixException;
import io.kamax.mxisd.util.GsonUtil; import io.kamax.mxisd.util.GsonUtil;
import io.kamax.mxisd.util.RestClientUtils; import io.kamax.mxisd.util.RestClientUtils;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
@@ -99,7 +99,7 @@ public class DirectoryManager {
log.warn("Homeserver does not support Directory feature, skipping"); log.warn("Homeserver does not support Directory feature, skipping");
} else { } else {
log.error("Homeserver returned an error while performing directory search"); log.error("Homeserver returned an error while performing directory search");
throw new MatrixException(status, info.getErrcode(), info.getError()); throw new HttpMatrixException(status, info.getErrcode(), info.getError());
} }
} }

View File

@@ -22,6 +22,7 @@ package io.kamax.mxisd.dns;
import io.kamax.mxisd.config.DnsOverwriteConfig; import io.kamax.mxisd.config.DnsOverwriteConfig;
import io.kamax.mxisd.exception.ConfigurationException; import io.kamax.mxisd.exception.ConfigurationException;
import io.kamax.mxisd.exception.InternalServerError;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -53,7 +54,7 @@ public class ClientDnsOverwrite {
URIBuilder builder = new URIBuilder(initial); URIBuilder builder = new URIBuilder(initial);
Entry mapping = mappings.get(initial.getHost()); Entry mapping = mappings.get(initial.getHost());
if (mapping == null) { if (mapping == null) {
return builder; throw new InternalServerError("No DNS client override for " + initial.getHost());
} }
try { try {

View File

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

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class FeatureNotAvailable extends MatrixException { public class FeatureNotAvailable extends HttpMatrixException {
private String internalReason; private String internalReason;

View File

@@ -20,28 +20,19 @@
package io.kamax.mxisd.exception; package io.kamax.mxisd.exception;
public class MatrixException extends MxisdException { import io.kamax.matrix.MatrixException;
public class HttpMatrixException extends MatrixException {
private int status; private int status;
private String errorCode;
private String error;
public MatrixException(int status, String errorCode, String error) { public HttpMatrixException(int status, String errorCode, String error) {
super(errorCode, error);
this.status = status; this.status = status;
this.errorCode = errorCode;
this.error = error;
} }
public int getStatus() { public int getStatus() {
return status; return status;
} }
public String getErrorCode() {
return errorCode;
}
public String getError() {
return error;
}
} }

View File

@@ -24,7 +24,7 @@ import org.apache.http.HttpStatus;
import java.time.Instant; import java.time.Instant;
public class InternalServerError extends MatrixException { public class InternalServerError extends HttpMatrixException {
private String reference = Long.toString(Instant.now().toEpochMilli()); private String reference = Long.toString(Instant.now().toEpochMilli());
private String internalReason; private String internalReason;

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class MessageForClientException extends MatrixException { public class MessageForClientException extends HttpMatrixException {
public MessageForClientException(String error) { public MessageForClientException(String error) {
super(HttpStatus.SC_OK, "M_MESSAGE_FOR_CLIENT", error); super(HttpStatus.SC_OK, "M_MESSAGE_FOR_CLIENT", error);

View File

@@ -23,7 +23,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class NotAllowedException extends MatrixException { public class NotAllowedException extends HttpMatrixException {
public NotAllowedException(String s) { public NotAllowedException(String s) {
super(HttpStatus.SC_FORBIDDEN, "M_FORBIDDEN", s); super(HttpStatus.SC_FORBIDDEN, "M_FORBIDDEN", s);

View File

@@ -2,7 +2,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class RemoteHomeServerException extends MatrixException { public class RemoteHomeServerException extends HttpMatrixException {
public RemoteHomeServerException(String error) { public RemoteHomeServerException(String error) {
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_HS_ERROR", "Error from remote server: " + error); super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_HS_ERROR", "Error from remote server: " + error);

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class RemoteIdentityServerException extends MatrixException { public class RemoteIdentityServerException extends HttpMatrixException {
public RemoteIdentityServerException(String error) { public RemoteIdentityServerException(String error) {
super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_IS_ERROR", "Error from remote server: " + error); super(HttpStatus.SC_SERVICE_UNAVAILABLE, "M_REMOTE_IS_ERROR", "Error from remote server: " + error);

View File

@@ -23,7 +23,7 @@ package io.kamax.mxisd.exception;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
public class RemoteLoginException extends MatrixException { public class RemoteLoginException extends HttpMatrixException {
private JsonObject errorBodyMsgResp; private JsonObject errorBodyMsgResp;

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.exception;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
public class SessionNotValidatedException extends MatrixException { public class SessionNotValidatedException extends HttpMatrixException {
public SessionNotValidatedException() { public SessionNotValidatedException() {
super(HttpStatus.SC_OK, "M_SESSION_NOT_VALIDATED", "This validation session has not yet been completed"); super(HttpStatus.SC_OK, "M_SESSION_NOT_VALIDATED", "This validation session has not yet been completed");

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.exception; package io.kamax.mxisd.exception;
public class SessionUnknownException extends MatrixException { public class SessionUnknownException extends HttpMatrixException {
public SessionUnknownException() { public SessionUnknownException() {
this("No valid session was found matching that sid and client secret"); this("No valid session was found matching that sid and client secret");

View File

@@ -21,7 +21,7 @@
package io.kamax.mxisd.lookup; package io.kamax.mxisd.lookup;
import com.google.gson.Gson; import com.google.gson.Gson;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
public class ThreePidMapping { public class ThreePidMapping {

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.lookup; package io.kamax.mxisd.lookup;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import java.time.Instant; import java.time.Instant;
@@ -29,7 +29,7 @@ public class ThreePidValidation extends ThreePid {
private Instant validation; private Instant validation;
public ThreePidValidation(ThreePid tpid, Instant validation) { public ThreePidValidation(ThreePid tpid, Instant validation) {
super(tpid); super(tpid.getMedium(), tpid.getAddress());
this.validation = validation; this.validation = validation;
} }

View File

@@ -0,0 +1,58 @@
/*
* 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.profile;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import org.springframework.stereotype.Component;
import java.util.Collection;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;
@Component
public class ProfileManager {
private List<ProfileProvider> providers;
public ProfileManager(List<ProfileProvider> providers) {
this.providers = providers.stream()
.filter(ProfileProvider::isEnabled)
.collect(Collectors.toList());
}
public <T> List<T> get(Function<ProfileProvider, List<T>> function) {
return providers.stream()
.map(function)
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
public List<_ThreePid> getThreepids(_MatrixID mxid) {
return get(p -> p.getThreepids(mxid));
}
public List<String> getRoles(_MatrixID mxid) {
return get(p -> p.getRoles(mxid));
}
}

View File

@@ -0,0 +1,36 @@
/*
* 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.profile;
import io.kamax.matrix._MatrixID;
import io.kamax.matrix._ThreePid;
import java.util.List;
public interface ProfileProvider {
boolean isEnabled();
List<_ThreePid> getThreepids(_MatrixID mxid);
List<String> getRoles(_MatrixID mxid);
}

View File

@@ -25,9 +25,9 @@ import com.google.i18n.phonenumbers.NumberParseException;
import com.google.i18n.phonenumbers.PhoneNumberUtil; import com.google.i18n.phonenumbers.PhoneNumberUtil;
import com.google.i18n.phonenumbers.Phonenumber; import com.google.i18n.phonenumbers.Phonenumber;
import io.kamax.matrix.MatrixID; import io.kamax.matrix.MatrixID;
import io.kamax.matrix.ThreePid;
import io.kamax.matrix.ThreePidMedium; import io.kamax.matrix.ThreePidMedium;
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.MatrixConfig;
import io.kamax.mxisd.config.SessionConfig; import io.kamax.mxisd.config.SessionConfig;
import io.kamax.mxisd.controller.identity.v1.io.RequestTokenResponse; import io.kamax.mxisd.controller.identity.v1.io.RequestTokenResponse;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.storage; package io.kamax.mxisd.storage;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.storage.dao.IThreePidSessionDao; import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
import io.kamax.mxisd.storage.ormlite.ThreePidInviteIO; import io.kamax.mxisd.storage.ormlite.ThreePidInviteIO;

View File

@@ -26,7 +26,7 @@ import com.j256.ormlite.dao.DaoManager;
import com.j256.ormlite.jdbc.JdbcConnectionSource; import com.j256.ormlite.jdbc.JdbcConnectionSource;
import com.j256.ormlite.support.ConnectionSource; import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils; import com.j256.ormlite.table.TableUtils;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.exception.InternalServerError; import io.kamax.mxisd.exception.InternalServerError;
import io.kamax.mxisd.invitation.IThreePidInviteReply; import io.kamax.mxisd.invitation.IThreePidInviteReply;
import io.kamax.mxisd.storage.IStorage; import io.kamax.mxisd.storage.IStorage;

View File

@@ -22,7 +22,7 @@ package io.kamax.mxisd.storage.ormlite.dao;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.storage.dao.IThreePidSessionDao; import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
@DatabaseTable(tableName = "session_3pid") @DatabaseTable(tableName = "session_3pid")

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.threepid.notification; package io.kamax.mxisd.threepid.notification;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ServerConfig; import io.kamax.mxisd.config.ServerConfig;
import io.kamax.mxisd.controller.identity.v1.IdentityAPIv1; import io.kamax.mxisd.controller.identity.v1.IdentityAPIv1;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.threepid.notification.email; package io.kamax.mxisd.threepid.notification.email;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.config.MatrixConfig; import io.kamax.mxisd.config.MatrixConfig;
import io.kamax.mxisd.config.ServerConfig; import io.kamax.mxisd.config.ServerConfig;
import io.kamax.mxisd.config.threepid.medium.EmailConfig; import io.kamax.mxisd.config.threepid.medium.EmailConfig;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.threepid.session; package io.kamax.mxisd.threepid.session;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import java.time.Instant; import java.time.Instant;
import java.util.Optional; import java.util.Optional;

View File

@@ -20,7 +20,7 @@
package io.kamax.mxisd.threepid.session; package io.kamax.mxisd.threepid.session;
import io.kamax.mxisd.ThreePid; import io.kamax.matrix.ThreePid;
import io.kamax.mxisd.exception.BadRequestException; import io.kamax.mxisd.exception.BadRequestException;
import io.kamax.mxisd.exception.InvalidCredentialsException; import io.kamax.mxisd.exception.InvalidCredentialsException;
import io.kamax.mxisd.storage.dao.IThreePidSessionDao; import io.kamax.mxisd.storage.dao.IThreePidSessionDao;
@@ -76,7 +76,7 @@ public class ThreePidSession implements IThreePidSession {
public ThreePidSession(String id, String server, ThreePid tPid, String secret, int attempt, String nextLink, String token) { public ThreePidSession(String id, String server, ThreePid tPid, String secret, int attempt, String nextLink, String token) {
this.id = id; this.id = id;
this.server = server; this.server = server;
this.tPid = new ThreePid(tPid); this.tPid = new ThreePid(tPid.getMedium(), tPid.getAddress());
this.secret = secret; this.secret = secret;
this.attempt = attempt; this.attempt = attempt;
this.nextLink = nextLink; this.nextLink = nextLink;

View File

@@ -0,0 +1,33 @@
/*
* 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;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Stream;
public class OptionalUtil {
public static <T> Optional<T> findFirst(Supplier<Optional<T>>... suppliers) {
return Stream.of(suppliers).map(Supplier::get).filter(Optional::isPresent).map(Optional::get).findFirst();
}
}

View File

@@ -151,10 +151,16 @@ sql:
identity: identity:
type: 'mxid' type: 'mxid'
query: 'SELECT user_id AS uid FROM user_threepids WHERE medium = ? AND address = ?' query: 'SELECT user_id AS uid FROM user_threepids WHERE medium = ? AND address = ?'
profile:
threepid:
query: 'SELECT medium, address FROM user_threepids WHERE user_id = ?'
synapseSql: synapseSql:
enabled: false enabled: false
type: 'sqlite' type: 'sqlite'
profile:
threepid:
query: 'SELECT medium, address FROM user_threepids WHERE user_id = ?'
wordpress: wordpress:
enabled: false enabled: false