This is an automated email from the ASF dual-hosted git repository.
ilgrosso pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/syncope.git
The following commit(s) were added to refs/heads/master by this push:
new cf54140 [SYNCOPE-1455] Cleaning up + more tests + some useful Filters
cf54140 is described below
commit cf54140d85cf3489f67de5aabc4a3e468b013998
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Tue Jun 23 14:20:47 2020 +0200
[SYNCOPE-1455] Cleaning up + more tests + some useful Filters
---
.../console/panels/GatewayRoutePredicatePanel.java | 6 +-
.../console/panels/GatewayRouteWizardBuilder.java | 8 -
.../panels/GatewayRouteWizardBuilder$Profile.html | 1 -
.../syncope/common/lib/to/GatewayRouteTO.java | 13 -
.../syncope/common/lib/types/FilterFactory.java | 3 +
.../common/lib/types/GatewayRoutePredicate.java | 8 +-
...ateCond.java => GatewayRoutePredicateCond.java} | 2 +-
.../core/persistence/api/entity/GatewayRoute.java | 5 -
.../src/test/resources/domains/MasterContent.xml | 3 +-
.../persistence/jpa/entity/JPAGatewayRoute.java | 17 -
.../persistence/jpa/inner/GatewayRouteTest.java | 3 -
.../src/test/resources/domains/MasterContent.xml | 2 +-
.../java/data/GatewayRouteDataBinderImpl.java | 3 -
.../syncope/fit/core/GatewayRouteITCase.java | 8 -
pom.xml | 6 +
sra/pom.xml | 17 +
.../syncope/sra/ApplicationContextUtils.java | 57 ++
.../java/org/apache/syncope/sra/RouteProvider.java | 98 ++--
...copeSRAApplication.java => SecurityConfig.java} | 44 +-
.../apache/syncope/sra/SyncopeSRAApplication.java | 49 +-
.../sra/filters/AddRefererFilterFactory.java | 18 +-
.../ClientCertsToRequestHeaderFilterFactory.java | 74 +++
.../{ => filters}/CustomGatewayFilterFactory.java | 9 +-
.../filters/LinkRewriteGatewayFilterFactory.java | 88 +++
.../ModifyResponseGatewayFilterFactory.java | 155 +++++
.../QueryParamToRequestHeaderFilterFactory.java | 56 ++
.../CustomRoutePredicateFactory.java | 2 +-
.../java/org/apache/syncope/sra/AbstractTest.java | 65 +++
.../java/org/apache/syncope/sra/ActuatorTest.java | 64 ++
.../org/apache/syncope/sra/RouteProviderTest.java | 647 +++++++++++++++++++++
.../syncope/sra/SyncopeCoreTestingServer.java | 32 +-
.../org/apache/syncope/sra/SyncopeSRATest.java | 209 -------
.../apache/syncope/sra/TLSRouteProviderTest.java | 148 +++++
.../apache/syncope/sra/ZookeeperTestingServer.java | 40 +-
.../BodyPropertyAddingGatewayFilterFactory.java | 2 +-
.../BodyPropertyMatchingRoutePredicateFactory.java | 2 +-
sra/src/test/resources/application-tls.properties | 31 +
sra/src/test/resources/client_pavel.p12 | Bin 0 -> 5557 bytes
sra/src/test/resources/keyStore.p12 | Bin 0 -> 4173 bytes
sra/src/test/resources/trustStore.jks | Bin 0 -> 1484 bytes
40 files changed, 1551 insertions(+), 444 deletions(-)
diff --git
a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
index 2dc4b58..df95baa 100644
---
a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
+++
b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRoutePredicatePanel.java
@@ -30,7 +30,7 @@ import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxCheckBoxPanel;
import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.PredicateCond;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicateCond;
import org.apache.syncope.common.lib.types.PredicateFactory;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.extensions.ajax.markup.html.IndicatingAjaxButton;
@@ -89,9 +89,9 @@ public class GatewayRoutePredicatePanel extends Panel {
new AjaxTextFieldPanel("args", "args", new
PropertyModel<>(predicate, "args"));
item.add(args.hideLabel());
- AjaxDropDownChoicePanel<PredicateCond> cond =
+ AjaxDropDownChoicePanel<GatewayRoutePredicateCond> cond =
new AjaxDropDownChoicePanel<>("cond", "cond", new
PropertyModel<>(predicate, "cond"));
- cond.setChoices(List.of(PredicateCond.values()));
+ cond.setChoices(List.of(GatewayRoutePredicateCond.values()));
item.add(cond.hideLabel());
ActionsPanel<Serializable> actions = new
ActionsPanel<>("actions", null);
diff --git
a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
index f043bc7..e4dce5e 100644
---
a/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
+++
b/client/am/console/src/main/java/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder.java
@@ -20,15 +20,11 @@ package org.apache.syncope.client.console.panels;
import java.io.Serializable;
import java.net.URI;
-import java.util.List;
-
import org.apache.syncope.client.console.rest.GatewayRouteRestClient;
import org.apache.syncope.client.console.wizards.BaseAjaxWizardBuilder;
-import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxDropDownChoicePanel;
import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxSpinnerFieldPanel;
import
org.apache.syncope.client.ui.commons.markup.html.form.AjaxTextFieldPanel;
import org.apache.syncope.common.lib.to.GatewayRouteTO;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.wicket.PageReference;
import org.apache.wicket.extensions.wizard.WizardModel;
import org.apache.wicket.extensions.wizard.WizardStep;
@@ -100,10 +96,6 @@ public class GatewayRouteWizardBuilder extends
BaseAjaxWizardBuilder<GatewayRout
target.addRequiredLabel().setEnabled(true);
target.getField().add(new UrlValidator(new String[] { "http",
"https" }));
add(target);
-
- add(new AjaxDropDownChoicePanel<>(
- "status", "status", new PropertyModel<>(route, "status")).
- setChoices(List.of((Serializable[])
GatewayRouteStatus.values())));
}
}
diff --git
a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
index 382d1fb..85e6968 100644
---
a/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
+++
b/client/am/console/src/main/resources/org/apache/syncope/client/console/panels/GatewayRouteWizardBuilder$Profile.html
@@ -21,6 +21,5 @@ under the License.
<div class="form-group"><span wicket:id="name">[name]</span></div>
<div class="form-group"><span wicket:id="order">[order]</span></div>
<div class="form-group"><span wicket:id="target">[target]</span></div>
- <div class="form-group"><span wicket:id="status">[status]</span></div>
</wicket:panel>
</html>
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
index fe8d987..8249c87 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/to/GatewayRouteTO.java
@@ -26,7 +26,6 @@ import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
public class GatewayRouteTO implements NamedEntityTO {
@@ -44,8 +43,6 @@ public class GatewayRouteTO implements NamedEntityTO {
private final List<GatewayRoutePredicate> predicates = new ArrayList<>();
- private GatewayRouteStatus status;
-
@Override
public String getKey() {
return key;
@@ -91,14 +88,6 @@ public class GatewayRouteTO implements NamedEntityTO {
return predicates;
}
- public GatewayRouteStatus getStatus() {
- return status;
- }
-
- public void setStatus(final GatewayRouteStatus status) {
- this.status = status;
- }
-
@Override
public int hashCode() {
return new HashCodeBuilder().
@@ -107,7 +96,6 @@ public class GatewayRouteTO implements NamedEntityTO {
append(target).
append(filters).
append(predicates).
- append(status).
build();
}
@@ -129,7 +117,6 @@ public class GatewayRouteTO implements NamedEntityTO {
append(target, other.target).
append(filters, other.filters).
append(predicates, other.predicates).
- append(status, other.status).
build();
}
}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/FilterFactory.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/FilterFactory.java
index 5d71698..e7d1403 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/FilterFactory.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/FilterFactory.java
@@ -42,6 +42,9 @@ public enum FilterFactory {
STRIP_PREFIX,
REQUEST_HEADER_TO_REQUEST_URI,
SET_REQUEST_SIZE,
+ LINK_REWRITE,
+ CLIENT_CERTS_TO_REQUEST_HEADER,
+ QUERY_PARAM_TO_REQUEST_HEADER,
CUSTOM
}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicate.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicate.java
index 2c0c3c7..2a19a5f 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicate.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicate.java
@@ -35,7 +35,7 @@ public class GatewayRoutePredicate implements BaseBean {
return this;
}
- public Builder cond(final PredicateCond cond) {
+ public Builder cond(final GatewayRoutePredicateCond cond) {
instance.setCond(cond);
return this;
}
@@ -57,7 +57,7 @@ public class GatewayRoutePredicate implements BaseBean {
private boolean negate;
- private PredicateCond cond;
+ private GatewayRoutePredicateCond cond;
private PredicateFactory factory;
@@ -71,11 +71,11 @@ public class GatewayRoutePredicate implements BaseBean {
this.negate = negate;
}
- public PredicateCond getCond() {
+ public GatewayRoutePredicateCond getCond() {
return cond;
}
- public void setCond(final PredicateCond cond) {
+ public void setCond(final GatewayRoutePredicateCond cond) {
this.cond = cond;
}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PredicateCond.java
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicateCond.java
similarity index 95%
rename from
common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PredicateCond.java
rename to
common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicateCond.java
index c62ff78..843659d 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/PredicateCond.java
+++
b/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRoutePredicateCond.java
@@ -18,7 +18,7 @@
*/
package org.apache.syncope.common.lib.types;
-public enum PredicateCond {
+public enum GatewayRoutePredicateCond {
AND,
OR
diff --git
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GatewayRoute.java
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GatewayRoute.java
index 4aef3f7..cf04b4e 100644
---
a/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GatewayRoute.java
+++
b/core/persistence-api/src/main/java/org/apache/syncope/core/persistence/api/entity/GatewayRoute.java
@@ -22,7 +22,6 @@ import java.net.URI;
import java.util.List;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
public interface GatewayRoute extends Entity {
@@ -45,8 +44,4 @@ public interface GatewayRoute extends Entity {
List<GatewayRoutePredicate> getPredicates();
void setPredicates(List<GatewayRoutePredicate> predicates);
-
- GatewayRouteStatus getStatus();
-
- void setStatus(GatewayRouteStatus status);
}
diff --git
a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
index b0053e4..ca04393 100644
--- a/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa-json/src/test/resources/domains/MasterContent.xml
@@ -2378,8 +2378,7 @@ $$ }
<SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's
your mother's maiden name?"/>
- <GatewayRoute id="ec7bada2-3dd6-460c-8441-65521d005ffa" name="basic1"
target="http://httpbin.org:80" status="PUBLISHED"
-
predicates="[{"cond":null,"factory":"METHOD","args":"GET"}]"/>
+ <GatewayRoute id="ec7bada2-3dd6-460c-8441-65521d005ffa" name="basic1"
target="http://httpbin.org:80"
predicates="[{"cond":null,"factory":"METHOD","args":"GET"}]"/>
<SyncopeLogger logType="AUDIT"
logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]"
logLevel="DEBUG"/>
diff --git
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAGatewayRoute.java
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAGatewayRoute.java
index 9b938fb..9970ff3 100644
---
a/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAGatewayRoute.java
+++
b/core/persistence-jpa/src/main/java/org/apache/syncope/core/persistence/jpa/entity/JPAGatewayRoute.java
@@ -24,14 +24,11 @@ import java.util.Optional;
import javax.persistence.Column;
import javax.persistence.Entity;
-import javax.persistence.EnumType;
-import javax.persistence.Enumerated;
import javax.persistence.Lob;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.syncope.core.persistence.api.entity.GatewayRoute;
import
org.apache.syncope.core.persistence.jpa.validation.entity.GatewayRouteCheck;
import org.apache.syncope.core.provisioning.api.serialization.POJOHelper;
@@ -59,10 +56,6 @@ public class JPAGatewayRoute extends
AbstractGeneratedKeyEntity implements Gatew
@Lob
private String filters;
- @NotNull
- @Enumerated(EnumType.STRING)
- private GatewayRouteStatus status;
-
@Override
public String getName() {
return name;
@@ -116,14 +109,4 @@ public class JPAGatewayRoute extends
AbstractGeneratedKeyEntity implements Gatew
public void setPredicates(final List<GatewayRoutePredicate> predicates) {
this.predicates = POJOHelper.serialize(predicates);
}
-
- @Override
- public GatewayRouteStatus getStatus() {
- return status;
- }
-
- @Override
- public void setStatus(final GatewayRouteStatus status) {
- this.status = status;
- }
}
diff --git
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/GatewayRouteTest.java
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/GatewayRouteTest.java
index abdf50d..36b7b09 100644
---
a/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/GatewayRouteTest.java
+++
b/core/persistence-jpa/src/test/java/org/apache/syncope/core/persistence/jpa/inner/GatewayRouteTest.java
@@ -29,7 +29,6 @@ import javax.ws.rs.HttpMethod;
import org.apache.syncope.common.lib.types.FilterFactory;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.syncope.common.lib.types.PredicateFactory;
import org.apache.syncope.core.persistence.api.dao.GatewayRouteDAO;
import org.apache.syncope.core.persistence.api.entity.GatewayRoute;
@@ -48,7 +47,6 @@ public class GatewayRouteTest extends AbstractTest {
public void find() {
GatewayRoute route =
routeDAO.find("ec7bada2-3dd6-460c-8441-65521d005ffa");
assertNotNull(route);
- assertEquals(GatewayRouteStatus.PUBLISHED, route.getStatus());
assertEquals(1, route.getPredicates().size());
route = routeDAO.find(UUID.randomUUID().toString());
@@ -71,7 +69,6 @@ public class GatewayRouteTest extends AbstractTest {
factory(PredicateFactory.METHOD).args(HttpMethod.GET).build()));
route.setFilters(List.of(new GatewayRouteFilter.Builder().
factory(FilterFactory.ADD_REQUEST_HEADER).args("X-Request-Foo,
Bar").build()));
- route.setStatus(GatewayRouteStatus.DRAFT);
int beforeCount = routeDAO.findAll().size();
diff --git a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
index 890cf97..34a8718 100644
--- a/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
+++ b/core/persistence-jpa/src/test/resources/domains/MasterContent.xml
@@ -2465,7 +2465,7 @@ $$ }
<SecurityQuestion id="887028ea-66fc-41e7-b397-620d7ea6dfbb" content="What's
your mother's maiden name?"/>
- <GatewayRoute id="ec7bada2-3dd6-460c-8441-65521d005ffa" name="basic1"
target="http://httpbin.org:80" status="PUBLISHED"
predicates="[{"cond":null,"factory":"METHOD","args":"GET"}]"/>
+ <GatewayRoute id="ec7bada2-3dd6-460c-8441-65521d005ffa" name="basic1"
target="http://httpbin.org:80"
predicates="[{"cond":null,"factory":"METHOD","args":"GET"}]"/>
<SyncopeLogger logType="AUDIT"
logName="syncope.audit.[LOGIC]:[SyncopeLogic]:[]:[isSelfRegAllowed]:[SUCCESS]"
logLevel="DEBUG"/>
diff --git
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GatewayRouteDataBinderImpl.java
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GatewayRouteDataBinderImpl.java
index 0259510..a086cfb 100644
---
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GatewayRouteDataBinderImpl.java
+++
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/GatewayRouteDataBinderImpl.java
@@ -22,7 +22,6 @@ import org.apache.commons.lang3.StringUtils;
import org.apache.syncope.common.lib.SyncopeClientException;
import org.apache.syncope.common.lib.to.GatewayRouteTO;
import org.apache.syncope.common.lib.types.ClientExceptionType;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.syncope.core.persistence.api.entity.GatewayRoute;
import org.apache.syncope.core.provisioning.api.data.GatewayRouteDataBinder;
import org.springframework.stereotype.Component;
@@ -48,7 +47,6 @@ public class GatewayRouteDataBinderImpl implements
GatewayRouteDataBinder {
route.setTarget(routeTO.getTarget());
route.setFilters(routeTO.getFilters());
route.setPredicates(routeTO.getPredicates());
- route.setStatus(routeTO.getStatus() == null ? GatewayRouteStatus.DRAFT
: routeTO.getStatus());
}
@Override
@@ -60,7 +58,6 @@ public class GatewayRouteDataBinderImpl implements
GatewayRouteDataBinder {
routeTO.setTarget(route.getTarget());
routeTO.getFilters().addAll(route.getFilters());
routeTO.getPredicates().addAll(route.getPredicates());
- routeTO.setStatus(route.getStatus());
return routeTO;
}
diff --git
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GatewayRouteITCase.java
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GatewayRouteITCase.java
index 4994066..76ac2be 100644
---
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GatewayRouteITCase.java
+++
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/GatewayRouteITCase.java
@@ -34,7 +34,6 @@ import
org.apache.syncope.common.lib.types.ClientExceptionType;
import org.apache.syncope.common.lib.types.FilterFactory;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.syncope.common.lib.types.PredicateFactory;
import org.apache.syncope.common.rest.api.service.GatewayRouteService;
import org.apache.syncope.fit.AbstractITCase;
@@ -46,7 +45,6 @@ public class GatewayRouteITCase extends AbstractITCase {
public void read() {
GatewayRouteTO route =
gatewayRouteService.read("ec7bada2-3dd6-460c-8441-65521d005ffa");
assertNotNull(route);
- assertEquals(GatewayRouteStatus.PUBLISHED, route.getStatus());
assertEquals(1, route.getPredicates().size());
try {
@@ -73,7 +71,6 @@ public class GatewayRouteITCase extends AbstractITCase {
factory(PredicateFactory.METHOD).args(HttpMethod.GET).build());
route.getFilters().add(new GatewayRouteFilter.Builder().
factory(FilterFactory.ADD_REQUEST_HEADER).args("X-Request-Foo,
Bar").build());
- route.setStatus(GatewayRouteStatus.DRAFT);
int beforeCount = gatewayRouteService.list().size();
@@ -86,11 +83,6 @@ public class GatewayRouteITCase extends AbstractITCase {
int afterCount = gatewayRouteService.list().size();
assertEquals(afterCount, beforeCount + 1);
- route.setStatus(GatewayRouteStatus.STAGING);
- gatewayRouteService.update(route);
- route = gatewayRouteService.read(route.getKey());
- assertEquals(GatewayRouteStatus.STAGING, route.getStatus());
-
gatewayRouteService.delete(route.getKey());
try {
diff --git a/pom.xml b/pom.xml
index 413a1f6..3104a45 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1993,6 +1993,12 @@ under the License.
<version>8.19</version>
</dependency>
+ <dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ <version>1.13.1</version>
+ </dependency>
+
<!-- TEST -->
<dependency>
<groupId>org.apache.curator</groupId>
diff --git a/sra/pom.xml b/sra/pom.xml
index b98503d..53275d4 100644
--- a/sra/pom.xml
+++ b/sra/pom.xml
@@ -77,6 +77,11 @@ under the License.
</dependency>
<dependency>
+ <groupId>org.jsoup</groupId>
+ <artifactId>jsoup</artifactId>
+ </dependency>
+
+ <dependency>
<groupId>org.apache.syncope.common.keymaster</groupId>
<artifactId>syncope-common-keymaster-client-api</artifactId>
<version>${project.version}</version>
@@ -180,6 +185,18 @@ under the License.
<testResource>
<directory>${basedir}/src/test/resources</directory>
<filtering>true</filtering>
+ <excludes>
+ <exclude>*.p12</exclude>
+ <exclude>*.jks</exclude>
+ </excludes>
+ </testResource>
+ <testResource>
+ <directory>${basedir}/src/test/resources</directory>
+ <filtering>false</filtering>
+ <includes>
+ <include>*.p12</include>
+ <include>*.jks</include>
+ </includes>
</testResource>
</testResources>
</build>
diff --git
a/sra/src/main/java/org/apache/syncope/sra/ApplicationContextUtils.java
b/sra/src/main/java/org/apache/syncope/sra/ApplicationContextUtils.java
new file mode 100644
index 0000000..e042b26
--- /dev/null
+++ b/sra/src/main/java/org/apache/syncope/sra/ApplicationContextUtils.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra;
+
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.BeanDefinitionRegistry;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.ConfigurableApplicationContext;
+
+public final class ApplicationContextUtils {
+
+ public static <T> T getOrCreateBean(
+ final ConfigurableApplicationContext ctx,
+ final String actualClazz,
+ final Class<T> type) throws ClassNotFoundException {
+
+ T bean;
+ if (ctx.getBeanFactory().containsSingleton(actualClazz)) {
+ bean = type.cast(ctx.getBeanFactory().getSingleton(actualClazz));
+ } else {
+ if (ApplicationListener.class.isAssignableFrom(type)) {
+ RootBeanDefinition bd = new RootBeanDefinition(
+ Class.forName(actualClazz),
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
+ bd.setScope(BeanDefinition.SCOPE_SINGLETON);
+ ((BeanDefinitionRegistry)
ctx.getBeanFactory()).registerBeanDefinition(actualClazz, bd);
+ bean = ctx.getBean(type);
+ } else {
+ bean = type.cast(ctx.getBeanFactory().
+ createBean(Class.forName(actualClazz),
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false));
+ ctx.getBeanFactory().registerSingleton(actualClazz, bean);
+ }
+ }
+ return bean;
+ }
+
+ private ApplicationContextUtils() {
+ // private constructor for static utility class
+ }
+}
diff --git a/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
b/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
index fb6c37c..00c1ac8 100644
--- a/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
+++ b/sra/src/main/java/org/apache/syncope/sra/RouteProvider.java
@@ -19,8 +19,10 @@
package org.apache.syncope.sra;
import java.time.ZonedDateTime;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.apache.commons.lang3.BooleanUtils;
@@ -33,13 +35,16 @@ import
org.apache.syncope.common.keymaster.client.api.model.NetworkService;
import org.apache.syncope.common.lib.to.GatewayRouteTO;
import org.apache.syncope.common.lib.types.GatewayRouteFilter;
import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
import org.apache.syncope.common.rest.api.service.GatewayRouteService;
+import org.apache.syncope.sra.filters.ClientCertsToRequestHeaderFilterFactory;
+import org.apache.syncope.sra.filters.CustomGatewayFilterFactory;
+import org.apache.syncope.sra.filters.LinkRewriteGatewayFilterFactory;
+import org.apache.syncope.sra.filters.QueryParamToRequestHeaderFilterFactory;
+import org.apache.syncope.sra.predicates.CustomRoutePredicateFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
-import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import
org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
@@ -110,7 +115,7 @@ public class RouteProvider {
private SyncopeClient client;
@SuppressWarnings("unchecked")
- private GatewayFilter toFilter(final String routeId, final
GatewayRouteFilter gwfilter)
+ private GatewayFilter toFilter(final GatewayRouteTO route, final
GatewayRouteFilter gwfilter)
throws ClassNotFoundException {
GatewayFilter filter;
@@ -140,7 +145,7 @@ public class RouteProvider {
case HYSTRIX:
String[] hystrixArgs = gwfilter.getArgs().split(",");
filter = ctx.getBean(HystrixGatewayFilterFactory.class).
- apply(routeId, c -> {
+ apply(route.getKey(), c -> {
if (StringUtils.isNotBlank(hystrixArgs[0])) {
c.setName(hystrixArgs[0].trim());
}
@@ -285,17 +290,43 @@ public class RouteProvider {
apply(c ->
c.setMaxSize(DataSize.ofBytes(Long.valueOf(gwfilter.getArgs().trim()))));
break;
+ case LINK_REWRITE:
+ filter = ApplicationContextUtils.getOrCreateBean(
+ ctx,
+ LinkRewriteGatewayFilterFactory.class.getName(),
+ LinkRewriteGatewayFilterFactory.class).
+ apply(c -> c.setData(route.getTarget().toASCIIString()
+ "," + gwfilter.getArgs().trim()));
+ break;
+
+ case CLIENT_CERTS_TO_REQUEST_HEADER:
+ String header = StringUtils.isBlank(gwfilter.getArgs()) ?
"X-Client-Certificate" : gwfilter.getArgs();
+ filter = ApplicationContextUtils.getOrCreateBean(
+ ctx,
+
ClientCertsToRequestHeaderFilterFactory.class.getName(),
+ ClientCertsToRequestHeaderFilterFactory.class).
+ apply(c -> c.setName(header.trim()));
+ break;
+
+ case QUERY_PARAM_TO_REQUEST_HEADER:
+ filter = ApplicationContextUtils.getOrCreateBean(
+ ctx,
+ QueryParamToRequestHeaderFilterFactory.class.getName(),
+ QueryParamToRequestHeaderFilterFactory.class).
+ apply(c -> c.setName(gwfilter.getArgs().trim()));
+ break;
+
case CUSTOM:
String[] customArgs = gwfilter.getArgs().split(";");
- CustomGatewayFilterFactory factory;
- if (ctx.getBeanFactory().containsSingleton(customArgs[0])) {
- factory = (CustomGatewayFilterFactory)
ctx.getBeanFactory().getSingleton(customArgs[0]);
- } else {
- factory = (CustomGatewayFilterFactory)
ctx.getBeanFactory().
- createBean(Class.forName(customArgs[0]),
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
- ctx.getBeanFactory().registerSingleton(customArgs[0],
factory);
- }
- filter = factory.apply(c -> c.setData(customArgs[1]));
+ Consumer<CustomGatewayFilterFactory.Config> customConsumer =
customArgs.length > 1
+ ? c -> c.setData(customArgs[1])
+ : c -> c.setData(null);
+ CustomGatewayFilterFactory factory =
ApplicationContextUtils.getOrCreateBean(
+ ctx,
+ customArgs[0],
+ CustomGatewayFilterFactory.class);
+ filter = factory.getOrder().
+ map(order -> (GatewayFilter) new
OrderedGatewayFilter(factory.apply(customConsumer), order)).
+ orElseGet(() -> factory.apply(customConsumer));
break;
default:
@@ -339,14 +370,16 @@ public class RouteProvider {
break;
case HEADER:
+ String[] headerArgs = gwpredicate.getArgs().split(",");
predicate = ctx.getBean(HeaderRoutePredicateFactory.class).
- applyAsync(c ->
c.setHeader(gwpredicate.getArgs().trim()));
+ applyAsync(c -> c.setHeader(headerArgs[0].trim()).
+ setRegexp(headerArgs[1].trim()));
break;
case HOST:
String[] hostArgs = gwpredicate.getArgs().split(",");
predicate = ctx.getBean(HostRoutePredicateFactory.class).
- applyAsync(c -> c.setPatterns(List.of(hostArgs)));
+ applyAsync(c ->
c.setPatterns(Arrays.asList(hostArgs)));
break;
case METHOD:
@@ -359,33 +392,32 @@ public class RouteProvider {
case PATH:
String[] pathArgs = gwpredicate.getArgs().split(",");
predicate = ctx.getBean(PathRoutePredicateFactory.class).
- applyAsync(c -> c.setPatterns(List.of(pathArgs)));
+ applyAsync(c ->
c.setPatterns(Arrays.asList(pathArgs)));
break;
case QUERY:
String[] queryArgs = gwpredicate.getArgs().split(",");
+ Consumer<QueryRoutePredicateFactory.Config> queryConsumer =
+ queryArgs.length > 1
+ ? c ->
c.setParam(queryArgs[0].trim()).setRegexp(queryArgs[1].trim())
+ : c -> c.setParam(queryArgs[0].trim());
predicate = ctx.getBean(QueryRoutePredicateFactory.class).
- applyAsync(c -> c.setParam(queryArgs[0].trim()).
- setRegexp(queryArgs[1].trim()));
+ applyAsync(queryConsumer);
break;
case REMOTE_ADDR:
String[] remoteAddrArgs = gwpredicate.getArgs().split(",");
predicate = ctx.getBean(RemoteAddrRoutePredicateFactory.class).
- applyAsync(c -> c.setSources(List.of(remoteAddrArgs)));
+ applyAsync(c ->
c.setSources(Arrays.asList(remoteAddrArgs)));
break;
case CUSTOM:
String[] customArgs = gwpredicate.getArgs().split(";");
- CustomRoutePredicateFactory factory;
- if (ctx.getBeanFactory().containsSingleton(customArgs[0])) {
- factory = (CustomRoutePredicateFactory)
ctx.getBeanFactory().getSingleton(customArgs[0]);
- } else {
- factory = (CustomRoutePredicateFactory)
ctx.getBeanFactory().
- createBean(Class.forName(customArgs[0]),
AbstractBeanDefinition.AUTOWIRE_BY_TYPE, false);
- ctx.getBeanFactory().registerSingleton(customArgs[0],
factory);
- }
- predicate = factory.applyAsync(c -> c.setData(customArgs[1]));
+ predicate = ApplicationContextUtils.getOrCreateBean(
+ ctx,
+ customArgs[0],
+ CustomRoutePredicateFactory.class).
+ applyAsync(c -> c.setData(customArgs[1]));
break;
default:
@@ -393,13 +425,10 @@ public class RouteProvider {
}
if (predicate == null) {
- throw new IllegalArgumentException("Could not translate " +
gwpredicate);
+ throw new IllegalArgumentException("Could not translate predicate
" + gwpredicate);
}
- if (negate) {
- predicate.negate();
- }
- return predicate;
+ return negate ? predicate.negate() : predicate;
}
private Route.AsyncBuilder toRoute(final GatewayRouteTO gwroute) {
@@ -438,7 +467,7 @@ public class RouteProvider {
builder.filters(gwroute.getFilters().stream().
map(gwfilter -> {
try {
- return toFilter(gwroute.getKey(), gwfilter);
+ return toFilter(gwroute, gwfilter);
} catch (Exception e) {
LOG.error("Could not translate {}, skipping",
gwfilter, e);
return null;
@@ -467,7 +496,6 @@ public class RouteProvider {
}
return client.getService(GatewayRouteService.class).list().stream().
- filter(gwroute -> gwroute.getStatus() ==
GatewayRouteStatus.PUBLISHED).
map(this::toRoute).
collect(Collectors.toList());
}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
similarity index 63%
copy from sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
copy to sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
index 3f56eb4..b11a7ac 100644
--- a/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
+++ b/sra/src/main/java/org/apache/syncope/sra/SecurityConfig.java
@@ -19,20 +19,11 @@
package org.apache.syncope.sra;
import java.util.Objects;
-import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
-import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
-import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.SpringApplication;
import
org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
-import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.cloud.gateway.route.Route;
-import org.springframework.cloud.gateway.route.RouteLocator;
-import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
-import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.PropertySource;
+import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import
org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
@@ -42,43 +33,14 @@ import
org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.server.SecurityWebFilterChain;
import
org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
import
org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
-import reactor.core.publisher.Flux;
-@PropertySource("classpath:sra.properties")
-@PropertySource(value = "file:${conf.directory}/sra.properties",
ignoreResourceNotFound = true)
@EnableWebFluxSecurity
-@SpringBootApplication
-public class SyncopeSRAApplication implements EnvironmentAware {
-
- public static void main(final String[] args) {
- SpringApplication.run(SyncopeSRAApplication.class, args);
- }
+@Configuration
+public class SecurityConfig {
@Autowired
- private RouteProvider provider;
-
private Environment env;
- @Override
- public void setEnvironment(final Environment env) {
- this.env = env;
- }
-
- @Bean
- public KeymasterStart keymasterStart() {
- return new KeymasterStart(NetworkService.Type.SRA);
- }
-
- @Bean
- public KeymasterStop keymasterStop() {
- return new KeymasterStop(NetworkService.Type.SRA);
- }
-
- @Bean
- public RouteLocator routes(final RouteLocatorBuilder builder) {
- return () ->
Flux.fromIterable(provider.fetch()).map(Route.AbstractBuilder::build);
- }
-
@Bean
public SecurityWebFilterChain actuatorSecurityFilterChain(final
ServerHttpSecurity http) {
ServerWebExchangeMatcher actuatorMatcher =
EndpointRequest.toAnyEndpoint();
diff --git
a/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
b/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
index 3f56eb4..10785b1 100644
--- a/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
+++ b/sra/src/main/java/org/apache/syncope/sra/SyncopeSRAApplication.java
@@ -18,37 +18,23 @@
*/
package org.apache.syncope.sra;
-import java.util.Objects;
import org.apache.syncope.common.keymaster.client.api.model.NetworkService;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStart;
import org.apache.syncope.common.keymaster.client.api.startstop.KeymasterStop;
-import org.apache.syncope.common.lib.types.IdRepoEntitlement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
-import
org.springframework.boot.actuate.autoconfigure.security.reactive.EndpointRequest;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
-import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
-import org.springframework.core.env.Environment;
-import
org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
-import org.springframework.security.config.web.server.ServerHttpSecurity;
-import
org.springframework.security.core.userdetails.MapReactiveUserDetailsService;
-import org.springframework.security.core.userdetails.User;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.web.server.SecurityWebFilterChain;
-import
org.springframework.security.web.server.util.matcher.NegatedServerWebExchangeMatcher;
-import
org.springframework.security.web.server.util.matcher.ServerWebExchangeMatcher;
import reactor.core.publisher.Flux;
@PropertySource("classpath:sra.properties")
@PropertySource(value = "file:${conf.directory}/sra.properties",
ignoreResourceNotFound = true)
-@EnableWebFluxSecurity
@SpringBootApplication
-public class SyncopeSRAApplication implements EnvironmentAware {
+public class SyncopeSRAApplication {
public static void main(final String[] args) {
SpringApplication.run(SyncopeSRAApplication.class, args);
@@ -57,11 +43,9 @@ public class SyncopeSRAApplication implements
EnvironmentAware {
@Autowired
private RouteProvider provider;
- private Environment env;
-
- @Override
- public void setEnvironment(final Environment env) {
- this.env = env;
+ @Bean
+ public RouteLocator routes(final RouteLocatorBuilder builder) {
+ return () ->
Flux.fromIterable(provider.fetch()).map(Route.AbstractBuilder::build);
}
@Bean
@@ -73,29 +57,4 @@ public class SyncopeSRAApplication implements
EnvironmentAware {
public KeymasterStop keymasterStop() {
return new KeymasterStop(NetworkService.Type.SRA);
}
-
- @Bean
- public RouteLocator routes(final RouteLocatorBuilder builder) {
- return () ->
Flux.fromIterable(provider.fetch()).map(Route.AbstractBuilder::build);
- }
-
- @Bean
- public SecurityWebFilterChain actuatorSecurityFilterChain(final
ServerHttpSecurity http) {
- ServerWebExchangeMatcher actuatorMatcher =
EndpointRequest.toAnyEndpoint();
- return http.securityMatcher(actuatorMatcher).
- authorizeExchange().anyExchange().authenticated().
- and().httpBasic().
- and().csrf().requireCsrfProtectionMatcher(new
NegatedServerWebExchangeMatcher(actuatorMatcher)).
- and().build();
- }
-
- @Bean
- public MapReactiveUserDetailsService userDetailsService() {
- UserDetails user = User.builder().
-
username(Objects.requireNonNull(env.getProperty("anonymousUser"))).
- password("{noop}" + env.getProperty("anonymousKey")).
- roles(IdRepoEntitlement.ANONYMOUS).
- build();
- return new MapReactiveUserDetailsService(user);
- }
}
diff --git
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRouteStatus.java
b/sra/src/main/java/org/apache/syncope/sra/filters/AddRefererFilterFactory.java
similarity index 58%
rename from
common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRouteStatus.java
rename to
sra/src/main/java/org/apache/syncope/sra/filters/AddRefererFilterFactory.java
index 5155a1d..c8fa789 100644
---
a/common/am/lib/src/main/java/org/apache/syncope/common/lib/types/GatewayRouteStatus.java
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/AddRefererFilterFactory.java
@@ -16,12 +16,18 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.common.lib.types;
+package org.apache.syncope.sra.filters;
-public enum GatewayRouteStatus {
- DRAFT,
- STAGING,
- PUBLISHED,
- DEPRECATED
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.http.HttpHeaders;
+public class AddRefererFilterFactory extends CustomGatewayFilterFactory {
+
+ @Override
+ public GatewayFilter apply(final Config config) {
+ return (exchange, chain) -> chain.filter(exchange.mutate().request(
+ exchange.getRequest().mutate().headers(headers -> headers.add(
+ HttpHeaders.REFERER,
exchange.getRequest().getURI().toASCIIString())).build()).
+ build());
+ }
}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/filters/ClientCertsToRequestHeaderFilterFactory.java
b/sra/src/main/java/org/apache/syncope/sra/filters/ClientCertsToRequestHeaderFilterFactory.java
new file mode 100644
index 0000000..259535b
--- /dev/null
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/ClientCertsToRequestHeaderFilterFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra.filters;
+
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Base64;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+
+public class ClientCertsToRequestHeaderFilterFactory extends
AbstractGatewayFilterFactory<NameConfig> {
+
+ private static final Logger LOG =
LoggerFactory.getLogger(ClientCertsToRequestHeaderFilterFactory.class);
+
+ public ClientCertsToRequestHeaderFilterFactory() {
+ super(NameConfig.class);
+ }
+
+ @Override
+ public GatewayFilter apply(final NameConfig config) {
+ return (exchange, chain) -> {
+ ServerHttpRequest originalRequest = exchange.getRequest();
+
+ ServerHttpRequest mutatedRequest;
+ if (originalRequest.getSslInfo() != null
+ &&
ArrayUtils.isNotEmpty(originalRequest.getSslInfo().getPeerCertificates())) {
+
+ LOG.debug("Client certificates found in original request: {}",
+
originalRequest.getSslInfo().getPeerCertificates().length);
+
+ List<String> certs = new ArrayList<>();
+ for (X509Certificate cert :
originalRequest.getSslInfo().getPeerCertificates()) {
+ try {
+
certs.add(Base64.getEncoder().encodeToString(cert.getEncoded()));
+ } catch (CertificateEncodingException e) {
+ LOG.error("Could not encode one of client
certificates", e);
+ }
+ }
+
+ mutatedRequest = originalRequest.mutate().
+ headers(headers -> headers.addAll(config.getName(),
certs)).
+ sslInfo(null).
+ build();
+ } else {
+ mutatedRequest = originalRequest;
+ }
+
+ return
chain.filter(exchange.mutate().request(mutatedRequest).build());
+ };
+ }
+}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/CustomGatewayFilterFactory.java
b/sra/src/main/java/org/apache/syncope/sra/filters/CustomGatewayFilterFactory.java
similarity index 89%
rename from
sra/src/main/java/org/apache/syncope/sra/CustomGatewayFilterFactory.java
rename to
sra/src/main/java/org/apache/syncope/sra/filters/CustomGatewayFilterFactory.java
index 7ac2cd8..d15bc41 100644
--- a/sra/src/main/java/org/apache/syncope/sra/CustomGatewayFilterFactory.java
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/CustomGatewayFilterFactory.java
@@ -16,8 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.sra;
+package org.apache.syncope.sra.filters;
+import java.util.Optional;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
@@ -27,7 +28,7 @@ import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFac
public abstract class CustomGatewayFilterFactory
extends
AbstractGatewayFilterFactory<CustomGatewayFilterFactory.Config> {
- public static class Config {
+ public static final class Config {
private String data;
@@ -44,6 +45,10 @@ public abstract class CustomGatewayFilterFactory
super(CustomGatewayFilterFactory.Config.class);
}
+ public Optional<Integer> getOrder() {
+ return Optional.empty();
+ }
+
@Override
public abstract GatewayFilter apply(Config config);
}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/filters/LinkRewriteGatewayFilterFactory.java
b/sra/src/main/java/org/apache/syncope/sra/filters/LinkRewriteGatewayFilterFactory.java
new file mode 100644
index 0000000..8120b0b
--- /dev/null
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/LinkRewriteGatewayFilterFactory.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra.filters;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
+import org.springframework.web.server.ServerWebExchange;
+
+public class LinkRewriteGatewayFilterFactory extends
ModifyResponseGatewayFilterFactory {
+
+ @Override
+ protected boolean skipCond(final ServerHttpResponseDecorator decorator) {
+ return decorator.getHeaders().getContentType() == null
+ ||
!StringUtils.containsIgnoreCase(decorator.getHeaders().getContentType().toString(),
"html");
+ }
+
+ private Charset getCharset(final ServerHttpResponseDecorator decorator) {
+ return decorator.getHeaders().getContentType() != null
+ && decorator.getHeaders().getContentType().getCharset() != null
+ ? decorator.getHeaders().getContentType().getCharset()
+ : StandardCharsets.UTF_8;
+ }
+
+ private void replace(final Document doc, final String element, final
String attr, final String prefix) {
+ doc.select(element).forEach(link -> {
+ String attrValue = link.attributes().get(attr);
+ if (attrValue.startsWith("/") && !attrValue.startsWith("//")) {
+ link.attr(attr, attrValue.replace(attrValue, prefix +
attrValue));
+ }
+ });
+ }
+
+ @Override
+ protected byte[] modifyResponse(
+ final InputStream responseBody,
+ final Config config,
+ final ServerHttpResponseDecorator decorator,
+ final ServerWebExchange exchange)
+ throws IOException {
+
+ String[] keyValue = config.getData().split(",");
+
+ String oldBase = StringUtils.appendIfMissing(keyValue[0], "/");
+ String newBase = StringUtils.appendIfMissing(keyValue[1], "/");
+ String newBaseAsPrefix = StringUtils.removeEnd(keyValue[1], "/");
+
+ boolean rewriterRootAttrs = true;
+ if (keyValue.length == 3) {
+ rewriterRootAttrs = BooleanUtils.toBoolean(keyValue[2]);
+ }
+
+ Document doc = Jsoup.parse(
+ responseBody, getCharset(decorator).name(),
exchange.getRequest().getURI().toASCIIString());
+
+ if (rewriterRootAttrs) {
+ replace(doc, "a", "href", newBaseAsPrefix);
+ replace(doc, "link", "href", newBaseAsPrefix);
+ replace(doc, "img", "src", newBaseAsPrefix);
+ replace(doc, "script", "src", newBaseAsPrefix);
+ replace(doc, "object", "data", newBaseAsPrefix);
+ }
+
+ return doc.toString().replace(oldBase, newBase).getBytes();
+ }
+}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/filters/ModifyResponseGatewayFilterFactory.java
b/sra/src/main/java/org/apache/syncope/sra/filters/ModifyResponseGatewayFilterFactory.java
new file mode 100644
index 0000000..36f3d00
--- /dev/null
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/ModifyResponseGatewayFilterFactory.java
@@ -0,0 +1,155 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra.filters;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import org.reactivestreams.Publisher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.core.io.buffer.DataBufferUtils;
+import org.springframework.core.io.buffer.PooledDataBuffer;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * Inspired by {@link
org.springframework.cloud.gateway.filter.factory.rewrite.ModifyResponseBodyGatewayFilterFactory}.
+ */
+public abstract class ModifyResponseGatewayFilterFactory extends
CustomGatewayFilterFactory {
+
+ protected static final Logger LOG =
LoggerFactory.getLogger(ModifyResponseGatewayFilterFactory.class);
+
+ @Override
+ public GatewayFilter apply(final Config config) {
+ return new InternalModifyResponseGatewayFilter(config);
+ }
+
+ protected abstract byte[] modifyResponse(
+ InputStream responseBody,
+ Config config,
+ ServerHttpResponseDecorator decorator,
+ ServerWebExchange exchange)
+ throws IOException;
+
+ protected boolean skipCond(final ServerHttpResponseDecorator decorator) {
+ LOG.debug("Decorator: {}", decorator);
+ return false;
+ }
+
+ protected class InternalModifyResponseGatewayFilter implements
GatewayFilter, Ordered {
+
+ private final Config config;
+
+ public InternalModifyResponseGatewayFilter(final Config config) {
+ this.config = config;
+ }
+
+ @Override
+ public Mono<Void> filter(final ServerWebExchange exchange, final
GatewayFilterChain chain) {
+ return
chain.filter(exchange.mutate().response(decorate(exchange)).build());
+ }
+
+ @SuppressWarnings("squid:S3776")
+ private ServerHttpResponse decorate(final ServerWebExchange exchange) {
+ return new ServerHttpResponseDecorator(exchange.getResponse()) {
+
+ @SuppressWarnings("squid:S3358")
+ @Override
+ public Mono<Void> writeWith(final Publisher<? extends
DataBuffer> body) {
+ return skipCond(this)
+ ? super.writeWith(body)
+ : super.writeWith(Flux.from(body).
+ collectList().
+ filter(list -> !list.isEmpty()).
+ map(list ->
list.get(0).factory().join(list)).
+ doOnDiscard(PooledDataBuffer.class,
DataBufferUtils::release).
+ map(dataBuffer -> {
+ if (dataBuffer.readableByteCount() >
0) {
+ LOG.trace("Retaining body in
exchange attribute");
+ exchange.getAttributes().put(
+
ServerWebExchangeUtils.CACHED_REQUEST_BODY_ATTR, dataBuffer);
+ }
+
+ boolean inputCompressed = false;
+ if (dataBuffer.readableByteCount() >=
2) {
+ byte[] first2 = new byte[2];
+ dataBuffer.read(first2, 0, 2);
+ dataBuffer.readPosition(0);
+
+ inputCompressed = ((first2[0] ==
(byte) (GZIPInputStream.GZIP_MAGIC))
+ && (first2[1] == (byte)
(GZIPInputStream.GZIP_MAGIC >> 8)));
+ }
+
+ boolean outputCompressed = false;
+ byte[] output;
+ try (InputStream is = inputCompressed
+ ? new
GZIPInputStream(dataBuffer.asInputStream())
+ : dataBuffer.asInputStream()) {
+
+ outputCompressed = is instanceof
GZIPInputStream;
+
+ output = modifyResponse(is,
config, this, exchange);
+ } catch (IOException e) {
+ LOG.error("While modifying
response", e);
+
+ output = new
byte[dataBuffer.readableByteCount()];
+ dataBuffer.read(output);
+ }
+
+ if (outputCompressed) {
+ try (ByteArrayOutputStream baos =
new ByteArrayOutputStream(output.length);
+ GZIPOutputStream gzipos =
new GZIPOutputStream(baos)) {
+
+ gzipos.write(output);
+ gzipos.finish();
+ output = baos.toByteArray();
+ } catch (IOException e) {
+ LOG.error("While GZIP-encoding
output", e);
+ }
+ }
+
+ return
exchange.getResponse().bufferFactory().wrap(output);
+ }));
+ }
+
+ @Override
+ public Mono<Void> writeAndFlushWith(final Publisher<? extends
Publisher<? extends DataBuffer>> body) {
+ return writeWith(Flux.from(body).flatMapSequential(p ->
p));
+ }
+ };
+ }
+
+ @Override
+ public int getOrder() {
+ return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1;
+ }
+ }
+}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/filters/QueryParamToRequestHeaderFilterFactory.java
b/sra/src/main/java/org/apache/syncope/sra/filters/QueryParamToRequestHeaderFilterFactory.java
new file mode 100644
index 0000000..85975f3
--- /dev/null
+++
b/sra/src/main/java/org/apache/syncope/sra/filters/QueryParamToRequestHeaderFilterFactory.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra.filters;
+
+import java.net.URI;
+import org.springframework.cloud.gateway.filter.GatewayFilter;
+import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
+import
org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory.NameConfig;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.web.util.UriComponentsBuilder;
+
+public class QueryParamToRequestHeaderFilterFactory extends
AbstractGatewayFilterFactory<NameConfig> {
+
+ public QueryParamToRequestHeaderFilterFactory() {
+ super(NameConfig.class);
+ }
+
+ @Override
+ public GatewayFilter apply(final NameConfig config) {
+ return (exchange, chain) -> {
+ ServerHttpRequest originalRequest = exchange.getRequest();
+
+ ServerHttpRequest mutatedRequest;
+ if (originalRequest.getQueryParams().isEmpty()) {
+ mutatedRequest = originalRequest;
+ } else {
+ URI newUri =
UriComponentsBuilder.fromUri(originalRequest.getURI()).
+ replaceQueryParam(config.getName()).build().toUri();
+
+ mutatedRequest = exchange.getRequest().mutate().
+ uri(newUri).
+ headers(headers -> headers.addAll(
+ config.getName(),
originalRequest.getQueryParams().get(config.getName()))).
+ build();
+ }
+
+ return
chain.filter(exchange.mutate().request(mutatedRequest).build());
+ };
+ }
+}
diff --git
a/sra/src/main/java/org/apache/syncope/sra/CustomRoutePredicateFactory.java
b/sra/src/main/java/org/apache/syncope/sra/predicates/CustomRoutePredicateFactory.java
similarity index 97%
rename from
sra/src/main/java/org/apache/syncope/sra/CustomRoutePredicateFactory.java
rename to
sra/src/main/java/org/apache/syncope/sra/predicates/CustomRoutePredicateFactory.java
index 22d9299..992eab8 100644
--- a/sra/src/main/java/org/apache/syncope/sra/CustomRoutePredicateFactory.java
+++
b/sra/src/main/java/org/apache/syncope/sra/predicates/CustomRoutePredicateFactory.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.sra;
+package org.apache.syncope.sra.predicates;
import java.util.function.Predicate;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
diff --git a/sra/src/test/java/org/apache/syncope/sra/AbstractTest.java
b/sra/src/test/java/org/apache/syncope/sra/AbstractTest.java
new file mode 100644
index 0000000..c6a3ee2
--- /dev/null
+++ b/sra/src/test/java/org/apache/syncope/sra/AbstractTest.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import java.io.IOException;
+import java.net.Socket;
+import java.util.Base64;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
+import org.springframework.test.context.ContextConfiguration;
+
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@ContextConfiguration(initializers = ZookeeperTestingServer.class)
+@AutoConfigureWireMock(port = 0)
+public abstract class AbstractTest {
+
+ protected static final ObjectMapper MAPPER = new
ObjectMapper().registerModule(new JavaTimeModule());
+
+ public static boolean available(int port) {
+ try (Socket ignored = new Socket("localhost", port)) {
+ return false;
+ } catch (IOException ignored) {
+ return true;
+ }
+ }
+
+ @Autowired
+ protected RouteRefresher routeRefresher;
+
+ @Value("${local.server.port}")
+ protected int gatewayPort;
+
+ @Value("${wiremock.server.port}")
+ protected int wiremockPort;
+
+ @Value("${anonymousUser}")
+ private String anonymousUser;
+
+ @Value("${anonymousKey}")
+ private String anonymousKey;
+
+ protected String basicAuthHeader() {
+ return "Basic " + Base64.getEncoder().encodeToString((anonymousUser +
":" + anonymousKey).getBytes());
+ }
+}
diff --git a/sra/src/test/java/org/apache/syncope/sra/ActuatorTest.java
b/sra/src/test/java/org/apache/syncope/sra/ActuatorTest.java
new file mode 100644
index 0000000..72a8432
--- /dev/null
+++ b/sra/src/test/java/org/apache/syncope/sra/ActuatorTest.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra;
+
+import javax.net.ssl.SSLException;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.actuate.endpoint.http.ActuatorMediaType;
+import org.springframework.http.HttpHeaders;
+import org.springframework.test.web.reactive.server.WebTestClient;
+
+public class ActuatorTest extends AbstractTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @Test
+ public void health() throws SSLException {
+ webClient.get().uri("/actuator/health").
+ exchange().expectStatus().isUnauthorized();
+
+ webClient.get().uri("/actuator/health").
+ header(HttpHeaders.AUTHORIZATION, basicAuthHeader()).
+ exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals(HttpHeaders.CONTENT_TYPE,
ActuatorMediaType.V3_JSON);
+ }
+
+ @Test
+ public void routes() throws SSLException {
+ webClient.get().uri("/actuator/gateway/routes").
+ exchange().expectStatus().isUnauthorized();
+
+ webClient.get().uri("/actuator/gateway/routes").
+ header(HttpHeaders.AUTHORIZATION, basicAuthHeader()).
+ exchange().expectStatus().isOk();
+ }
+
+ @Test
+ public void requests() throws SSLException {
+ webClient.get().uri("/actuator/metrics/gateway.requests").
+ exchange().expectStatus().isUnauthorized();
+
+ webClient.get().uri("/actuator/metrics/gateway.requests").
+ header(HttpHeaders.AUTHORIZATION, basicAuthHeader()).
+ exchange().expectStatus().isNotFound();
+ }
+}
diff --git a/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
b/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
new file mode 100644
index 0000000..4c778ee
--- /dev/null
+++ b/sra/src/test/java/org/apache/syncope/sra/RouteProviderTest.java
@@ -0,0 +1,647 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.equalTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.post;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import java.io.IOException;
+import java.net.URI;
+import java.time.ZonedDateTime;
+import org.apache.syncope.common.lib.to.GatewayRouteTO;
+import org.apache.syncope.common.lib.types.FilterFactory;
+import org.apache.syncope.common.lib.types.GatewayRouteFilter;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicateCond;
+import org.apache.syncope.common.lib.types.PredicateFactory;
+import org.apache.syncope.sra.filters.BodyPropertyAddingGatewayFilterFactory;
+import
org.apache.syncope.sra.predicates.BodyPropertyMatchingRoutePredicateFactory;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import org.springframework.web.reactive.function.BodyInserters;
+
+public class RouteProviderTest extends AbstractTest {
+
+ @Autowired
+ private WebTestClient webClient;
+
+ @BeforeEach
+ public void clearRoutes() {
+ SyncopeCoreTestingServer.ROUTES.clear();
+ }
+
+ @Test
+ public void root() {
+ webClient.get().exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void addResponseHeader() {
+ // 1. no mapping for URL
+
webClient.get().uri("/addResponseHeader").exchange().expectStatus().isNotFound();
+
+ // 2. stub for proxied URL
+ stubFor(get(urlEqualTo("/addResponseHeader")).willReturn(aResponse()));
+
+ // 3. create route configuration
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("addResponseHeader");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.METHOD).args("GET").build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.PATH).args("/addResponseHeader").cond(GatewayRoutePredicateCond.AND).build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Hello,World").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ // 4. now mapping works for URL
+ webClient.get().uri("/addResponseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Hello", "World");
+
+ // 5. update route configuration
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Hello,WorldZ").build());
+
+ routeRefresher.refresh();
+
+ // 6. mapping for URL is updated too
+ webClient.get().uri("/addResponseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Hello", "WorldZ");
+
+ // 7. update route configuration again
+ route.getFilters().clear();
+
+ routeRefresher.refresh();
+
+ // 8. mapping for URL is updated again
+ webClient.get().uri("/addResponseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().doesNotExist("Hello");
+ }
+
+ @Test
+ public void addRequestHeader() {
+
webClient.get().uri("/requestHeader").exchange().expectStatus().isNotFound();
+
+ stubFor(get(urlEqualTo("/requestHeader")).withHeader("Hello",
equalTo("World")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("requestHeader");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.REMOTE_ADDR).args("localhost").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_REQUEST_HEADER).args("Hello,World").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/requestHeader").exchange().expectStatus().isOk();
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_REQUEST_HEADER).args("Hello,Mondo").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/requestHeader").exchange().expectStatus().isNotFound();
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.REMOVE_REQUEST_HEADER).args("Hello").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/requestHeader").header("Hello",
"World").exchange().expectStatus().isNotFound();
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.SET_REQUEST_HEADER).args("Hello,
World").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/requestHeader").header("Hello",
"Mondo").exchange().expectStatus().isOk();
+ }
+
+ @Test
+ public void hystrix() {
+ webClient.get().uri("/fallback").exchange().
+ expectStatus().isOk().
+ expectBody().
+ consumeWith(response ->
assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
+
+ stubFor(get(urlEqualTo("/delay/3")).
+ willReturn(aResponse().
+ withBody("no fallback").
+ withFixedDelay(3000)));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("hystrix");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.HOST).args("*.hystrix.com").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.HYSTRIX).args("fallbackcmd,forward:/fallback").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/delay/3").
+ header(HttpHeaders.HOST, "www.hystrix.com").
+ exchange().
+ expectStatus().isOk().
+ expectBody().
+ consumeWith(response ->
assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
+ }
+
+ @Test
+ public void requestHeaderToRequestUri() {
+
webClient.get().uri("/requestHeaderToRequestUri").exchange().expectStatus().isNotFound();
+
+
stubFor(get(urlEqualTo("/requestHeaderToRequestUri")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("requestHeaderToRequestUri");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.REQUEST_HEADER_TO_REQUEST_URI).args("NewUri").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/requestHeaderToRequestUri").
+ header("NewUri", "http://localhost:" + wiremockPort +
"/requestHeaderToRequestUri").
+ exchange().expectStatus().isOk();
+ }
+
+ @Test
+ public void responseHeader() {
+
webClient.get().uri("/responseHeader").exchange().expectStatus().isNotFound();
+
+
stubFor(get(urlEqualTo("/responseHeader")).willReturn(aResponse().withHeader("Hello",
"World")));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("responseHeader");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.REMOVE_RESPONSE_HEADER).args("Hello").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/responseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().doesNotExist("Hello");
+
+ route.getFilters().clear();
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/responseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Hello", "World");
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.REWRITE_RESPONSE_HEADER).args("Hello,World,Mondo").build());
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/responseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Hello", "Mondo");
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.SET_RESPONSE_HEADER).args("Hello,Mondo").build());
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/responseHeader").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Hello", "Mondo");
+ }
+
+ @Test
+ public void addRequestParameter() {
+
webClient.get().uri("/addRequestParameter?Hello=World").exchange().expectStatus().isNotFound();
+
+
stubFor(get(urlEqualTo("/addRequestParameter?Hello=World")).withQueryParam("Hello",
equalTo("World")).
+ willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("addRequestParameter");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_REQUEST_PARAMETER).args("Hello,World").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/addRequestParameter").exchange().expectStatus().isOk();
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_REQUEST_PARAMETER).args("Hello,Mondo").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/addRequestParameter").exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void rewritePath() {
+ webClient.get().uri("/rewrite").exchange().expectStatus().isNotFound();
+
+ stubFor(get(urlEqualTo("/rewrite")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("rewrite");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.REWRITE_PATH).args("/remove/(?<segment>.*),
/${segment}").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.SECURE_HEADERS).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/remove/rewrite").exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("X-XSS-Protection", "1 ;
mode=block");
+
+ route.getFilters().clear();
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/remove/rewrite").exchange().
+ expectStatus().isNotFound();
+
+ route.getFilters().clear();
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/rewrite").exchange().
+ expectStatus().isOk().
+ expectHeader().doesNotExist("X-XSS-Protection");
+
+ route.getFilters().clear();
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.PATH).args("/remove/{segment}").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.SET_PATH).args("/{segment}").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/remove/rewrite").exchange().
+ expectStatus().isOk();
+
+ route.getFilters().clear();
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.STRIP_PREFIX).args("1").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/remove/rewrite").exchange().expectStatus().isOk();
+ }
+
+ @Test
+ public void redirect() {
+
webClient.get().uri("/redirect").exchange().expectStatus().isNotFound();
+
+ stubFor(get(urlEqualTo("/redirect")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("redirect");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.REDIRECT).args("307,http://127.0.0.1:" +
wiremockPort).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/redirect").exchange().expectStatus().isTemporaryRedirect();
+
+ route.getFilters().clear();
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/redirect").exchange().expectStatus().isOk();
+
+ route.getFilters().clear();
+ route.getFilters().add(new
GatewayRouteFilter.Builder().factory(FilterFactory.SET_STATUS).args("404").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/redirect").exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void datetime() {
+
webClient.get().uri("/prefix/datetime").exchange().expectStatus().isNotFound();
+
+ stubFor(get(urlEqualTo("/prefix/datetime")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("datetime");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.AFTER).args(ZonedDateTime.now().minusYears(1).toString()).build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.BEFORE).args(ZonedDateTime.now().plusYears(1).toString()).
+ cond(GatewayRoutePredicateCond.AND).build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.BETWEEN).args(ZonedDateTime.now().minusYears(1).toString()
+ ","
+ + ZonedDateTime.now().plusYears(1).toString()).
+ cond(GatewayRoutePredicateCond.AND).build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.PREFIX_PATH).args("/prefix").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/datetime").exchange().
+ expectStatus().isOk();
+
+ route.getPredicates().clear();
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.AFTER).args(ZonedDateTime.now().plusYears(1).toString()).build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.BEFORE).args(ZonedDateTime.now().minusYears(1).toString()).
+ cond(GatewayRoutePredicateCond.OR).build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.BETWEEN).args(ZonedDateTime.now().plusYears(1).toString()
+ ","
+ +
ZonedDateTime.now().minusYears(1).toString()).cond(GatewayRoutePredicateCond.OR).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/datetime").exchange().expectStatus().isNotFound();
+
+ route.getPredicates().clear();
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.BEFORE).negate().args(ZonedDateTime.now().minusYears(1).toString()).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/datetime").exchange().expectStatus().isOk();
+ }
+
+ @Test
+ public void header() {
+ webClient.get().uri("/header").exchange().expectStatus().isNotFound();
+
+ stubFor(get(urlEqualTo("/header")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("header");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.COOKIE).args("Hello,World").build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.HOST).args("host").cond(GatewayRoutePredicateCond.AND).build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.HEADER).args("Hello,World").cond(GatewayRoutePredicateCond.AND).build());
+ route.getFilters().add(new
GatewayRouteFilter.Builder().factory(FilterFactory.PRESERVE_HOST_HEADER).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/header").cookie("Hello", "World").header("Host",
"host").header("Hello", "World").
+ exchange().expectStatus().isOk();
+
+ webClient.get().uri("/header").cookie("Hello", "Mondo").header("Host",
"host").header("Hello", "World").
+ exchange().expectStatus().isNotFound();
+
+ webClient.get().uri("/header").cookie("Hello", "World").header("Host",
"anotherHost").header("Hello", "World").
+ exchange().expectStatus().isNotFound();
+
+ webClient.get().uri("/header").cookie("Hello", "World").header("Host",
"host").header("Hello", "Mondo").
+ exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void query() {
+ stubFor(get(urlEqualTo("/query?name=value")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("query");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.QUERY).args("name,value").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.SAVE_SESSION).build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.SET_REQUEST_SIZE).args("5000").build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.RETRY).args("3").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/query?name=value").exchange().expectStatus().isOk();
+
+ route.getPredicates().clear();
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.QUERY).args("name,anotherValue").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/query?name=value").exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void path() {
+ stubFor(get(urlEqualTo("/pathMatcher/1")).willReturn(aResponse()));
+ stubFor(get(urlEqualTo("/pathMatcher/2")).willReturn(aResponse()));
+ stubFor(get(urlEqualTo("/pathMatcher/2/3")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("pathMatcher");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.PATH).args("/pathMatcher/**").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/pathMatcher/1").exchange().expectStatus().isOk();
+ webClient.get().uri("/pathMatcher/2").exchange().expectStatus().isOk();
+
webClient.get().uri("/pathMatcher/2/3").exchange().expectStatus().isOk();
+
webClient.get().uri("/pathMatcher/4").exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void linkRewrite() {
+ stubFor(get(urlEqualTo("/linkRewrite")).willReturn(aResponse().
+ withHeader(HttpHeaders.CONTENT_TYPE,
MediaType.TEXT_HTML_VALUE).
+ withBody("<html><head></head><body><a
href=\"/absolute\">absolute link</a></body></html>")));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("linkRewrite");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new
GatewayRouteFilter.Builder().factory(FilterFactory.LINK_REWRITE).
+ args("http://localhost:" + gatewayPort).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/linkRewrite").exchange().
+ expectStatus().isOk().
+ expectBody().consumeWith(exchange -> {
+ assertTrue(new String(exchange.getResponseBody()).
+ contains("<a href=\"http://localhost:" +
gatewayPort + "/absolute\">"));
+ });
+
+ route.getFilters().clear();
+ route.getFilters().add(new
GatewayRouteFilter.Builder().factory(FilterFactory.LINK_REWRITE).
+ args("http://localhost:" + gatewayPort + ",true").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/linkRewrite").exchange().
+ expectStatus().isOk().
+ expectBody().consumeWith(exchange -> {
+ assertTrue(new String(exchange.getResponseBody()).
+ contains("<a href=\"http://localhost:" +
gatewayPort + "/absolute\">"));
+ });
+ }
+
+ @Test
+ public void clientCertToRequestHeader() {
+ stubFor(get(urlEqualTo("/clientCert")).willReturn(aResponse().
+ withHeader(HttpHeaders.CONTENT_TYPE,
MediaType.TEXT_HTML_VALUE)));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("clientCert");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.CLIENT_CERTS_TO_REQUEST_HEADER).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/clientCert").exchange().
+ expectStatus().isOk().
+ expectHeader().doesNotExist("X-Client-Certificate");
+ }
+
+ @Test
+ public void queryParamToRequestHeader() {
+ stubFor(get(urlEqualTo("/queryParamToRequestHeader")).
+ withHeader("Hello", equalTo("World")).willReturn(aResponse()));
+
+
stubFor(get(urlEqualTo("/queryParamToRequestHeader?Header=Test&Header=Test1")).
+ withHeader("Hello", equalTo("World")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("queryParamToRequestHeader");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.QUERY_PARAM_TO_REQUEST_HEADER).args("Hello").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/queryParamToRequestHeader").exchange().
+ expectStatus().isNotFound();
+
+
webClient.get().uri("/queryParamToRequestHeader?Hello=World").exchange().
+ expectStatus().isOk();
+
+
webClient.get().uri("/queryParamToRequestHeader?Header=Test&Hello=World&Header=Test1").exchange().
+ expectStatus().isOk();
+ }
+
+ @Test
+ public void custom() {
+ stubFor(post(urlEqualTo("/custom")).
+ willReturn(aResponse().
+ withHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE).
+ withBody("{\"data\": \"data\"}")));
+
+ GatewayRouteTO routeTO = new GatewayRouteTO();
+ routeTO.setKey("custom");
+ routeTO.setTarget(URI.create("http://localhost:" + wiremockPort));
+ routeTO.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.CUSTOM).
+ args(BodyPropertyMatchingRoutePredicateFactory.class.getName()
+ ";cool").build());
+ routeTO.getFilters().add(new GatewayRouteFilter.Builder().
+
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Custom,matched").build());
+ routeTO.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.CUSTOM).
+ args(BodyPropertyAddingGatewayFilterFactory.class.getName() +
";customized=true").build());
+
+ SyncopeCoreTestingServer.ROUTES.put(routeTO.getKey(), routeTO);
+ routeRefresher.refresh();
+
+ webClient.post().uri("/custom").
+
body(BodyInserters.fromValue(MAPPER.createObjectNode().put("other", true))).
+ exchange().
+ expectStatus().isNotFound();
+
+ webClient.post().uri("/custom").
+
body(BodyInserters.fromValue(MAPPER.createObjectNode().put("cool", true))).
+ exchange().
+ expectStatus().isOk().
+ expectHeader().valueEquals("Custom", "matched").
+ expectBody().
+ consumeWith(response -> {
+ try {
+ JsonNode body =
MAPPER.readTree(response.getResponseBody());
+ assertTrue(body.has("customized"));
+ assertTrue(body.get("customized").asBoolean());
+ } catch (IOException e) {
+ fail(e.getMessage(), e);
+ }
+ });
+ }
+}
diff --git
a/sra/src/test/java/org/apache/syncope/sra/SyncopeCoreTestingServer.java
b/sra/src/test/java/org/apache/syncope/sra/SyncopeCoreTestingServer.java
index 0d740e4..a90217b 100644
--- a/sra/src/test/java/org/apache/syncope/sra/SyncopeCoreTestingServer.java
+++ b/sra/src/test/java/org/apache/syncope/sra/SyncopeCoreTestingServer.java
@@ -53,21 +53,23 @@ public class SyncopeCoreTestingServer implements
ApplicationListener<ContextRefr
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
- // 1. start (mocked) Core as embedded CXF
- JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
- sf.setAddress(ADDRESS);
- sf.setResourceClasses(GatewayRouteService.class);
- sf.setResourceProvider(
- GatewayRouteService.class,
- new SingletonResourceProvider(new StubGatewayRouteService(),
true));
- sf.setProviders(List.of(new JacksonJsonProvider()));
- sf.create();
-
- // 2. register Core in Keymaster
- NetworkService core = new NetworkService();
- core.setType(NetworkService.Type.CORE);
- core.setAddress(ADDRESS);
- serviceOps.register(core);
+ if (AbstractTest.available(9080)) {
+ // 1. start (mocked) Core as embedded CXF
+ JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
+ sf.setAddress(ADDRESS);
+ sf.setResourceClasses(GatewayRouteService.class);
+ sf.setResourceProvider(
+ GatewayRouteService.class,
+ new SingletonResourceProvider(new
StubGatewayRouteService(), true));
+ sf.setProviders(List.of(new JacksonJsonProvider()));
+ sf.create();
+
+ // 2. register Core in Keymaster
+ NetworkService core = new NetworkService();
+ core.setType(NetworkService.Type.CORE);
+ core.setAddress(ADDRESS);
+ serviceOps.register(core);
+ }
}
public class StubGatewayRouteService implements GatewayRouteService {
diff --git a/sra/src/test/java/org/apache/syncope/sra/SyncopeSRATest.java
b/sra/src/test/java/org/apache/syncope/sra/SyncopeSRATest.java
deleted file mode 100644
index e5caef8..0000000
--- a/sra/src/test/java/org/apache/syncope/sra/SyncopeSRATest.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.syncope.sra;
-
-import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
-import static com.github.tomakehurst.wiremock.client.WireMock.get;
-import static com.github.tomakehurst.wiremock.client.WireMock.post;
-import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
-import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
-import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-import static org.junit.jupiter.api.Assertions.fail;
-
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import java.io.IOException;
-import java.net.URI;
-import org.apache.syncope.common.lib.to.GatewayRouteTO;
-import org.apache.syncope.common.lib.types.FilterFactory;
-import org.apache.syncope.common.lib.types.GatewayRouteFilter;
-import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
-import org.apache.syncope.common.lib.types.GatewayRouteStatus;
-import org.apache.syncope.common.lib.types.PredicateCond;
-import org.apache.syncope.common.lib.types.PredicateFactory;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.cloud.contract.wiremock.AutoConfigureWireMock;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.web.reactive.server.WebTestClient;
-import org.springframework.web.reactive.function.BodyInserters;
-
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@ContextConfiguration(initializers = ZookeeperTestingServer.class)
-@AutoConfigureWireMock(port = 0)
-public class SyncopeSRATest {
-
- private static final ObjectMapper MAPPER = new ObjectMapper();
-
- @Autowired
- private WebTestClient webClient;
-
- @Autowired
- private RouteRefresher routeRefresher;
-
- @Value("${wiremock.server.port}")
- private int wiremockPort;
-
- @BeforeEach
- public void clearRoutes() {
- SyncopeCoreTestingServer.ROUTES.clear();
- }
-
- @Test
- public void root() {
- webClient.get().exchange().expectStatus().isNotFound();
- }
-
- @Test
- public void getAddResponseHeader() {
- // 1. no mapping for URL
-
webClient.get().uri("/getAddResponseHeader").exchange().expectStatus().isNotFound();
-
- // 2. stub for proxied URL
-
stubFor(get(urlEqualTo("/getAddResponseHeader")).willReturn(aResponse()));
-
- // 3. create route configuration
- GatewayRouteTO routeTO = new GatewayRouteTO();
- routeTO.setKey("getAddResponseHeader");
- routeTO.setStatus(GatewayRouteStatus.PUBLISHED);
- routeTO.setTarget(URI.create("http://localhost:" + wiremockPort));
- routeTO.getPredicates().add(new GatewayRoutePredicate.Builder().
- factory(PredicateFactory.METHOD).args("GET").build());
- routeTO.getPredicates().add(new GatewayRoutePredicate.Builder().
-
factory(PredicateFactory.PATH).args("/getAddResponseHeader").cond(PredicateCond.AND).build());
- routeTO.getFilters().add(new GatewayRouteFilter.Builder().
-
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Hello,World").build());
-
- SyncopeCoreTestingServer.ROUTES.put(routeTO.getKey(), routeTO);
-
- routeRefresher.refresh();
-
- // 4. now mapping works for URL
- webClient.get().uri("/getAddResponseHeader").exchange().
- expectStatus().isOk().
- expectHeader().valueEquals("Hello", "World");
-
- // 5. update route configuration
- routeTO.getFilters().clear();
- routeTO.getFilters().add(new GatewayRouteFilter.Builder().
-
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Hello,WorldZ").build());
-
- routeRefresher.refresh();
-
- // 6. mapping for URL is updated too
- webClient.get().uri("/getAddResponseHeader").exchange().
- expectStatus().isOk().
- expectHeader().valueEquals("Hello", "WorldZ");
-
- // 7. update route configuration again
- routeTO.getFilters().clear();
-
- routeRefresher.refresh();
-
- // 8. mapping for URL is updated again
- webClient.get().uri("/getAddResponseHeader").exchange().
- expectStatus().isOk().
- expectHeader().doesNotExist("Hello");
- }
-
- @Test
- public void hystrix() {
- webClient.get().uri("/fallback").exchange().
- expectStatus().isOk().
- expectBody().
- consumeWith(response ->
assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
-
- stubFor(get(urlEqualTo("/delay/3")).
- willReturn(aResponse().
- withBody("no fallback").
- withFixedDelay(3000)));
-
- GatewayRouteTO routeTO = new GatewayRouteTO();
- routeTO.setKey("hystrix");
- routeTO.setStatus(GatewayRouteStatus.PUBLISHED);
- routeTO.setTarget(URI.create("http://localhost:" + wiremockPort));
- routeTO.getPredicates().add(new GatewayRoutePredicate.Builder().
- factory(PredicateFactory.HOST).args("*.hystrix.com").build());
- routeTO.getFilters().add(new GatewayRouteFilter.Builder().
-
factory(FilterFactory.HYSTRIX).args("fallbackcmd,forward:/fallback").build());
-
- SyncopeCoreTestingServer.ROUTES.put(routeTO.getKey(), routeTO);
-
- routeRefresher.refresh();
-
- webClient.get().uri("/delay/3").
- header(HttpHeaders.HOST, "www.hystrix.com").
- exchange().
- expectStatus().isOk().
- expectBody().
- consumeWith(response ->
assertThat(response.getResponseBody()).isEqualTo("fallback".getBytes()));
- }
-
- @Test
- public void custom() {
- stubFor(post(urlEqualTo("/custom")).
- willReturn(aResponse().
- withHeader(HttpHeaders.CONTENT_TYPE,
MediaType.APPLICATION_JSON_VALUE).
- withBody("{\"data\": \"data\"}")));
-
- GatewayRouteTO routeTO = new GatewayRouteTO();
- routeTO.setKey("custom");
- routeTO.setStatus(GatewayRouteStatus.PUBLISHED);
- routeTO.setTarget(URI.create("http://localhost:" + wiremockPort));
- routeTO.getPredicates().add(new GatewayRoutePredicate.Builder().
- factory(PredicateFactory.CUSTOM).
- args(BodyPropertyMatchingRoutePredicateFactory.class.getName()
+ ";cool").build());
- routeTO.getFilters().add(new GatewayRouteFilter.Builder().
-
factory(FilterFactory.ADD_RESPONSE_HEADER).args("Custom,matched").build());
- routeTO.getFilters().add(new GatewayRouteFilter.Builder().
- factory(FilterFactory.CUSTOM).
- args(BodyPropertyAddingGatewayFilterFactory.class.getName() +
";customized=true").build());
-
- SyncopeCoreTestingServer.ROUTES.put(routeTO.getKey(), routeTO);
-
- routeRefresher.refresh();
-
- webClient.post().uri("/custom").
-
body(BodyInserters.fromValue(MAPPER.createObjectNode().put("other", true))).
- exchange().
- expectStatus().isNotFound();
-
- webClient.post().uri("/custom").
-
body(BodyInserters.fromValue(MAPPER.createObjectNode().put("cool", true))).
- exchange().
- expectStatus().isOk().
- expectHeader().valueEquals("Custom", "matched").
- expectBody().
- consumeWith(response -> {
- try {
- JsonNode body =
MAPPER.readTree(response.getResponseBody());
- assertTrue(body.has("customized"));
- assertTrue(body.get("customized").asBoolean());
- } catch (IOException e) {
- fail(e.getMessage(), e);
- }
- });
- }
-}
diff --git a/sra/src/test/java/org/apache/syncope/sra/TLSRouteProviderTest.java
b/sra/src/test/java/org/apache/syncope/sra/TLSRouteProviderTest.java
new file mode 100644
index 0000000..8401abe
--- /dev/null
+++ b/sra/src/test/java/org/apache/syncope/sra/TLSRouteProviderTest.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.syncope.sra;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+
+import com.github.tomakehurst.wiremock.matching.AnythingPattern;
+import io.netty.handler.ssl.SslContext;
+import io.netty.handler.ssl.SslContextBuilder;
+import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
+import java.io.IOException;
+import java.net.URI;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLException;
+import org.apache.syncope.common.lib.to.GatewayRouteTO;
+import org.apache.syncope.common.lib.types.FilterFactory;
+import org.apache.syncope.common.lib.types.GatewayRouteFilter;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicate;
+import org.apache.syncope.common.lib.types.GatewayRoutePredicateCond;
+import org.apache.syncope.common.lib.types.PredicateFactory;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.client.reactive.ClientHttpConnector;
+import org.springframework.http.client.reactive.ReactorClientHttpConnector;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.web.reactive.server.WebTestClient;
+import reactor.netty.http.client.HttpClient;
+
+@ActiveProfiles({ "tls" })
+public class TLSRouteProviderTest extends AbstractTest {
+
+ private WebTestClient webClient() throws SSLException {
+ SslContext sslContext = SslContextBuilder.forClient().
+ trustManager(InsecureTrustManagerFactory.INSTANCE).
+ build();
+ return webClient(sslContext);
+ }
+
+ private WebTestClient webClient(final SslContext sslContext) throws
SSLException {
+ HttpClient httpClient = HttpClient.create().
+ secure(sslContextSpec ->
sslContextSpec.sslContext(sslContext));
+ ClientHttpConnector connector = new
ReactorClientHttpConnector(httpClient);
+ return
WebTestClient.bindToServer(connector).baseUrl("https://localhost:" +
gatewayPort).build();
+ }
+
+ @BeforeEach
+ public void clearRoutes() {
+ SyncopeCoreTestingServer.ROUTES.clear();
+ }
+
+ @Test
+ public void root() throws SSLException {
+ webClient().get().exchange().expectStatus().isNotFound();
+ }
+
+ @Test
+ public void clientAuth() throws SSLException, KeyStoreException,
IOException, NoSuchAlgorithmException,
+ CertificateException, UnrecoverableKeyException,
KeyManagementException {
+
+ KeyStore store = KeyStore.getInstance("PKCS12");
+ store.load(getClass().getResourceAsStream("/client_pavel.p12"),
"password".toCharArray());
+
+ KeyManagerFactory kmf =
KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
+ kmf.init(store, "password".toCharArray());
+
+ SslContext sslContext = SslContextBuilder.forClient().
+ trustManager(InsecureTrustManagerFactory.INSTANCE).
+ keyManager(kmf).
+ build();
+ WebTestClient webClient = webClient(sslContext);
+
+ stubFor(get(urlEqualTo("/getWithClientAuth")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("getWithClientAuth");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.METHOD).args("GET").build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.PATH).args("/getWithClientAuth").cond(GatewayRoutePredicateCond.AND).build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.CLIENT_CERTS_TO_REQUEST_HEADER).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+
webClient.get().uri("/getWithClientAuth").exchange().expectStatus().isOk();
+
+ verify(getRequestedFor(urlEqualTo("/getWithClientAuth")).
+ withHeader("X-Client-Certificate", new AnythingPattern()));
+ }
+
+ @Test
+ public void withoutClientCert() throws SSLException, KeyStoreException,
IOException, NoSuchAlgorithmException,
+ CertificateException, UnrecoverableKeyException,
KeyManagementException {
+
+ SslContext sslContext = SslContextBuilder.forClient().
+ trustManager(InsecureTrustManagerFactory.INSTANCE).
+ build();
+ WebTestClient webClient = webClient(sslContext);
+
+ stubFor(get(urlEqualTo("/withoutClientCert")).willReturn(aResponse()));
+
+ GatewayRouteTO route = new GatewayRouteTO();
+ route.setKey("withoutClientCert");
+ route.setTarget(URI.create("http://localhost:" + wiremockPort));
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+ factory(PredicateFactory.METHOD).args("GET").build());
+ route.getPredicates().add(new GatewayRoutePredicate.Builder().
+
factory(PredicateFactory.PATH).args("/withoutClientCert").cond(GatewayRoutePredicateCond.AND).build());
+ route.getFilters().add(new GatewayRouteFilter.Builder().
+ factory(FilterFactory.CLIENT_CERTS_TO_REQUEST_HEADER).build());
+
+ SyncopeCoreTestingServer.ROUTES.put(route.getKey(), route);
+ routeRefresher.refresh();
+
+ webClient.get().uri("/withoutClientCert").exchange().
+ expectStatus().isOk().
+ expectHeader().doesNotExist("X-Client-Certificate");
+ }
+}
diff --git
a/sra/src/test/java/org/apache/syncope/sra/ZookeeperTestingServer.java
b/sra/src/test/java/org/apache/syncope/sra/ZookeeperTestingServer.java
index 930d724..b9c8762 100644
--- a/sra/src/test/java/org/apache/syncope/sra/ZookeeperTestingServer.java
+++ b/sra/src/test/java/org/apache/syncope/sra/ZookeeperTestingServer.java
@@ -53,29 +53,31 @@ public class ZookeeperTestingServer implements
ApplicationContextInitializer<Con
throw new IllegalStateException("Could not load
/keymaster.properties", e);
}
- Configuration.setConfiguration(new Configuration() {
+ if (AbstractTest.available(port.get())) {
+ Configuration.setConfiguration(new Configuration() {
- private final AppConfigurationEntry[] entries = {
- new AppConfigurationEntry(
- DigestLoginModule.class.getName(),
- AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
- Map.of("user_" + username.get(), password.get()))
- };
+ private final AppConfigurationEntry[] entries = {
+ new AppConfigurationEntry(
+ DigestLoginModule.class.getName(),
+ AppConfigurationEntry.LoginModuleControlFlag.REQUIRED,
+ Map.of("user_" + username.get(), password.get()))
+ };
- @Override
- public AppConfigurationEntry[] getAppConfigurationEntry(final
String name) {
- return entries;
- }
- });
+ @Override
+ public AppConfigurationEntry[] getAppConfigurationEntry(final
String name) {
+ return entries;
+ }
+ });
- Map<String, Object> customProperties = new HashMap<>();
- customProperties.put("authProvider.1",
SASLAuthenticationProvider.class.getName());
- InstanceSpec spec = new InstanceSpec(null, port.get(), -1, -1, true,
1, -1, -1, customProperties);
+ Map<String, Object> customProperties = new HashMap<>();
+ customProperties.put("authProvider.1",
SASLAuthenticationProvider.class.getName());
+ InstanceSpec spec = new InstanceSpec(null, port.get(), -1, -1,
true, 1, -1, -1, customProperties);
- try {
- new TestingServer(spec, true);
- } catch (Exception e) {
- fail(e);
+ try {
+ new TestingServer(spec, true);
+ } catch (Exception e) {
+ fail(e);
+ }
}
}
}
diff --git
a/sra/src/test/java/org/apache/syncope/sra/BodyPropertyAddingGatewayFilterFactory.java
b/sra/src/test/java/org/apache/syncope/sra/filters/BodyPropertyAddingGatewayFilterFactory.java
similarity index 99%
rename from
sra/src/test/java/org/apache/syncope/sra/BodyPropertyAddingGatewayFilterFactory.java
rename to
sra/src/test/java/org/apache/syncope/sra/filters/BodyPropertyAddingGatewayFilterFactory.java
index d849771..853c92b 100644
---
a/sra/src/test/java/org/apache/syncope/sra/BodyPropertyAddingGatewayFilterFactory.java
+++
b/sra/src/test/java/org/apache/syncope/sra/filters/BodyPropertyAddingGatewayFilterFactory.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.sra;
+package org.apache.syncope.sra.filters;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
diff --git
a/sra/src/test/java/org/apache/syncope/sra/BodyPropertyMatchingRoutePredicateFactory.java
b/sra/src/test/java/org/apache/syncope/sra/predicates/BodyPropertyMatchingRoutePredicateFactory.java
similarity index 98%
rename from
sra/src/test/java/org/apache/syncope/sra/BodyPropertyMatchingRoutePredicateFactory.java
rename to
sra/src/test/java/org/apache/syncope/sra/predicates/BodyPropertyMatchingRoutePredicateFactory.java
index 9be1ab8..cdbd3fd 100644
---
a/sra/src/test/java/org/apache/syncope/sra/BodyPropertyMatchingRoutePredicateFactory.java
+++
b/sra/src/test/java/org/apache/syncope/sra/predicates/BodyPropertyMatchingRoutePredicateFactory.java
@@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.syncope.sra;
+package org.apache.syncope.sra.predicates;
import com.fasterxml.jackson.databind.JsonNode;
import java.util.List;
diff --git a/sra/src/test/resources/application-tls.properties
b/sra/src/test/resources/application-tls.properties
new file mode 100644
index 0000000..5aa6f20
--- /dev/null
+++ b/sra/src/test/resources/application-tls.properties
@@ -0,0 +1,31 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+server.ssl.enabled=true
+
+server.ssl.key-store-type=PKCS12
+server.ssl.key-store=classpath:keyStore.p12
+server.ssl.key-store-password=password
+
+server.ssl.trust-store=classpath:trustStore.jks
+server.ssl.trust-store-password=password
+server.ssl.trust-store-type=JKS
+
+server.ssl.client-auth=want
+
+server.port=8443
+security.require-ssl=true
+service.discovery.address=http://localhost:8443
diff --git a/sra/src/test/resources/client_pavel.p12
b/sra/src/test/resources/client_pavel.p12
new file mode 100644
index 0000000..b7958f2
Binary files /dev/null and b/sra/src/test/resources/client_pavel.p12 differ
diff --git a/sra/src/test/resources/keyStore.p12
b/sra/src/test/resources/keyStore.p12
new file mode 100644
index 0000000..85505b9
Binary files /dev/null and b/sra/src/test/resources/keyStore.p12 differ
diff --git a/sra/src/test/resources/trustStore.jks
b/sra/src/test/resources/trustStore.jks
new file mode 100644
index 0000000..6000a06
Binary files /dev/null and b/sra/src/test/resources/trustStore.jks differ