diff --git a/jans-auth-server/agama/engine/pom.xml b/jans-auth-server/agama/engine/pom.xml
index 65aa9517d85..64a14a5013f 100644
--- a/jans-auth-server/agama/engine/pom.xml
+++ b/jans-auth-server/agama/engine/pom.xml
@@ -50,6 +50,14 @@
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 11
+
+
diff --git a/jans-auth-server/agama/model/pom.xml b/jans-auth-server/agama/model/pom.xml
index 69c7e9f4f2e..76c114cfac1 100644
--- a/jans-auth-server/agama/model/pom.xml
+++ b/jans-auth-server/agama/model/pom.xml
@@ -38,4 +38,17 @@
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+
+ 11
+
+
+
+
+
\ No newline at end of file
diff --git a/jans-auth-server/model/src/main/java/io/jans/as/model/configuration/AppConfiguration.java b/jans-auth-server/model/src/main/java/io/jans/as/model/configuration/AppConfiguration.java
index 82580622ec5..8ba2ea48cfc 100644
--- a/jans-auth-server/model/src/main/java/io/jans/as/model/configuration/AppConfiguration.java
+++ b/jans-auth-server/model/src/main/java/io/jans/as/model/configuration/AppConfiguration.java
@@ -570,6 +570,9 @@ public class AppConfiguration implements Configuration {
@DocProperty(description = "JMS Password")
private String jmsPassword;
+ @DocProperty(description = "This list specifies which external URIs can be called by AS (if empty any URI can be called)")
+ private List externalUriWhiteList;
+
@DocProperty(description = "This list specifies which client redirection URIs are white-listed")
private List clientWhiteList;
@@ -2473,6 +2476,15 @@ public void setJmsPassword(String jmsPassword) {
this.jmsPassword = jmsPassword;
}
+ public List getExternalUriWhiteList() {
+ if (externalUriWhiteList == null) externalUriWhiteList = new ArrayList<>();
+ return externalUriWhiteList;
+ }
+
+ public void setExternalUriWhiteList(List externalUriWhiteList) {
+ this.externalUriWhiteList = externalUriWhiteList;
+ }
+
public List getClientWhiteList() {
return clientWhiteList;
}
diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterValidator.java b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterValidator.java
index e6064a4493f..dacd65bcc6d 100644
--- a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterValidator.java
+++ b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/RegisterValidator.java
@@ -20,7 +20,6 @@
import io.jans.as.model.jwt.Jwt;
import io.jans.as.model.register.RegisterErrorResponseType;
import io.jans.as.model.ssa.SsaValidationType;
-import io.jans.as.model.util.JwtUtil;
import io.jans.as.model.util.Pair;
import io.jans.as.server.ciba.CIBARegisterParamsValidatorService;
import io.jans.as.server.model.common.AbstractToken;
@@ -28,6 +27,7 @@
import io.jans.as.server.model.common.AuthorizationGrantList;
import io.jans.as.server.model.registration.RegisterParamsValidator;
import io.jans.as.server.service.external.ExternalDynamicClientRegistrationService;
+import io.jans.as.server.service.net.UriService;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -78,6 +78,9 @@ public class RegisterValidator {
@Inject
private SsaValidationConfigService ssaValidationConfigService;
+ @Inject
+ private UriService uriService;
+
public void validateNotBlank(String input, String errorReason) {
if (StringUtils.isBlank(input)) {
log.trace("Failed to perform client action, reason: {}", errorReason);
@@ -191,7 +194,7 @@ private String getJwksString(JSONObject softwareStatement) {
@Nullable
private JSONObject getJwks(HttpServletRequest httpRequest, Jwt jwt, String jwksUri, String jwksStr) {
if (StringUtils.isNotBlank(jwksUri)) {
- return JwtUtil.getJSONWebKeys(jwksUri);
+ return uriService.loadJson(jwksUri);
}
if (StringUtils.isNotBlank(jwksStr)) {
@@ -259,8 +262,11 @@ public JSONObject validateSoftwareStatement(HttpServletRequest httpServletReques
}
JSONObject jwks = Strings.isNullOrEmpty(jwksUriClaim) ?
- new JSONObject(jwksClaim) :
- JwtUtil.getJSONWebKeys(jwksUriClaim);
+ null :
+ uriService.loadJson(jwksUriClaim);
+ if (jwks == null && StringUtils.isNotBlank(jwksClaim)) {
+ jwks = new JSONObject(jwksClaim);
+ }
boolean validSignature = cryptoProvider.verifySignature(softwareStatement.getSigningInput(),
softwareStatement.getEncodedSignature(),
diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/SsaValidationConfigService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/SsaValidationConfigService.java
index f3fdb9abc06..15e2ff5d0f7 100644
--- a/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/SsaValidationConfigService.java
+++ b/jans-auth-server/server/src/main/java/io/jans/as/server/register/ws/rs/SsaValidationConfigService.java
@@ -12,7 +12,7 @@
import io.jans.as.model.register.RegisterRequestParam;
import io.jans.as.model.ssa.SsaValidationConfig;
import io.jans.as.model.ssa.SsaValidationType;
-import io.jans.as.model.util.JwtUtil;
+import io.jans.as.server.service.net.UriService;
import jakarta.ejb.Stateless;
import jakarta.inject.Inject;
import jakarta.inject.Named;
@@ -42,6 +42,9 @@ public class SsaValidationConfigService {
@Inject
private AbstractCryptoProvider cryptoProvider;
+ @Inject
+ private UriService uriService;
+
public List getByIssuer(String issuer, SsaValidationType type) {
if (StringUtils.isBlank(issuer)) {
return new ArrayList<>();
@@ -130,7 +133,7 @@ private boolean isSignatureValid(Jwt jwt, SsaValidationConfig config) {
private JSONObject loadJwks(SsaValidationConfig config) {
JSONObject jwks = null;
if (StringUtils.isNotBlank(config.getJwksUri())) {
- jwks = JwtUtil.getJSONWebKeys(config.getJwksUri());
+ jwks = uriService.loadJson(config.getJwksUri());
}
if (jwks == null && StringUtils.isNotBlank(config.getJwks())) {
@@ -138,10 +141,10 @@ private JSONObject loadJwks(SsaValidationConfig config) {
}
if (jwks == null && StringUtils.isNotBlank(config.getConfigurationEndpoint()) && StringUtils.isNotBlank(config.getConfigurationEndpointClaim())) {
- final JSONObject responseJson = JwtUtil.getJSONWebKeys(config.getConfigurationEndpoint());
+ final JSONObject responseJson = uriService.loadJson(config.getConfigurationEndpoint());
final String jwksEndpoint = responseJson.optString(config.getConfigurationEndpointClaim());
if (StringUtils.isNotBlank(jwksEndpoint)) {
- jwks = JwtUtil.getJSONWebKeys(jwksEndpoint);
+ jwks = uriService.loadJson(jwksEndpoint);
}
}
return jwks;
diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/service/net/UriService.java b/jans-auth-server/server/src/main/java/io/jans/as/server/service/net/UriService.java
new file mode 100644
index 00000000000..d00ec92bc34
--- /dev/null
+++ b/jans-auth-server/server/src/main/java/io/jans/as/server/service/net/UriService.java
@@ -0,0 +1,48 @@
+package io.jans.as.server.service.net;
+
+import io.jans.as.model.configuration.AppConfiguration;
+import io.jans.as.model.util.JwtUtil;
+import io.jans.as.model.util.URLPatternList;
+import jakarta.ejb.Stateless;
+import jakarta.inject.Inject;
+import jakarta.inject.Named;
+import org.apache.tika.utils.StringUtils;
+import org.json.JSONObject;
+import org.slf4j.Logger;
+
+import java.util.List;
+
+/**
+ * @author Yuriy Z
+ */
+@Stateless
+@Named
+public class UriService {
+
+ @Inject
+ private Logger log;
+
+ @Inject
+ private AppConfiguration appConfiguration;
+
+ public boolean canCall(String uri) {
+ if (StringUtils.isBlank(uri)) {
+ return false;
+ }
+
+ final List externalUriWhiteList = appConfiguration.getExternalUriWhiteList();
+ if (externalUriWhiteList == null || externalUriWhiteList.isEmpty()) {
+ return true;
+ }
+
+ return new URLPatternList(externalUriWhiteList).isUrlListed(uri);
+ }
+
+ public JSONObject loadJson(String uri) {
+ if (!canCall(uri)) {
+ log.debug("Unable to call external uri: {}, externalUriWhiteList: {}", uri, appConfiguration.getExternalUriWhiteList());
+ return null;
+ }
+ return JwtUtil.getJSONWebKeys(uri);
+ }
+}
diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/service/net/UriServiceTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/service/net/UriServiceTest.java
new file mode 100644
index 00000000000..bc91feb0f06
--- /dev/null
+++ b/jans-auth-server/server/src/test/java/io/jans/as/server/service/net/UriServiceTest.java
@@ -0,0 +1,53 @@
+package io.jans.as.server.service.net;
+
+import io.jans.as.model.configuration.AppConfiguration;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.testng.MockitoTestNGListener;
+import org.slf4j.Logger;
+import org.testng.annotations.Listeners;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.assertFalse;
+
+/**
+ * @author Yuriy Z
+ */
+@Listeners(MockitoTestNGListener.class)
+public class UriServiceTest {
+
+ @InjectMocks
+ private UriService uriService;
+
+ @Mock
+ private Logger log;
+
+ @Mock
+ private AppConfiguration appConfiguration;
+
+ @Test
+ public void canCall_whenExternalUriWhiteListIsBlank_shouldReturnTrue() {
+ when(appConfiguration.getExternalUriWhiteList()).thenReturn(new ArrayList<>());
+
+ assertTrue(uriService.canCall("http://example.com"));
+ }
+
+ @Test
+ public void canCall_whenUriAllowedByExternalUriWhiteList_shouldReturnTrue() {
+ when(appConfiguration.getExternalUriWhiteList()).thenReturn(Collections.singletonList("example.com"));
+
+ assertTrue(uriService.canCall("http://example.com"));
+ }
+
+ @Test
+ public void canCall_whenUriNotAllowedByExternalUriWhiteList_shouldReturnFalse() {
+ when(appConfiguration.getExternalUriWhiteList()).thenReturn(Collections.singletonList("my.com"));
+
+ assertFalse(uriService.canCall("http://example.com"));
+ }
+}
diff --git a/jans-auth-server/server/src/test/resources/testng.xml b/jans-auth-server/server/src/test/resources/testng.xml
index fde8aa49b18..dbaf66c846c 100644
--- a/jans-auth-server/server/src/test/resources/testng.xml
+++ b/jans-auth-server/server/src/test/resources/testng.xml
@@ -18,6 +18,7 @@
+