Add skeleton support for Directory and Identity in Exec IdStore
This commit is contained in:
@@ -27,100 +27,28 @@ import io.kamax.matrix.json.GsonUtil;
|
|||||||
import io.kamax.mxisd.UserID;
|
import io.kamax.mxisd.UserID;
|
||||||
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.backend.rest.RestAuthRequestJson;
|
||||||
import io.kamax.mxisd.config.ExecConfig;
|
import io.kamax.mxisd.config.ExecConfig;
|
||||||
import io.kamax.mxisd.exception.ConfigurationException;
|
|
||||||
import io.kamax.mxisd.exception.InternalServerError;
|
import io.kamax.mxisd.exception.InternalServerError;
|
||||||
import io.kamax.mxisd.util.TriFunction;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.zeroturnaround.exec.ProcessExecutor;
|
|
||||||
import org.zeroturnaround.exec.ProcessResult;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Objects;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.util.Optional;
|
||||||
import java.util.*;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.BiConsumer;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
|
public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
|
||||||
|
|
||||||
private final transient Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
|
private final transient Logger log = LoggerFactory.getLogger(ExecAuthStore.class);
|
||||||
|
|
||||||
private Map<String, Supplier<String>> inputTemplates;
|
|
||||||
private Map<String, BiConsumer<String, ExecAuthResult>> outputMapper;
|
|
||||||
|
|
||||||
private TriFunction<String, _MatrixID, String, String> inputMapper;
|
|
||||||
|
|
||||||
private ExecConfig.Auth cfg;
|
private ExecConfig.Auth cfg;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExecAuthStore(ExecConfig cfg) {
|
public ExecAuthStore(ExecConfig cfg) {
|
||||||
this.cfg = Objects.requireNonNull(cfg.getAuth());
|
this.cfg = Objects.requireNonNull(cfg.getAuth());
|
||||||
|
|
||||||
inputTemplates = new HashMap<>();
|
|
||||||
inputTemplates.put(JsonType, () -> {
|
|
||||||
JsonObject json = new JsonObject();
|
|
||||||
json.addProperty("localpart", cfg.getToken().getLocalpart());
|
|
||||||
json.addProperty("domain", cfg.getToken().getDomain());
|
|
||||||
json.addProperty("mxid", cfg.getToken().getMxid());
|
|
||||||
json.addProperty("password", cfg.getToken().getPassword());
|
|
||||||
return GsonUtil.get().toJson(json);
|
|
||||||
});
|
|
||||||
inputTemplates.put(MultilinesType, () -> cfg.getToken().getLocalpart() + System.lineSeparator() +
|
|
||||||
cfg.getToken().getDomain() + System.lineSeparator() +
|
|
||||||
cfg.getToken().getMxid() + System.lineSeparator() +
|
|
||||||
cfg.getToken().getPassword() + System.lineSeparator()
|
|
||||||
);
|
|
||||||
|
|
||||||
inputMapper = (input, uId, password) -> input.replace(cfg.getToken().getLocalpart(), uId.getLocalPart())
|
|
||||||
.replace(cfg.getToken().getDomain(), uId.getDomain())
|
|
||||||
.replace(cfg.getToken().getMxid(), uId.getId())
|
|
||||||
.replace(cfg.getToken().getPassword(), password);
|
|
||||||
|
|
||||||
outputMapper = new HashMap<>();
|
|
||||||
outputMapper.put(JsonType, (output, result) -> {
|
|
||||||
JsonObject data = GsonUtil.getObj(GsonUtil.parseObj(output), "auth");
|
|
||||||
GsonUtil.findPrimitive(data, "success")
|
|
||||||
.map(JsonPrimitive::getAsBoolean)
|
|
||||||
.ifPresent(result::setSuccess);
|
|
||||||
GsonUtil.findObj(data, "profile")
|
|
||||||
.flatMap(p -> GsonUtil.findString(p, "display_name"))
|
|
||||||
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
|
||||||
});
|
|
||||||
outputMapper.put(MultilinesType, (output, result) -> {
|
|
||||||
String[] lines = output.split("\\R");
|
|
||||||
if (lines.length > 2) {
|
|
||||||
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
result.setSuccess(Optional.ofNullable(StringUtils.isEmpty(lines[0]) ? null : lines[0])
|
|
||||||
.map(v -> StringUtils.equalsAnyIgnoreCase(v, "true", "1"))
|
|
||||||
.orElse(result.isSuccess()));
|
|
||||||
|
|
||||||
if (lines.length == 2) {
|
|
||||||
Optional.ofNullable(StringUtils.isEmpty(lines[1]) ? null : lines[1])
|
|
||||||
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
validateConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateConfig() {
|
|
||||||
if (StringUtils.isNotEmpty(cfg.getInput().getType()) && !inputTemplates.containsKey(cfg.getInput().getType())) {
|
|
||||||
throw new ConfigurationException("Exec Auth input type is not valid: " + cfg.getInput().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(cfg.getOutput().getType()) && !outputMapper.containsKey(cfg.getOutput().getType())) {
|
|
||||||
throw new ConfigurationException("Exec Auth output type is not valid: " + cfg.getInput().getType());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -138,52 +66,64 @@ public class ExecAuthStore extends ExecStore implements AuthenticatorProvider {
|
|||||||
ExecAuthResult result = new ExecAuthResult();
|
ExecAuthResult result = new ExecAuthResult();
|
||||||
result.setId(new UserID(UserIdType.Localpart, uId.getLocalPart()));
|
result.setId(new UserID(UserIdType.Localpart, uId.getLocalPart()));
|
||||||
|
|
||||||
ProcessExecutor psExec = new ProcessExecutor().readOutput(true);
|
Processor<ExecAuthResult> process = new Processor<>();
|
||||||
|
process.withConfig(cfg);
|
||||||
|
process.addTokenMapper(cfg.getToken().getLocalpart(), uId::getLocalPart);
|
||||||
|
process.addTokenMapper(cfg.getToken().getDomain(), uId::getDomain);
|
||||||
|
process.addTokenMapper(cfg.getToken().getMxid(), uId::getId);
|
||||||
|
process.addTokenMapper(cfg.getToken().getPassword(), () -> password);
|
||||||
|
|
||||||
List<String> args = new ArrayList<>();
|
process.addInputTemplate(JsonType, tokens -> {
|
||||||
args.add(cfg.getCommand());
|
RestAuthRequestJson json = new RestAuthRequestJson();
|
||||||
args.addAll(cfg.getArgs().stream().map(arg -> inputMapper.apply(arg, uId, password)).collect(Collectors.toList()));
|
json.setLocalpart(tokens.getLocalpart());
|
||||||
psExec.command(args);
|
json.setDomain(tokens.getDomain());
|
||||||
|
json.setMxid(tokens.getMxid());
|
||||||
|
json.setPassword(tokens.getPassword());
|
||||||
|
return GsonUtil.get().toJson(json);
|
||||||
|
});
|
||||||
|
process.addInputTemplate(MultilinesType, tokens -> tokens.getLocalpart() + System.lineSeparator() +
|
||||||
|
tokens.getDomain() + System.lineSeparator() +
|
||||||
|
tokens.getMxid() + System.lineSeparator() +
|
||||||
|
tokens.getPassword() + System.lineSeparator()
|
||||||
|
);
|
||||||
|
|
||||||
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream()
|
process.withExitHandler(pr -> result.setExitStatus(pr.getExitValue()));
|
||||||
.peek(e -> e.setValue(inputMapper.apply(e.getValue(), uId, password)))
|
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(cfg.getInput().getType())) {
|
process.withSuccessHandler(pr -> result.setSuccess(true));
|
||||||
String template = cfg.getInput().getTemplate().orElseGet(inputTemplates.get(cfg.getInput().getType()));
|
process.withSuccessDefault(o -> result);
|
||||||
String input = inputMapper.apply(template, uId, password);
|
process.addSuccessMapper(JsonType, output -> {
|
||||||
psExec.redirectInput(IOUtils.toInputStream(input, StandardCharsets.UTF_8));
|
JsonObject data = GsonUtil.getObj(GsonUtil.parseObj(output), "auth");
|
||||||
}
|
GsonUtil.findPrimitive(data, "success")
|
||||||
|
.map(JsonPrimitive::getAsBoolean)
|
||||||
|
.ifPresent(result::setSuccess);
|
||||||
|
GsonUtil.findObj(data, "profile")
|
||||||
|
.flatMap(p -> GsonUtil.findString(p, "display_name"))
|
||||||
|
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
||||||
|
|
||||||
try {
|
return result;
|
||||||
log.info("Executing {}", cfg.getCommand());
|
});
|
||||||
ProcessResult psResult = psExec.execute();
|
process.addSuccessMapper(MultilinesType, output -> {
|
||||||
result.setExitStatus(psResult.getExitValue());
|
String[] lines = output.split("\\R");
|
||||||
String output = psResult.outputUTF8();
|
if (lines.length > 2) {
|
||||||
log.debug("Command output:{}{}", System.lineSeparator(), output);
|
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
||||||
|
}
|
||||||
|
|
||||||
log.info("Exit status: {}", result.getExitStatus());
|
result.setSuccess(Optional.ofNullable(StringUtils.isEmpty(lines[0]) ? null : lines[0])
|
||||||
if (cfg.getExit().getSuccess().contains(result.getExitStatus())) {
|
.map(v -> StringUtils.equalsAnyIgnoreCase(v, "true", "1"))
|
||||||
result.setSuccess(true);
|
.orElse(result.isSuccess()));
|
||||||
if (result.isSuccess() && StringUtils.isNotEmpty(output)) {
|
|
||||||
outputMapper.get(cfg.getOutput().getType()).accept(output, result);
|
if (lines.length == 2) {
|
||||||
} else {
|
Optional.ofNullable(StringUtils.isEmpty(lines[1]) ? null : lines[1])
|
||||||
if (StringUtils.isNotEmpty(output)) {
|
.ifPresent(v -> result.getProfile().setDisplayName(v));
|
||||||
log.info("Exec auth failed with output:{}{}", System.lineSeparator(), output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (cfg.getExit().getFailure().contains(result.getExitStatus())) {
|
|
||||||
log.debug("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
|
||||||
result.setSuccess(false);
|
|
||||||
} else {
|
|
||||||
log.error("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
|
||||||
throw new InternalServerError("Exec auth command returned with unexpected exit status");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
} catch (IOException | InterruptedException | TimeoutException e) {
|
});
|
||||||
throw new InternalServerError(e);
|
|
||||||
}
|
process.withFailureHandler(pr -> result.setSuccess(false));
|
||||||
|
process.withFailureDefault(o -> result);
|
||||||
|
|
||||||
|
return process.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,10 +20,13 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.backend.exec;
|
package io.kamax.mxisd.backend.exec;
|
||||||
|
|
||||||
|
import io.kamax.matrix.MatrixID;
|
||||||
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
import io.kamax.mxisd.config.ExecConfig;
|
import io.kamax.mxisd.config.ExecConfig;
|
||||||
|
import io.kamax.mxisd.config.MatrixConfig;
|
||||||
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchRequest;
|
||||||
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
import io.kamax.mxisd.controller.directory.v1.io.UserDirectorySearchResult;
|
||||||
import io.kamax.mxisd.directory.IDirectoryProvider;
|
import io.kamax.mxisd.directory.IDirectoryProvider;
|
||||||
import io.kamax.mxisd.exception.NotImplementedException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
@@ -31,10 +34,12 @@ import org.springframework.stereotype.Component;
|
|||||||
public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider {
|
public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider {
|
||||||
|
|
||||||
private ExecConfig.Directory cfg;
|
private ExecConfig.Directory cfg;
|
||||||
|
private MatrixConfig mxCfg;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExecDirectoryStore(ExecConfig cfg) {
|
public ExecDirectoryStore(ExecConfig cfg, MatrixConfig mxCfg) {
|
||||||
this.cfg = cfg.getDirectory();
|
this.cfg = cfg.getDirectory();
|
||||||
|
this.mxCfg = mxCfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -42,14 +47,35 @@ public class ExecDirectoryStore extends ExecStore implements IDirectoryProvider
|
|||||||
return cfg.isEnabled();
|
return cfg.isEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private UserDirectorySearchResult search(ExecConfig.Process cfg, UserDirectorySearchRequest request) {
|
||||||
|
Processor<UserDirectorySearchResult> processor = new Processor<>();
|
||||||
|
processor.withConfig(cfg);
|
||||||
|
processor.addInputTemplate(JsonType, tokens -> GsonUtil.get().toJson(new UserDirectorySearchRequest(tokens.getType(), tokens.getQuery())));
|
||||||
|
processor.addInputTemplate(MultilinesType, tokens -> tokens.getType() + System.lineSeparator() + tokens.getQuery());
|
||||||
|
|
||||||
|
processor.addTokenMapper(cfg.getToken().getType(), request::getBy);
|
||||||
|
processor.addTokenMapper(cfg.getToken().getQuery(), request::getSearchTerm);
|
||||||
|
|
||||||
|
processor.addSuccessMapper(JsonType, output -> {
|
||||||
|
UserDirectorySearchResult response = GsonUtil.get().fromJson(output, UserDirectorySearchResult.class);
|
||||||
|
for (UserDirectorySearchResult.Result result : response.getResults()) {
|
||||||
|
result.setUserId(MatrixID.asAcceptable(result.getUserId(), mxCfg.getDomain()).getId());
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
});
|
||||||
|
processor.withFailureDefault(output -> new UserDirectorySearchResult());
|
||||||
|
|
||||||
|
return processor.execute();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDirectorySearchResult searchByDisplayName(String query) {
|
public UserDirectorySearchResult searchByDisplayName(String query) {
|
||||||
throw new NotImplementedException(this.getClass().getName());
|
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("name", query));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDirectorySearchResult searchBy3pid(String query) {
|
public UserDirectorySearchResult searchBy3pid(String query) {
|
||||||
throw new NotImplementedException(this.getClass().getName());
|
return search(cfg.getSearch().getByName(), new UserDirectorySearchRequest("threepid", query));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,35 +20,29 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.backend.exec;
|
package io.kamax.mxisd.backend.exec;
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import io.kamax.matrix.MatrixID;
|
import io.kamax.matrix.MatrixID;
|
||||||
import io.kamax.matrix._MatrixID;
|
import io.kamax.matrix.ThreePid;
|
||||||
import io.kamax.matrix.json.GsonUtil;
|
import io.kamax.matrix.json.GsonUtil;
|
||||||
|
import io.kamax.mxisd.UserIdType;
|
||||||
|
import io.kamax.mxisd.backend.rest.LookupBulkResponseJson;
|
||||||
import io.kamax.mxisd.config.ExecConfig;
|
import io.kamax.mxisd.config.ExecConfig;
|
||||||
import io.kamax.mxisd.config.MatrixConfig;
|
import io.kamax.mxisd.config.MatrixConfig;
|
||||||
import io.kamax.mxisd.exception.ConfigurationException;
|
|
||||||
import io.kamax.mxisd.exception.InternalServerError;
|
import io.kamax.mxisd.exception.InternalServerError;
|
||||||
import io.kamax.mxisd.exception.NotImplementedException;
|
|
||||||
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 org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.zeroturnaround.exec.ProcessExecutor;
|
|
||||||
import org.zeroturnaround.exec.ProcessResult;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.util.Collections;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.util.List;
|
||||||
import java.util.*;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeoutException;
|
|
||||||
import java.util.function.BiFunction;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@@ -59,85 +53,10 @@ public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
|
|||||||
private final ExecConfig.Identity cfg;
|
private final ExecConfig.Identity cfg;
|
||||||
private final MatrixConfig mxCfg;
|
private final MatrixConfig mxCfg;
|
||||||
|
|
||||||
private BiFunction<String, SingleLookupRequest, String> singleInputMap;
|
|
||||||
private Map<String, Supplier<String>> singleInputTemplates;
|
|
||||||
private Map<String, Function<String, Optional<_MatrixID>>> singleOutputMap;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) {
|
public ExecIdentityStore(ExecConfig cfg, MatrixConfig mxCfg) {
|
||||||
this.cfg = cfg.getIdentity();
|
this.cfg = cfg.getIdentity();
|
||||||
this.mxCfg = mxCfg;
|
this.mxCfg = mxCfg;
|
||||||
|
|
||||||
singleInputMap = (v, request) -> v.replace(cfg.getToken().getMedium(), request.getType())
|
|
||||||
.replace(cfg.getToken().getAddress(), request.getThreePid());
|
|
||||||
|
|
||||||
singleInputTemplates = new HashMap<>();
|
|
||||||
singleInputTemplates.put(JsonType, () -> {
|
|
||||||
JsonObject json = new JsonObject();
|
|
||||||
json.addProperty("medium", cfg.getToken().getMedium());
|
|
||||||
json.addProperty("address", cfg.getToken().getAddress());
|
|
||||||
return GsonUtil.get().toJson(json);
|
|
||||||
});
|
|
||||||
singleInputTemplates.put(MultilinesType, () -> cfg.getToken().getMedium()
|
|
||||||
+ System.lineSeparator()
|
|
||||||
+ cfg.getToken().getAddress()
|
|
||||||
);
|
|
||||||
|
|
||||||
singleOutputMap = new HashMap<>();
|
|
||||||
singleOutputMap.put(JsonType, output -> {
|
|
||||||
if (StringUtils.isBlank(output)) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
return GsonUtil.findObj(GsonUtil.parseObj(output), "lookup").map(lookup -> {
|
|
||||||
String type = GsonUtil.getStringOrThrow(lookup, "type");
|
|
||||||
String value = GsonUtil.getStringOrThrow(lookup, "value");
|
|
||||||
if (StringUtils.equals(type, "uid")) {
|
|
||||||
return MatrixID.asAcceptable(value, mxCfg.getDomain());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.equals(type, "mxid")) {
|
|
||||||
return MatrixID.asAcceptable(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InternalServerError("Invalid user type: " + type);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
singleOutputMap.put(MultilinesType, output -> {
|
|
||||||
String[] lines = output.split("\\R");
|
|
||||||
if (lines.length > 2) {
|
|
||||||
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lines.length == 1 && StringUtils.isBlank(lines[0])) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
String type = StringUtils.trimToEmpty(lines.length == 1 ? "uid" : lines[0]);
|
|
||||||
String value = StringUtils.trimToEmpty(lines.length == 2 ? lines[1] : lines[0]);
|
|
||||||
|
|
||||||
if (StringUtils.equals(type, "uid")) {
|
|
||||||
return Optional.of(MatrixID.asAcceptable(value, mxCfg.getDomain()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.equals(type, "mxid")) {
|
|
||||||
return Optional.of(MatrixID.asAcceptable(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new InternalServerError("Invalid user type: " + type);
|
|
||||||
});
|
|
||||||
|
|
||||||
validateConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void validateConfig() {
|
|
||||||
if (StringUtils.isNotEmpty(cfg.getInput().getType()) && !singleInputTemplates.containsKey(cfg.getInput().getType())) {
|
|
||||||
throw new ConfigurationException("Exec Identity Single Lookup: input type is not valid: " + cfg.getInput().getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(cfg.getOutput().getType()) && !singleOutputMap.containsKey(cfg.getOutput().getType())) {
|
|
||||||
throw new ConfigurationException("Exec Auth output type is not valid: " + cfg.getInput().getType());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -155,55 +74,125 @@ public class ExecIdentityStore extends ExecStore implements IThreePidProvider {
|
|||||||
return cfg.getPriority();
|
return cfg.getPriority();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ExecConfig.Process getSingleCfg() {
|
||||||
|
return cfg.getLookup().getSingle();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
public Optional<SingleLookupReply> find(SingleLookupRequest request) {
|
||||||
ProcessExecutor psExec = new ProcessExecutor().readOutput(true);
|
Processor<Optional<SingleLookupReply>> processor = new Processor<>();
|
||||||
|
processor.withConfig(cfg.getLookup().getSingle());
|
||||||
|
|
||||||
List<String> args = new ArrayList<>();
|
processor.addTokenMapper(getSingleCfg().getToken().getMedium(), request::getType);
|
||||||
args.add(cfg.getCommand());
|
processor.addTokenMapper(getSingleCfg().getToken().getAddress(), request::getThreePid);
|
||||||
args.addAll(cfg.getArgs().stream().map(arg -> singleInputMap.apply(arg, request)).collect(Collectors.toList()));
|
|
||||||
psExec.command(args);
|
|
||||||
|
|
||||||
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream()
|
processor.addInputTemplate(JsonType, tokens -> {
|
||||||
.peek(e -> e.setValue(singleInputMap.apply(e.getValue(), request)))
|
JsonObject json = new JsonObject();
|
||||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
json.addProperty("medium", tokens.getMedium());
|
||||||
|
json.addProperty("address", tokens.getAddress());
|
||||||
|
return GsonUtil.get().toJson(json);
|
||||||
|
});
|
||||||
|
processor.addInputTemplate(MultilinesType, tokens -> tokens.getMedium()
|
||||||
|
+ System.lineSeparator()
|
||||||
|
+ tokens.getAddress()
|
||||||
|
);
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(cfg.getInput().getType())) {
|
processor.addSuccessMapper(JsonType, output -> {
|
||||||
String template = cfg.getInput().getTemplate().orElseGet(singleInputTemplates.get(cfg.getInput().getType()));
|
if (StringUtils.isBlank(output)) {
|
||||||
String input = singleInputMap.apply(template, request);
|
return Optional.empty();
|
||||||
psExec.redirectInput(IOUtils.toInputStream(input, StandardCharsets.UTF_8));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
return GsonUtil.findObj(GsonUtil.parseObj(output), "lookup").map(lookup -> {
|
||||||
log.info("Executing {}", cfg.getCommand());
|
String type = GsonUtil.getStringOrThrow(lookup, "type");
|
||||||
ProcessResult psResult = psExec.execute();
|
String value = GsonUtil.getStringOrThrow(lookup, "value");
|
||||||
String output = psResult.outputUTF8();
|
if (UserIdType.Localpart.is(type)) {
|
||||||
log.debug("Command output:{}{}", System.lineSeparator(), output);
|
return MatrixID.asAcceptable(value, mxCfg.getDomain());
|
||||||
|
|
||||||
log.info("Exit status: {}", psResult.getExitValue());
|
|
||||||
if (cfg.getExit().getSuccess().contains(psResult.getExitValue())) {
|
|
||||||
if (StringUtils.isBlank(output)) {
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return singleOutputMap.get(cfg.getOutput().getType())
|
if (UserIdType.MatrixID.is(type)) {
|
||||||
.apply(output)
|
return MatrixID.asAcceptable(value);
|
||||||
.map(mxId -> new SingleLookupReply(request, mxId));
|
}
|
||||||
} else if (cfg.getExit().getFailure().contains(psResult.getExitValue())) {
|
|
||||||
log.debug("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
throw new InternalServerError("Invalid user type: " + type);
|
||||||
return Optional.empty();
|
}).map(mxId -> new SingleLookupReply(request, mxId));
|
||||||
} else {
|
});
|
||||||
log.error("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
|
||||||
throw new InternalServerError("Exec auth command returned with unexpected exit status");
|
processor.addSuccessMapper(MultilinesType, output -> {
|
||||||
|
String[] lines = output.split("\\R");
|
||||||
|
if (lines.length > 2) {
|
||||||
|
throw new InternalServerError("Exec auth command returned more than 2 lines (" + lines.length + ")");
|
||||||
}
|
}
|
||||||
} catch (IOException | InterruptedException | TimeoutException e) {
|
|
||||||
throw new InternalServerError(e);
|
if (lines.length == 1 && StringUtils.isBlank(lines[0])) {
|
||||||
}
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
String type = StringUtils.trimToEmpty(lines.length == 1 ? "uid" : lines[0]);
|
||||||
|
String value = StringUtils.trimToEmpty(lines.length == 2 ? lines[1] : lines[0]);
|
||||||
|
|
||||||
|
if (UserIdType.Localpart.is(type)) {
|
||||||
|
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value, mxCfg.getDomain())));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UserIdType.MatrixID.is(type)) {
|
||||||
|
return Optional.of(new SingleLookupReply(request, MatrixID.asAcceptable(value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InternalServerError("Invalid user type: " + type);
|
||||||
|
});
|
||||||
|
|
||||||
|
processor.withFailureDefault(o -> Optional.empty());
|
||||||
|
|
||||||
|
return processor.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) {
|
public List<ThreePidMapping> populate(List<ThreePidMapping> mappings) {
|
||||||
throw new NotImplementedException(this.getClass().getName());
|
Processor<List<ThreePidMapping>> processor = new Processor<>();
|
||||||
|
processor.withConfig(cfg.getLookup().getBulk());
|
||||||
|
|
||||||
|
processor.addInput(JsonType, () -> {
|
||||||
|
JsonArray tpids = GsonUtil.asArray(mappings.stream()
|
||||||
|
.map(mapping -> GsonUtil.get().toJsonTree(new ThreePid(mapping.getMedium(), mapping.getValue())))
|
||||||
|
.collect(Collectors.toList()));
|
||||||
|
return GsonUtil.get().toJson(GsonUtil.makeObj("lookup", tpids));
|
||||||
|
});
|
||||||
|
processor.addInput(MultilinesType, () -> {
|
||||||
|
StringBuilder input = new StringBuilder();
|
||||||
|
for (ThreePidMapping mapping : mappings) {
|
||||||
|
input.append(mapping.getMedium()).append("\t").append(mapping.getValue()).append(System.lineSeparator());
|
||||||
|
}
|
||||||
|
return input.toString();
|
||||||
|
});
|
||||||
|
|
||||||
|
processor.addSuccessMapper(JsonType, output -> {
|
||||||
|
if (StringUtils.isBlank(output)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
LookupBulkResponseJson response = GsonUtil.get().fromJson(output, LookupBulkResponseJson.class);
|
||||||
|
return response.getLookup().stream().map(item -> {
|
||||||
|
ThreePidMapping mapping = new ThreePidMapping();
|
||||||
|
mapping.setMedium(item.getMedium());
|
||||||
|
mapping.setValue(item.getAddress());
|
||||||
|
|
||||||
|
if (UserIdType.Localpart.is(item.getId().getType())) {
|
||||||
|
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue(), mxCfg.getDomain()).getId());
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UserIdType.MatrixID.is(item.getId().getType())) {
|
||||||
|
mapping.setValue(MatrixID.asAcceptable(item.getId().getValue()).getId());
|
||||||
|
return mapping;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InternalServerError("Invalid user type: " + item.getId().getType());
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
});
|
||||||
|
|
||||||
|
processor.withFailureDefault(output -> Collections.emptyList());
|
||||||
|
|
||||||
|
return processor.execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,9 +20,227 @@
|
|||||||
|
|
||||||
package io.kamax.mxisd.backend.exec;
|
package io.kamax.mxisd.backend.exec;
|
||||||
|
|
||||||
public abstract class ExecStore {
|
import io.kamax.mxisd.config.ExecConfig;
|
||||||
|
import io.kamax.mxisd.exception.InternalServerError;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.zeroturnaround.exec.ProcessExecutor;
|
||||||
|
import org.zeroturnaround.exec.ProcessResult;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class ExecStore {
|
||||||
|
|
||||||
public static final String JsonType = "json";
|
public static final String JsonType = "json";
|
||||||
public static final String MultilinesType = "multilines";
|
public static final String MultilinesType = "multilines";
|
||||||
|
|
||||||
|
private final Logger log = LoggerFactory.getLogger(ExecStore.class);
|
||||||
|
|
||||||
|
public class Processor<V> {
|
||||||
|
|
||||||
|
private ExecConfig.Process cfg;
|
||||||
|
|
||||||
|
private Supplier<Optional<String>> inputSupplier;
|
||||||
|
private Function<String, String> inputTypeMapper;
|
||||||
|
private Function<String, String> inputUnknownTypeMapper;
|
||||||
|
private Map<String, Supplier<String>> inputTypeSuppliers;
|
||||||
|
|
||||||
|
private Map<String, Function<ExecConfig.TokenOverride, String>> inputTypeTemplates;
|
||||||
|
private Supplier<String> inputTypeNoTemplateHandler;
|
||||||
|
private Map<String, Function<ExecConfig.TokenOverride, String>> inputTypeTokenizers;
|
||||||
|
private Map<String, Supplier<String>> tokenMappers;
|
||||||
|
private Function<String, String> tokenHandler;
|
||||||
|
|
||||||
|
private Consumer<ProcessResult> onExitHandler;
|
||||||
|
private Consumer<ProcessResult> successHandler;
|
||||||
|
private Map<String, Function<String, V>> successMappers;
|
||||||
|
private Function<String, V> successDefault;
|
||||||
|
private Consumer<ProcessResult> failureHandler;
|
||||||
|
private Map<String, Function<String, V>> failureMappers;
|
||||||
|
private Function<String, V> failureDefault;
|
||||||
|
private Consumer<ProcessResult> unknownHandler;
|
||||||
|
private Map<String, Function<String, V>> unknownMappers;
|
||||||
|
private Function<String, V> unknownDefault;
|
||||||
|
|
||||||
|
public Processor() {
|
||||||
|
tokenMappers = new HashMap<>();
|
||||||
|
inputTypeSuppliers = new HashMap<>();
|
||||||
|
inputTypeTemplates = new HashMap<>();
|
||||||
|
|
||||||
|
tokenHandler = input -> {
|
||||||
|
for (Map.Entry<String, Supplier<String>> entry : tokenMappers.entrySet()) {
|
||||||
|
input = input.replace(entry.getKey(), entry.getValue().get());
|
||||||
|
}
|
||||||
|
return input;
|
||||||
|
};
|
||||||
|
|
||||||
|
inputTypeNoTemplateHandler = () -> cfg.getInput().getType()
|
||||||
|
.map(type -> inputTypeTemplates.get(type).apply(cfg.getToken()))
|
||||||
|
.orElse("");
|
||||||
|
|
||||||
|
inputUnknownTypeMapper = type -> tokenHandler.apply(cfg.getInput().getTemplate().orElseGet(inputTypeNoTemplateHandler));
|
||||||
|
|
||||||
|
inputTypeMapper = type -> {
|
||||||
|
if (!inputTypeSuppliers.containsKey(type)) {
|
||||||
|
return inputUnknownTypeMapper.apply(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputTypeSuppliers.get(type).get();
|
||||||
|
};
|
||||||
|
|
||||||
|
inputSupplier = () -> cfg.getInput().getType().map(type -> inputTypeMapper.apply(type));
|
||||||
|
|
||||||
|
onExitHandler = pr -> {
|
||||||
|
};
|
||||||
|
|
||||||
|
successMappers = new HashMap<>();
|
||||||
|
successHandler = pr -> {
|
||||||
|
};
|
||||||
|
successDefault = output -> {
|
||||||
|
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||||
|
throw new InternalServerError("Exec command has no success handler configured. This is a bug. Please report.");
|
||||||
|
};
|
||||||
|
|
||||||
|
failureHandler = pr -> {
|
||||||
|
};
|
||||||
|
failureMappers = new HashMap<>();
|
||||||
|
failureDefault = output -> {
|
||||||
|
log.info("{} stdout: {}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||||
|
throw new InternalServerError("Exec command has no failure handler configured. This is a bug. Please report.");
|
||||||
|
};
|
||||||
|
|
||||||
|
unknownHandler = pr -> log.warn("Unexpected exit status: {}", pr.getExitValue());
|
||||||
|
unknownMappers = new HashMap<>();
|
||||||
|
unknownDefault = output -> {
|
||||||
|
log.error("{} stdout:{}{}", cfg.getCommand(), System.lineSeparator(), output);
|
||||||
|
throw new InternalServerError("Exec command returned with unexpected exit status");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withConfig(ExecConfig.Process cfg) {
|
||||||
|
this.cfg = cfg;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addTokenMapper(String token, Supplier<String> data) {
|
||||||
|
tokenMappers.put(token, data);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withTokenHandler(Function<String, String> tokenHandler) {
|
||||||
|
this.tokenHandler = tokenHandler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addInput(String type, Supplier<String> handler) {
|
||||||
|
inputTypeSuppliers.put(type, handler);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addInputTemplate(String type, Function<ExecConfig.TokenOverride, String> template) {
|
||||||
|
inputTypeTemplates.put(type, template);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withExitHandler(Consumer<ProcessResult> handler) {
|
||||||
|
onExitHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withSuccessHandler(Consumer<ProcessResult> handler) {
|
||||||
|
successHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addSuccessMapper(String type, Function<String, V> mapper) {
|
||||||
|
successMappers.put(type, mapper);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withSuccessDefault(Function<String, V> mapper) {
|
||||||
|
successDefault = mapper;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withFailureHandler(Consumer<ProcessResult> handler) {
|
||||||
|
failureHandler = handler;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addFailureMapper(String type, Function<String, V> mapper) {
|
||||||
|
failureMappers.put(type, mapper);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withFailureDefault(Function<String, V> mapper) {
|
||||||
|
failureDefault = mapper;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> addUnknownMapper(String type, Function<String, V> mapper) {
|
||||||
|
unknownMappers.put(type, mapper);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Processor<V> withUnknownDefault(Function<String, V> mapper) {
|
||||||
|
unknownDefault = mapper;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
V execute() {
|
||||||
|
log.info("Executing {}", cfg.getCommand());
|
||||||
|
|
||||||
|
try {
|
||||||
|
ProcessExecutor psExec = new ProcessExecutor().readOutput(true);
|
||||||
|
|
||||||
|
List<String> args = new ArrayList<>();
|
||||||
|
args.add(cfg.getCommand());
|
||||||
|
args.addAll(cfg.getArgs().stream().map(arg -> tokenHandler.apply(arg)).collect(Collectors.toList()));
|
||||||
|
psExec.command(args);
|
||||||
|
|
||||||
|
psExec.environment(new HashMap<>(cfg.getEnv()).entrySet().stream()
|
||||||
|
.peek(e -> e.setValue(tokenHandler.apply(e.getValue())))
|
||||||
|
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||||
|
|
||||||
|
inputSupplier.get().ifPresent(input -> psExec.redirectInput(IOUtils.toInputStream(input, StandardCharsets.UTF_8)));
|
||||||
|
|
||||||
|
ProcessResult psResult = psExec.execute();
|
||||||
|
String output = psResult.outputUTF8();
|
||||||
|
onExitHandler.accept(psResult);
|
||||||
|
|
||||||
|
if (cfg.getExit().getSuccess().contains(psResult.getExitValue())) {
|
||||||
|
successHandler.accept(psResult);
|
||||||
|
|
||||||
|
return cfg.getOutput().getType()
|
||||||
|
.map(type -> successMappers.getOrDefault(type, successDefault).apply(output))
|
||||||
|
.orElseGet(() -> successDefault.apply(output));
|
||||||
|
} else if (cfg.getExit().getFailure().contains(psResult.getExitValue())) {
|
||||||
|
failureHandler.accept(psResult);
|
||||||
|
|
||||||
|
return cfg.getOutput().getType()
|
||||||
|
.map(type -> failureMappers.getOrDefault(type, failureDefault).apply(output))
|
||||||
|
.orElseGet(() -> failureDefault.apply(output));
|
||||||
|
} else {
|
||||||
|
unknownHandler.accept(psResult);
|
||||||
|
|
||||||
|
return cfg.getOutput().getType()
|
||||||
|
.map(type -> unknownMappers.getOrDefault(type, unknownDefault).apply(output))
|
||||||
|
.orElseGet(() -> unknownDefault.apply(output));
|
||||||
|
}
|
||||||
|
} catch (IOException | InterruptedException | TimeoutException e) {
|
||||||
|
log.error("Failed to execute {}", cfg.getCommand());
|
||||||
|
throw new InternalServerError(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -36,8 +36,8 @@ public class ExecConfig {
|
|||||||
private String type;
|
private String type;
|
||||||
private String template;
|
private String template;
|
||||||
|
|
||||||
public String getType() {
|
public Optional<String> getType() {
|
||||||
return type;
|
return Optional.ofNullable(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setType(String type) {
|
public void setType(String type) {
|
||||||
@@ -83,6 +83,10 @@ public class ExecConfig {
|
|||||||
private String domain;
|
private String domain;
|
||||||
private String mxid;
|
private String mxid;
|
||||||
private String password;
|
private String password;
|
||||||
|
private String medium;
|
||||||
|
private String address;
|
||||||
|
private String type;
|
||||||
|
private String query;
|
||||||
|
|
||||||
public String getLocalpart() {
|
public String getLocalpart() {
|
||||||
return StringUtils.defaultIfEmpty(localpart, getToken().getLocalpart());
|
return StringUtils.defaultIfEmpty(localpart, getToken().getLocalpart());
|
||||||
@@ -116,6 +120,38 @@ public class ExecConfig {
|
|||||||
this.password = password;
|
this.password = password;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getMedium() {
|
||||||
|
return StringUtils.defaultIfEmpty(medium, getToken().getMedium());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMedium(String medium) {
|
||||||
|
this.medium = medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAddress() {
|
||||||
|
return StringUtils.defaultIfEmpty(address, getToken().getAddress());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAddress(String address) {
|
||||||
|
this.address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return StringUtils.defaultIfEmpty(type, getToken().getType());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuery() {
|
||||||
|
return StringUtils.defaultIfEmpty(query, getToken().getQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuery(String query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Token {
|
public class Token {
|
||||||
@@ -126,6 +162,8 @@ public class ExecConfig {
|
|||||||
private String password = "{password}";
|
private String password = "{password}";
|
||||||
private String medium = "{medium}";
|
private String medium = "{medium}";
|
||||||
private String address = "{address}";
|
private String address = "{address}";
|
||||||
|
private String type = "{type}";
|
||||||
|
private String query = "{query}";
|
||||||
|
|
||||||
public String getLocalpart() {
|
public String getLocalpart() {
|
||||||
return localpart;
|
return localpart;
|
||||||
@@ -175,6 +213,22 @@ public class ExecConfig {
|
|||||||
this.address = address;
|
this.address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getType() {
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setType(String type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getQuery() {
|
||||||
|
return query;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setQuery(String query) {
|
||||||
|
this.query = query;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Process {
|
public class Process {
|
||||||
@@ -311,10 +365,34 @@ public class ExecConfig {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Identity extends Process {
|
public class Lookup {
|
||||||
|
|
||||||
|
private Process single = new Process();
|
||||||
|
private Process bulk = new Process();
|
||||||
|
|
||||||
|
public Process getSingle() {
|
||||||
|
return single;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSingle(Process single) {
|
||||||
|
this.single = single;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Process getBulk() {
|
||||||
|
return bulk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBulk(Process bulk) {
|
||||||
|
this.bulk = bulk;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Identity {
|
||||||
|
|
||||||
private Boolean enabled;
|
private Boolean enabled;
|
||||||
private int priority;
|
private int priority;
|
||||||
|
private Lookup lookup = new Lookup();
|
||||||
|
|
||||||
public Boolean isEnabled() {
|
public Boolean isEnabled() {
|
||||||
return enabled;
|
return enabled;
|
||||||
@@ -332,6 +410,14 @@ public class ExecConfig {
|
|||||||
this.priority = priority;
|
this.priority = priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Lookup getLookup() {
|
||||||
|
return lookup;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLookup(Lookup lookup) {
|
||||||
|
this.lookup = lookup;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class Profile extends Process {
|
public class Profile extends Process {
|
||||||
|
@@ -29,6 +29,11 @@ public class UserDirectorySearchRequest {
|
|||||||
setSearchTerm(searchTerm);
|
setSearchTerm(searchTerm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public UserDirectorySearchRequest(String type, String searchTerm) {
|
||||||
|
setBy(type);
|
||||||
|
setSearchTerm(searchTerm);
|
||||||
|
}
|
||||||
|
|
||||||
public String getBy() {
|
public String getBy() {
|
||||||
return by;
|
return by;
|
||||||
}
|
}
|
||||||
|
@@ -18,11 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.backend.exec.input;
|
package io.kamax.mxisd.backend.exec.auth.input;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class ArgsTest extends InputTest {
|
public class ExecAuthArgsTest extends ExecAuthTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setValidCommand() {
|
protected void setValidCommand() {
|
@@ -18,11 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.backend.exec.input;
|
package io.kamax.mxisd.backend.exec.auth.input;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
|
||||||
public class EnvTest extends InputTest {
|
public class ExecAuthEnvTest extends ExecAuthTest {
|
||||||
|
|
||||||
private final String LocalpartEnv = "LOCALPART";
|
private final String LocalpartEnv = "LOCALPART";
|
||||||
private final String DomainEnv = "DOMAIN";
|
private final String DomainEnv = "DOMAIN";
|
@@ -18,11 +18,11 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.backend.exec.input;
|
package io.kamax.mxisd.backend.exec.auth.input;
|
||||||
|
|
||||||
import io.kamax.mxisd.backend.exec.ExecStore;
|
import io.kamax.mxisd.backend.exec.ExecStore;
|
||||||
|
|
||||||
public class MultilinesTest extends InputTest {
|
public class ExecAuthInputMultilinesTest extends ExecAuthTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setValidCommand() {
|
protected void setValidCommand() {
|
@@ -18,7 +18,7 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.kamax.mxisd.backend.exec.input;
|
package io.kamax.mxisd.backend.exec.auth.input;
|
||||||
|
|
||||||
import io.kamax.matrix.MatrixID;
|
import io.kamax.matrix.MatrixID;
|
||||||
import io.kamax.matrix._MatrixID;
|
import io.kamax.matrix._MatrixID;
|
||||||
@@ -35,7 +35,7 @@ import java.util.Collections;
|
|||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
public abstract class InputTest {
|
public abstract class ExecAuthTest {
|
||||||
|
|
||||||
protected final ExecConfig cfg;
|
protected final ExecConfig cfg;
|
||||||
protected final ExecAuthStore p;
|
protected final ExecAuthStore p;
|
||||||
@@ -90,7 +90,7 @@ public abstract class InputTest {
|
|||||||
cfg.getAuth().addEnv("REQ_PASS", requiredPass);
|
cfg.getAuth().addEnv("REQ_PASS", requiredPass);
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputTest() {
|
public ExecAuthTest() {
|
||||||
cfg = new ExecConfig();
|
cfg = new ExecConfig();
|
||||||
p = new ExecAuthStore(cfg);
|
p = new ExecAuthStore(cfg);
|
||||||
}
|
}
|
Reference in New Issue
Block a user