diff --git a/java-security-test/pom.xml b/java-security-test/pom.xml index 40c55d50e..eea8654ce 100644 --- a/java-security-test/pom.xml +++ b/java-security-test/pom.xml @@ -41,13 +41,13 @@ ${org.eclipse.jetty.version} - org.eclipse.jetty.ee9 - jetty-ee9-servlet + org.eclipse.jetty.ee10 + jetty-ee10-servlet ${org.eclipse.jetty.version} - org.eclipse.jetty.ee9 - jetty-ee9-webapp + org.eclipse.jetty.ee10 + jetty-ee10-webapp ${org.eclipse.jetty.version} diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java index 7a9c99c5a..930a220af 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTest.java @@ -5,6 +5,40 @@ */ package com.sap.cloud.security.test; +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.urlEqualTo; +import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static com.sap.cloud.security.config.Service.IAS; +import static com.sap.cloud.security.config.Service.XSUAA; +import static com.sap.cloud.security.xsuaa.client.OidcConfigurationService.DISCOVERY_ENDPOINT_DEFAULT; + +import java.io.IOException; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.security.NoSuchAlgorithmException; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.util.ArrayList; +import java.util.Base64; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import javax.annotation.Nullable; + +import org.apache.commons.io.IOUtils; +import org.eclipse.jetty.ee10.servlet.FilterHolder; +import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler; +import org.eclipse.jetty.ee10.webapp.WebAppContext; +import org.eclipse.jetty.server.Server; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.github.tomakehurst.wiremock.WireMockServer; import com.sap.cloud.environment.servicebinding.SapVcapServicesServiceBindingAccessor; import com.sap.cloud.environment.servicebinding.api.ServiceBinding; @@ -25,32 +59,10 @@ import com.sap.cloud.security.xsuaa.client.XsuaaDefaultEndpoints; import com.sap.cloud.security.xsuaa.http.HttpHeaders; import com.sap.cloud.security.xsuaa.http.MediaType; + import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import jakarta.servlet.Servlet; -import org.apache.commons.io.IOUtils; -import org.eclipse.jetty.ee9.security.ConstraintSecurityHandler; -import org.eclipse.jetty.server.Server; -import org.eclipse.jetty.ee9.servlet.FilterHolder; -import org.eclipse.jetty.ee9.servlet.ServletHolder; -import org.eclipse.jetty.ee9.webapp.WebAppContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.annotation.Nullable; -import java.io.IOException; -import java.net.URI; -import java.nio.charset.StandardCharsets; -import java.security.NoSuchAlgorithmException; -import java.security.interfaces.RSAPublicKey; -import java.security.spec.InvalidKeySpecException; -import java.util.*; - -import static com.github.tomakehurst.wiremock.client.WireMock.*; -import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; -import static com.sap.cloud.security.config.Service.IAS; -import static com.sap.cloud.security.config.Service.XSUAA; -import static com.sap.cloud.security.xsuaa.client.OidcConfigurationService.DISCOVERY_ENDPOINT_DEFAULT; public class SecurityTest implements SecurityTestContext, ServiceMockConfiguration, ApplicationServerConfiguration { @@ -228,7 +240,7 @@ void startApplicationServer() throws Exception { WebAppContext context = new WebAppContext(); context.setContextPath("/"); - context.setResourceBase("src/main/webapp"); + context.setBaseResourceAsString("src/main/webapp"); context.setSecurityHandler(security); applicationServletsByPath diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTestRule.java b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTestRule.java index a63b93bbc..70ffb2827 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTestRule.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/SecurityTestRule.java @@ -5,6 +5,11 @@ */ package com.sap.cloud.security.test; +import javax.annotation.Nullable; + +import org.eclipse.jetty.ee10.servlet.ServletHolder; +import org.junit.rules.ExternalResource; + import com.github.tomakehurst.wiremock.WireMockServer; import com.sap.cloud.security.config.OAuth2ServiceConfigurationBuilder; import com.sap.cloud.security.config.Service; @@ -12,12 +17,9 @@ import com.sap.cloud.security.test.api.SecurityTestContext; import com.sap.cloud.security.test.api.ServiceMockConfiguration; import com.sap.cloud.security.token.Token; + import jakarta.servlet.Filter; import jakarta.servlet.Servlet; -import org.eclipse.jetty.ee9.servlet.ServletHolder; -import org.junit.rules.ExternalResource; - -import javax.annotation.Nullable; public class SecurityTestRule extends ExternalResource implements SecurityTestContext, ServiceMockConfiguration, ApplicationServerConfiguration { diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/api/ApplicationServerConfiguration.java b/java-security-test/src/main/java/com/sap/cloud/security/test/api/ApplicationServerConfiguration.java index 962a66f45..eb39604f6 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/api/ApplicationServerConfiguration.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/api/ApplicationServerConfiguration.java @@ -5,12 +5,14 @@ */ package com.sap.cloud.security.test.api; +import org.eclipse.jetty.ee10.servlet.ServletHolder; + import com.sap.cloud.security.config.Service; import com.sap.cloud.security.test.ApplicationServerOptions; import com.sap.cloud.security.test.SecurityTestRule; + import jakarta.servlet.Filter; import jakarta.servlet.Servlet; -import org.eclipse.jetty.ee9.servlet.ServletHolder; public interface ApplicationServerConfiguration { diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/extension/SecurityTestExtension.java b/java-security-test/src/main/java/com/sap/cloud/security/test/extension/SecurityTestExtension.java index 693be82f4..639f04172 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/extension/SecurityTestExtension.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/extension/SecurityTestExtension.java @@ -13,7 +13,7 @@ import com.sap.cloud.security.test.api.ServiceMockConfiguration; import jakarta.servlet.Filter; import jakarta.servlet.Servlet; -import org.eclipse.jetty.ee9.servlet.ServletHolder; +import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.junit.jupiter.api.extension.*; /** diff --git a/java-security-test/src/main/java/com/sap/cloud/security/test/jetty/JettyTokenAuthenticator.java b/java-security-test/src/main/java/com/sap/cloud/security/test/jetty/JettyTokenAuthenticator.java index dd1897ec7..cf53cd76f 100644 --- a/java-security-test/src/main/java/com/sap/cloud/security/test/jetty/JettyTokenAuthenticator.java +++ b/java-security-test/src/main/java/com/sap/cloud/security/test/jetty/JettyTokenAuthenticator.java @@ -5,31 +5,37 @@ */ package com.sap.cloud.security.test.jetty; +import java.security.Principal; +import java.util.HashSet; +import java.util.Set; +import java.util.function.Function; + +import javax.security.auth.Subject; + +import org.eclipse.jetty.ee10.servlet.ServletContextRequest; +import org.eclipse.jetty.ee10.servlet.ServletContextResponse; +import org.eclipse.jetty.security.AuthenticationState; +import org.eclipse.jetty.security.Authenticator; +import org.eclipse.jetty.security.Constraint.Authorization; +import org.eclipse.jetty.security.ServerAuthException; +import org.eclipse.jetty.security.authentication.LoginAuthenticator; +import org.eclipse.jetty.security.internal.DefaultUserIdentity; +import org.eclipse.jetty.server.Request; +import org.eclipse.jetty.server.Response; +import org.eclipse.jetty.server.Session; +import org.eclipse.jetty.util.Callback; + import com.sap.cloud.security.servlet.TokenAuthenticationResult; import com.sap.cloud.security.servlet.TokenAuthenticator; + import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; import jakarta.servlet.http.HttpServletResponse; -import org.eclipse.jetty.ee9.security.Authenticator; -import org.eclipse.jetty.ee9.security.UserAuthentication; -import org.eclipse.jetty.ee9.nested.Authentication; -import org.eclipse.jetty.security.internal.DefaultUserIdentity; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.security.auth.Subject; -import java.io.IOException; -import java.security.Principal; -import java.util.HashSet; -import java.util.Set; - /** * Decorates the TokenAuthenticator and adapts it to Jetty. */ public class JettyTokenAuthenticator implements Authenticator { - private static final Logger LOGGER = LoggerFactory.getLogger(JettyTokenAuthenticator.class); - private final TokenAuthenticator tokenAuthenticator; public JettyTokenAuthenticator(TokenAuthenticator tokenAuthenticator) { @@ -37,52 +43,39 @@ public JettyTokenAuthenticator(TokenAuthenticator tokenAuthenticator) { } @Override - public Authentication validateRequest(ServletRequest request, ServletResponse response, boolean mandatory) { - TokenAuthenticationResult tokenAuthenticationResult = tokenAuthenticator.validateRequest(request, response); - if (tokenAuthenticationResult.isAuthenticated()) { - return createAuthentication(tokenAuthenticationResult); - } else { - sendUnauthenticatedResponse(response, tokenAuthenticationResult.getUnauthenticatedReason()); - return Authentication.UNAUTHENTICATED; - } - } - - private void sendUnauthenticatedResponse(ServletResponse response, String unauthenticatedReason) { - if (response instanceof HttpServletResponse) { - try { - HttpServletResponse httpServletResponse = (HttpServletResponse) response; - httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, unauthenticatedReason); // 401 - } catch (IOException e) { - LOGGER.error("Failed to send error response", e); - } - } - } - - @Override - public void setConfiguration(AuthConfiguration configuration) { + public void setConfiguration(Configuration configuration) { } @Override - public String getAuthMethod() { + public String getAuthenticationType() { return "Token"; } @Override - public void prepareRequest(ServletRequest request) { + public Authorization getConstraintAuthentication(String pathInContext, Authorization existing, Function getSession) { + return Authorization.ANY_USER; } @Override - public boolean secureResponse(ServletRequest request, ServletResponse response, boolean mandatory, - Authentication.User validatedUser) { - return true; + public AuthenticationState validateRequest(Request request, Response response, Callback callback) throws ServerAuthException { + ServletRequest servletRequest = request instanceof ServletContextRequest scr ? scr.getServletApiRequest() : null; + ServletResponse servletResponse = response instanceof ServletContextResponse scr ? scr.getServletApiResponse() : null; + + TokenAuthenticationResult tokenAuthenticationResult = tokenAuthenticator.validateRequest(servletRequest, servletResponse); + if (tokenAuthenticationResult.isAuthenticated()) { + return createAuthentication(tokenAuthenticationResult); + } else { + Response.writeError(request, response, callback, HttpServletResponse.SC_UNAUTHORIZED, tokenAuthenticationResult.getUnauthenticatedReason()); + return AuthenticationState.SEND_FAILURE; + } } - private Authentication createAuthentication(TokenAuthenticationResult tokenAuthentication) { + private AuthenticationState createAuthentication(TokenAuthenticationResult tokenAuthentication) { Principal principal = tokenAuthentication.getPrincipal(); Set principals = new HashSet<>(); principals.add(principal); Subject subject = new Subject(true, principals, new HashSet<>(), new HashSet<>()); String[] scopes = tokenAuthentication.getScopes().toArray(new String[0]); - return new UserAuthentication(getAuthMethod(), new DefaultUserIdentity(subject, principal, scopes)); + return new LoginAuthenticator.UserAuthenticationSucceeded(getAuthenticationType(), new DefaultUserIdentity(subject, principal, scopes)); } } diff --git a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java index bf2a3bcfc..9ef9776af 100644 --- a/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java +++ b/java-security-test/src/test/java/com/sap/cloud/security/test/SecurityTestRuleTest.java @@ -21,7 +21,7 @@ import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClients; -import org.eclipse.jetty.ee9.servlet.ServletHolder; +import org.eclipse.jetty.ee10.servlet.ServletHolder; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test;