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 1c03449604f..96fe4db1e50 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 @@ -809,6 +809,9 @@ public class AppConfiguration implements Configuration { @DocProperty(description = "SSA Configuration") private SsaConfiguration ssaConfiguration; + @DocProperty(description = "Enable/Disable block authorizations that originate from Webview (Mobile apps).", defaultValue = "false") + private Boolean blockWebviewAuthorizationEnabled = false; + public List getDcrSsaValidationConfigs() { if (dcrSsaValidationConfigs == null) dcrSsaValidationConfigs = new ArrayList<>(); return dcrSsaValidationConfigs; @@ -3085,4 +3088,12 @@ public SsaConfiguration getSsaConfiguration() { public void setSsaConfiguration(SsaConfiguration ssaConfiguration) { this.ssaConfiguration = ssaConfiguration; } + + public Boolean getBlockWebviewAuthorizationEnabled() { + return blockWebviewAuthorizationEnabled; + } + + public void setBlockWebviewAuthorizationEnabled(Boolean blockWebviewAuthorizationEnabled) { + this.blockWebviewAuthorizationEnabled = blockWebviewAuthorizationEnabled; + } } diff --git a/jans-auth-server/server/conf/jans-config.json b/jans-auth-server/server/conf/jans-config.json index 770b0d15d30..4176186bd49 100644 --- a/jans-auth-server/server/conf/jans-config.json +++ b/jans-auth-server/server/conf/jans-config.json @@ -449,5 +449,6 @@ "defaultResponseHeaders": { "Cache-Control": "max-age=0, no-store" } - } + }, + "blockWebviewAuthorizationEnabled": false } diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java index 4def82ed7ad..27f0f40c668 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceImpl.java @@ -168,6 +168,8 @@ public Response requestAuthorizationGet( String codeChallenge, String codeChallengeMethod, String customResponseHeaders, String claims, String authReqId, HttpServletRequest httpRequest, HttpServletResponse httpResponse, SecurityContext securityContext) { + authorizeRestWebServiceValidator.validateNotWebView(httpRequest); + AuthzRequest authzRequest = new AuthzRequest(); authzRequest.setHttpMethod(HttpMethod.GET); authzRequest.setScope(scope); @@ -210,6 +212,8 @@ public Response requestAuthorizationPost( String codeChallenge, String codeChallengeMethod, String customResponseHeaders, String claims, String authReqId, HttpServletRequest httpRequest, HttpServletResponse httpResponse, SecurityContext securityContext) { + authorizeRestWebServiceValidator.validateNotWebView(httpRequest); + AuthzRequest authzRequest = new AuthzRequest(); authzRequest.setHttpMethod(HttpMethod.POST); authzRequest.setScope(scope); diff --git a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java index 04db0673674..e2753e8f128 100644 --- a/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java +++ b/jans-auth-server/server/src/main/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidator.java @@ -458,4 +458,14 @@ public void checkSignedRequestRequired(AuthzRequest authzRequest) { throw createInvalidJwtRequestException(authzRequest.getRedirectUriResponse(), "A signed request object is required"); } } + + public void validateNotWebView(HttpServletRequest httpRequest) { + if (appConfiguration.getBlockWebviewAuthorizationEnabled()) { + String headerRequestedWith = httpRequest.getHeader("X-Requested-With"); + if (headerRequestedWith != null) { + log.error("Unauthorized, request contains X-Requested-With: {}", headerRequestedWith); + throw new WebApplicationException(Response.status(Response.Status.UNAUTHORIZED).build()); + } + } + } } diff --git a/jans-auth-server/server/src/test/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidatorTest.java b/jans-auth-server/server/src/test/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidatorTest.java index a08290c1490..ff51516ca16 100644 --- a/jans-auth-server/server/src/test/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidatorTest.java +++ b/jans-auth-server/server/src/test/java/io/jans/as/server/authorize/ws/rs/AuthorizeRestWebServiceValidatorTest.java @@ -9,6 +9,8 @@ import io.jans.as.server.service.DeviceAuthorizationService; import io.jans.as.server.service.RedirectionUriService; import io.jans.as.server.service.SessionIdService; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.WebApplicationException; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.testng.MockitoTestNGListener; @@ -16,9 +18,8 @@ import org.testng.annotations.Listeners; import org.testng.annotations.Test; -import static org.mockito.Mockito.when; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.assertTrue; +import static org.mockito.Mockito.*; +import static org.testng.Assert.*; /** * @author Yuriy Z @@ -74,4 +75,33 @@ public void isAuthnMaxAgeValid_whenMaxAgeIsZeroAndDisableAuthnForMaxAgeZeroIsTru public void isAuthnMaxAgeValid_whenMaxAgeIsNull_shouldReturnTrue() { assertTrue(authorizeRestWebServiceValidator.isAuthnMaxAgeValid(0, new SessionId(), new Client())); } + + @Test + public void validateNotWebView_blockWebviewDisabled_valid() { + HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + when(appConfiguration.getBlockWebviewAuthorizationEnabled()).thenReturn(false); + + authorizeRestWebServiceValidator.validateNotWebView(httpServletRequest); + verifyNoInteractions(log, httpServletRequest); + } + + @Test + public void validateNotWebView_blockWebviewEnabled_valid() { + HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + when(appConfiguration.getBlockWebviewAuthorizationEnabled()).thenReturn(true); + + authorizeRestWebServiceValidator.validateNotWebView(httpServletRequest); + verifyNoInteractions(log); + } + + @Test + public void validateNotWebView_withRequestedWithHeader_throwUnauthorized() { + HttpServletRequest httpServletRequest = mock(HttpServletRequest.class); + when(appConfiguration.getBlockWebviewAuthorizationEnabled()).thenReturn(true); + String testPackage = "test.app.package"; + when(httpServletRequest.getHeader(any())).thenReturn(testPackage); + + assertThrows(WebApplicationException.class, () -> authorizeRestWebServiceValidator.validateNotWebView(httpServletRequest)); + verify(log).error(anyString(), eq(testPackage)); + } } diff --git a/jans-linux-setup/jans_setup/openbanking/templates/jans-auth/jans-auth-config.json b/jans-linux-setup/jans_setup/openbanking/templates/jans-auth/jans-auth-config.json index f07331124d7..5c8dfb9a394 100644 --- a/jans-linux-setup/jans_setup/openbanking/templates/jans-auth/jans-auth-config.json +++ b/jans-linux-setup/jans_setup/openbanking/templates/jans-auth/jans-auth-config.json @@ -394,5 +394,6 @@ "staticKid": "%(static_kid)s", "forceOfflineAccessScopeToEnableRefreshToken" : false, "redirectUrisRegexEnabled": false, - "useHighestLevelScriptIfAcrScriptNotFound": true + "useHighestLevelScriptIfAcrScriptNotFound": true, + "blockWebviewAuthorizationEnabled": false } diff --git a/jans-linux-setup/jans_setup/templates/jans-auth/jans-auth-config.json b/jans-linux-setup/jans_setup/templates/jans-auth/jans-auth-config.json index b1af26481ed..aba9596ca9d 100644 --- a/jans-linux-setup/jans_setup/templates/jans-auth/jans-auth-config.json +++ b/jans-linux-setup/jans_setup/templates/jans-auth/jans-auth-config.json @@ -497,5 +497,6 @@ "defaultResponseHeaders": { "Cache-Control": "max-age=0, no-store" } - } + }, + "blockWebviewAuthorizationEnabled": false }