From 98df4e1d07d9ced5ca3d3bde7a22a8e34d5bac1d Mon Sep 17 00:00:00 2001 From: Arjan Tijms Date: Mon, 28 Mar 2022 21:27:13 +0200 Subject: [PATCH] Initial commit for Jakarta Authentication TCK Signed-off-by: Arjan Tijms --- pom.xml | 35 + tck/async-authentication/pom.xml | 51 ++ .../bean/AsyncBean.java | 53 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 99 +++ .../servlet/AsyncServlet.java | 51 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../AsyncAuthenticationPublicTest.java | 54 ++ tck/basic-authentication/pom.xml | 77 +++ .../sam/SamAutoRegistrationListener.java | 37 + .../test/basic/sam/TestServerAuthModule.java | 100 +++ .../test/basic/servlet/ProtectedServlet.java | 54 ++ .../test/basic/servlet/PublicServlet.java | 54 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../BasicAuthenticationProtectedTest.java | 85 +++ .../basic/BasicAuthenticationPublicTest.java | 67 ++ .../BasicAuthenticationStatelessTest.java | 201 ++++++ tck/common/pom.xml | 72 ++ .../test/common/ArquillianBase.java | 184 +++++ tck/custom-principal/pom.xml | 39 ++ .../test/customprincipal/sam/MyPrincipal.java | 38 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 101 +++ .../servlet/ProtectedServlet.java | 59 ++ .../servlet/PublicServlet.java | 58 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../CustomPrincipalProtectedTest.java | 71 ++ .../CustomPrincipalPublicTest.java | 67 ++ .../CustomPrincipalStatelessTest.java | 195 ++++++ tck/dispatching-jsf-cdi/pom.xml | 51 ++ .../test/dispatching/bean/MyBean.java | 38 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../dispatching/sam/TestServerAuthModule.java | 108 +++ .../dispatching/servlet/ForwardedServlet.java | 57 ++ .../dispatching/servlet/IncludedServlet.java | 46 ++ .../dispatching/servlet/ProtectedServlet.java | 40 ++ .../dispatching/servlet/PublicServlet.java | 40 ++ .../src/main/webapp/WEB-INF/beans.xml | 0 .../src/main/webapp/WEB-INF/faces-config.xml | 5 + .../src/main/webapp/WEB-INF/web.xml | 36 + .../src/main/webapp/forward-cdi.xhtml | 11 + .../src/main/webapp/forward.xhtml | 11 + .../src/main/webapp/include-cdi.xhtml | 27 + .../src/main/webapp/include.xhtml | 27 + .../test/dispatching/CDIForwardTest.java | 107 +++ .../test/dispatching/CDIIncludeTest.java | 65 ++ .../test/dispatching/JSFCDIForwardTest.java | 70 ++ .../test/dispatching/JSFCDIIncludeTest.java | 70 ++ .../test/dispatching/JSFForwardTest.java | 68 ++ tck/dispatching/pom.xml | 39 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../dispatching/sam/TestServerAuthModule.java | 90 +++ .../dispatching/servlet/ForwardedServlet.java | 41 ++ .../dispatching/servlet/IncludedServlet.java | 41 ++ .../dispatching/servlet/ProtectedServlet.java | 40 ++ .../dispatching/servlet/PublicServlet.java | 40 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../test/dispatching/BasicForwardTest.java | 64 ++ .../test/dispatching/BasicIncludeTest.java | 64 ++ tck/ejb-propagation/pom.xml | 51 ++ .../test/ejbpropagation/ejb/ProtectedEJB.java | 66 ++ .../test/ejbpropagation/ejb/PublicEJB.java | 43 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 88 +++ .../servlet/ProtectedServletProtectedEJB.java | 77 +++ .../servlet/ProtectedServletPublicEJB.java | 64 ++ .../servlet/PublicServletProtectedEJB.java | 77 +++ .../servlet/PublicServletPublicEJB.java | 64 ++ .../servlet/PublicServletPublicEJBLogout.java | 84 +++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../ProtectedEJBPropagationTest.java | 98 +++ .../PublicEJBPropagationLogoutTest.java | 81 +++ .../PublicEJBPropagationTest.java | 61 ++ tck/ejb-register-session/pom.xml | 51 ++ .../registersession/ejb/ProtectedEJB.java | 66 ++ .../test/registersession/ejb/PublicEJB.java | 42 ++ .../test/registersession/sam/MyPrincipal.java | 38 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 121 ++++ .../servlet/ProtectedServlet.java | 60 ++ .../servlet/PublicServlet.java | 60 ++ .../servlet/PublicServletProtectedEJB.java | 77 +++ .../servlet/PublicServletPublicEJB.java | 64 ++ .../src/main/webapp/WEB-INF/web.xml | 37 + ...sionCustomPrincipalEJBPropagationTest.java | 164 +++++ .../RegisterSessionEJBPropagationTest.java | 164 +++++ tck/invoke-ejb-cdi/pom.xml | 51 ++ .../test/invoke/bean/CDIBean.java | 38 ++ .../test/invoke/bean/EJBBean.java | 27 + .../sam/SamAutoRegistrationListener.java | 37 + .../test/invoke/sam/TestServerAuthModule.java | 144 ++++ .../test/invoke/servlet/ProtectedServlet.java | 41 ++ .../test/invoke/servlet/PublicServlet.java | 41 ++ .../src/main/webapp/WEB-INF/beans.xml | 0 .../src/main/webapp/WEB-INF/web.xml | 36 + .../invoke/InvokeCDIBeanProtectedTest.java | 76 +++ .../test/invoke/InvokeCDIBeanPublicTest.java | 106 +++ .../invoke/InvokeEJBBeanProtectedTest.java | 73 ++ .../test/invoke/InvokeEJBBeanPublicTest.java | 73 ++ tck/jacc-propagation/pom.xml | 51 ++ .../jacc/JakartaAuthorization.java | 61 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 88 +++ .../servlet/ProtectedServlet.java | 42 ++ .../servlet/PublicServlet.java | 49 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../AuthzPropagationProtectedTest.java | 69 ++ .../AuthzPropagationPublicTest.java | 106 +++ tck/lifecycle/pom.xml | 39 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestLifecycleAuthModule.java | 107 +++ .../lifecycle/servlet/ProtectedServlet.java | 45 ++ .../test/lifecycle/servlet/PublicServlet.java | 45 ++ tck/lifecycle/src/main/webapp/WEB-INF/web.xml | 36 + .../AuthModuleMethodInvocationTest.java | 98 +++ .../test/lifecycle/IsMandatoryTest.java | 67 ++ tck/pom.xml | 643 ++++++++++++++++++ tck/programmatic-authentication/pom.xml | 39 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 100 +++ .../servlet/AuthenticateServlet.java | 88 +++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../ProgrammaticAuthenticationTest.java | 100 +++ tck/register-session/pom.xml | 40 ++ .../test/registersession/sam/MyPrincipal.java | 38 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../sam/TestServerAuthModule.java | 121 ++++ .../servlet/ProtectedServlet.java | 53 ++ .../servlet/PublicServlet.java | 53 ++ .../src/main/webapp/WEB-INF/web.xml | 37 + .../RegisterSessionCustomPrincipalTest.java | 212 ++++++ .../registersession/RegisterSessionTest.java | 202 ++++++ tck/status-codes/pom.xml | 39 ++ .../sam/SamAutoRegistrationListener.java | 37 + .../statuscodes/sam/TestServerAuthModule.java | 66 ++ .../statuscodes/servlet/ProtectedServlet.java | 41 ++ .../statuscodes/servlet/PublicServlet.java | 41 ++ .../src/main/webapp/WEB-INF/web.xml | 36 + .../statuscodes/ProtectedStatusCodesTest.java | 59 ++ .../statuscodes/PublicStatusCodesTest.java | 59 ++ tck/wrapping/pom.xml | 39 ++ .../sam/SamAutoRegistrationListener.java | 45 ++ .../sam/TestWrappingServerAuthModule.java | 110 +++ .../test/wrapping/servlet/DeclaredFilter.java | 61 ++ .../wrapping/servlet/ProgrammaticFilter.java | 59 ++ .../wrapping/servlet/ProtectedServlet.java | 49 ++ .../TestHttpServletRequestWrapper.java | 42 ++ .../TestHttpServletResponseWrapper.java | 42 ++ tck/wrapping/src/main/webapp/WEB-INF/web.xml | 36 + .../test/wrapping/WrappingTest.java | 105 +++ tck/zip.xml | 38 ++ 151 files changed, 9994 insertions(+) create mode 100644 tck/async-authentication/pom.xml create mode 100644 tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/bean/AsyncBean.java create mode 100644 tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/SamAutoRegistrationListener.java create mode 100644 tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/TestServerAuthModule.java create mode 100644 tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/servlet/AsyncServlet.java create mode 100644 tck/async-authentication/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/async-authentication/src/test/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/AsyncAuthenticationPublicTest.java create mode 100644 tck/basic-authentication/pom.xml create mode 100644 tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/SamAutoRegistrationListener.java create mode 100644 tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/TestServerAuthModule.java create mode 100644 tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/ProtectedServlet.java create mode 100644 tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/PublicServlet.java create mode 100644 tck/basic-authentication/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationProtectedTest.java create mode 100644 tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationPublicTest.java create mode 100644 tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationStatelessTest.java create mode 100644 tck/common/pom.xml create mode 100644 tck/common/src/main/java/ee/jakarta/tck/authentication/test/common/ArquillianBase.java create mode 100644 tck/custom-principal/pom.xml create mode 100644 tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/MyPrincipal.java create mode 100644 tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/SamAutoRegistrationListener.java create mode 100644 tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/TestServerAuthModule.java create mode 100644 tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/ProtectedServlet.java create mode 100644 tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/PublicServlet.java create mode 100644 tck/custom-principal/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalProtectedTest.java create mode 100644 tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalPublicTest.java create mode 100644 tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalStatelessTest.java create mode 100644 tck/dispatching-jsf-cdi/pom.xml create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/bean/MyBean.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java create mode 100644 tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/beans.xml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/faces-config.xml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/forward-cdi.xhtml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/forward.xhtml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/include-cdi.xhtml create mode 100644 tck/dispatching-jsf-cdi/src/main/webapp/include.xhtml create mode 100644 tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIForwardTest.java create mode 100644 tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIIncludeTest.java create mode 100644 tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIForwardTest.java create mode 100644 tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIIncludeTest.java create mode 100644 tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFForwardTest.java create mode 100644 tck/dispatching/pom.xml create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java create mode 100644 tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java create mode 100644 tck/dispatching/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicForwardTest.java create mode 100644 tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicIncludeTest.java create mode 100644 tck/ejb-propagation/pom.xml create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/ProtectedEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/PublicEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/SamAutoRegistrationListener.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/TestServerAuthModule.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletProtectedEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletPublicEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletProtectedEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJB.java create mode 100644 tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJBLogout.java create mode 100644 tck/ejb-propagation/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/ProtectedEJBPropagationTest.java create mode 100644 tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationLogoutTest.java create mode 100644 tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationTest.java create mode 100644 tck/ejb-register-session/pom.xml create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/ProtectedEJB.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/PublicEJB.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletProtectedEJB.java create mode 100644 tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletPublicEJB.java create mode 100644 tck/ejb-register-session/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java create mode 100644 tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionEJBPropagationTest.java create mode 100644 tck/invoke-ejb-cdi/pom.xml create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/CDIBean.java create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/EJBBean.java create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/SamAutoRegistrationListener.java create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/TestServerAuthModule.java create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/ProtectedServlet.java create mode 100644 tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/PublicServlet.java create mode 100644 tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/beans.xml create mode 100644 tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanProtectedTest.java create mode 100644 tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanPublicTest.java create mode 100644 tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanProtectedTest.java create mode 100644 tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanPublicTest.java create mode 100644 tck/jacc-propagation/pom.xml create mode 100644 tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/jacc/JakartaAuthorization.java create mode 100644 tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/SamAutoRegistrationListener.java create mode 100644 tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/TestServerAuthModule.java create mode 100644 tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/ProtectedServlet.java create mode 100644 tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/PublicServlet.java create mode 100644 tck/jacc-propagation/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationProtectedTest.java create mode 100644 tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationPublicTest.java create mode 100644 tck/lifecycle/pom.xml create mode 100644 tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/SamAutoRegistrationListener.java create mode 100644 tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/TestLifecycleAuthModule.java create mode 100644 tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/ProtectedServlet.java create mode 100644 tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/PublicServlet.java create mode 100644 tck/lifecycle/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/AuthModuleMethodInvocationTest.java create mode 100644 tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/IsMandatoryTest.java create mode 100644 tck/pom.xml create mode 100644 tck/programmatic-authentication/pom.xml create mode 100644 tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/SamAutoRegistrationListener.java create mode 100644 tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/TestServerAuthModule.java create mode 100644 tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/servlet/AuthenticateServlet.java create mode 100644 tck/programmatic-authentication/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/programmatic-authentication/src/test/java/ee/jakarta/tck/authentication/test/programmaticauthentication/ProgrammaticAuthenticationTest.java create mode 100644 tck/register-session/pom.xml create mode 100644 tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java create mode 100644 tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java create mode 100644 tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java create mode 100644 tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java create mode 100644 tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java create mode 100644 tck/register-session/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalTest.java create mode 100644 tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionTest.java create mode 100644 tck/status-codes/pom.xml create mode 100644 tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/SamAutoRegistrationListener.java create mode 100644 tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/TestServerAuthModule.java create mode 100644 tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/ProtectedServlet.java create mode 100644 tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/PublicServlet.java create mode 100644 tck/status-codes/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/ProtectedStatusCodesTest.java create mode 100644 tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/PublicStatusCodesTest.java create mode 100644 tck/wrapping/pom.xml create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/SamAutoRegistrationListener.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/TestWrappingServerAuthModule.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/DeclaredFilter.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProgrammaticFilter.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProtectedServlet.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletRequestWrapper.java create mode 100644 tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletResponseWrapper.java create mode 100644 tck/wrapping/src/main/webapp/WEB-INF/web.xml create mode 100644 tck/wrapping/src/test/java/ee/jakarta/tck/authentication/test/wrapping/WrappingTest.java create mode 100644 tck/zip.xml diff --git a/pom.xml b/pom.xml index 82802d8..7157be7 100644 --- a/pom.xml +++ b/pom.xml @@ -99,5 +99,40 @@ + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + + + maven-dependency-plugin + + + [3.1.2,) + + + unpack + + + + + + + + + + + + diff --git a/tck/async-authentication/pom.xml b/tck/async-authentication/pom.xml new file mode 100644 index 0000000..939cdb6 --- /dev/null +++ b/tck/async-authentication/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + async-authentication + war + + Jakarta Authentication TCK - async-authentication + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipEJB} + + + + + diff --git a/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/bean/AsyncBean.java b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/bean/AsyncBean.java new file mode 100644 index 0000000..42ff3b6 --- /dev/null +++ b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/bean/AsyncBean.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbasyncauthentication.bean; + +import static java.lang.Thread.interrupted; +import static java.lang.Thread.sleep; + +import java.io.IOException; + +import jakarta.ejb.Asynchronous; +import jakarta.ejb.Stateless; +import jakarta.servlet.AsyncContext; + +/** + * + * @author Arjan Tijms + * + */ +@Stateless +public class AsyncBean { + + @Asynchronous + public void doAsync(AsyncContext asyncContext) { + + try { + sleep(1000); + } catch (InterruptedException e) { + interrupted(); + } + + try { + asyncContext.getResponse().getWriter().write("async response"); + } catch (IOException e) { + e.printStackTrace(); + } + + asyncContext.complete(); + } + +} diff --git a/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/SamAutoRegistrationListener.java b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..1afeb9b --- /dev/null +++ b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbasyncauthentication.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/TestServerAuthModule.java b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/TestServerAuthModule.java new file mode 100644 index 0000000..d1d9a59 --- /dev/null +++ b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/sam/TestServerAuthModule.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbasyncauthentication.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic SAM that returns a single hardcoded user named "test" with role "architect" when the request parameter + * doLogin is present. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getParameter("doLogin") != null) { + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user + new CallerPrincipalCallback(clientSubject, "test"), + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) + }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } +} \ No newline at end of file diff --git a/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/servlet/AsyncServlet.java b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/servlet/AsyncServlet.java new file mode 100644 index 0000000..fddd344 --- /dev/null +++ b/tck/async-authentication/src/main/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/servlet/AsyncServlet.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbasyncauthentication.servlet; + +import java.io.IOException; + +import ee.jakarta.tck.authentication.test.ejbasyncauthentication.bean.AsyncBean; +import jakarta.ejb.EJB; +import jakarta.servlet.AsyncContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/asyncServlet", asyncSupported = true) +public class AsyncServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @EJB + private AsyncBean asyncBean; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + AsyncContext asyncContext = request.startAsync(); + asyncContext.setTimeout(5000); + + asyncBean.doAsync(asyncContext); + } + +} \ No newline at end of file diff --git a/tck/async-authentication/src/main/webapp/WEB-INF/web.xml b/tck/async-authentication/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/async-authentication/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/async-authentication/src/test/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/AsyncAuthenticationPublicTest.java b/tck/async-authentication/src/test/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/AsyncAuthenticationPublicTest.java new file mode 100644 index 0000000..ec9f2a0 --- /dev/null +++ b/tck/async-authentication/src/test/java/ee/jakarta/tck/authentication/test/ejbasyncauthentication/AsyncAuthenticationPublicTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbasyncauthentication; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class AsyncAuthenticationPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + /** + * This tests that an async response works at all in the mere presence of + * a JASPIC SAM (that does nothing) + */ + @Test + public void testBasicAsync() throws IOException { + String response = getFromServerPath("public/asyncServlet"); + assertTrue(response.contains("async response")); + } + +} \ No newline at end of file diff --git a/tck/basic-authentication/pom.xml b/tck/basic-authentication/pom.xml new file mode 100644 index 0000000..bd9088c --- /dev/null +++ b/tck/basic-authentication/pom.xml @@ -0,0 +1,77 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + basic-authentication + war + + Jakarta Authentication TCK - basic-authentication + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + + + maven-dependency-plugin + + + [3.2.0,) + + + unpack + + + + + + + + + + + + + + diff --git a/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/SamAutoRegistrationListener.java b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..84742e5 --- /dev/null +++ b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.basic.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/TestServerAuthModule.java b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/TestServerAuthModule.java new file mode 100644 index 0000000..6c619a9 --- /dev/null +++ b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/sam/TestServerAuthModule.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.basic.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic ServerAuthModule that returns a single hardcoded user named "test" with role "architect" when the request parameter + * doLogin is present. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getParameter("doLogin") != null) { + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user + new CallerPrincipalCallback(clientSubject, "test"), + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) + }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/ProtectedServlet.java b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/ProtectedServlet.java new file mode 100644 index 0000000..92d81d1 --- /dev/null +++ b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/ProtectedServlet.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.basic.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a protected servlet \n"); + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + response.getWriter().write("web username: " + webName + "\n"); + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/PublicServlet.java b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/PublicServlet.java new file mode 100644 index 0000000..b4826b6 --- /dev/null +++ b/tck/basic-authentication/src/main/java/ee/jakarta/tck/authentication/test/basic/servlet/PublicServlet.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.basic.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a public servlet \n"); + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + response.getWriter().write("web username: " + webName + "\n"); + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/basic-authentication/src/main/webapp/WEB-INF/web.xml b/tck/basic-authentication/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/basic-authentication/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationProtectedTest.java b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationProtectedTest.java new file mode 100644 index 0000000..5383520 --- /dev/null +++ b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationProtectedTest.java @@ -0,0 +1,85 @@ +package ee.jakarta.tck.authentication.test.basic; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that we can login from a protected resource (a resource for which + * security constraints have been set) and then access it. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class BasicAuthenticationProtectedTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testProtectedPageNotLoggedin() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse( + "Not authenticated, so should not have been able to access protected resource", + response.contains("This is a protected servlet") + ); + } + + @Test + public void testProtectedPageLoggedin() throws IOException { + + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Should have been authenticated, but could not access protected resource", + response.contains("This is a protected servlet") + ); + + // Not only does the page needs to be accessible, the caller should have + // the correct + // name and roles as well + + // Being able to access a page protected by a role but then seeing the un-authenticated + // (anonymous) user would normally be impossible, but could happen if the authorization + // system checks roles on the authenticated subject, but does not correctly expose + // or propagate these to the HttpServletRequest + assertFalse( + "Protected resource could be accessed, but the user appears to be the unauthenticated user. " + + "This should not be possible", + response.contains("web username: null") + ); + + // An authenticated user should have the exact name "test" and nothing else. + assertTrue( + "Protected resource could be accessed, but the username is not correct.", + response.contains("web username: test") + ); + + // Being able to access a page protected by role "architect" but failing + // the test for this role would normally be impossible, but could happen if the + // authorization system checks roles on the authenticated subject, but does not + // correctly expose or propagate these to the HttpServletRequest + assertTrue( + "Resource protected by role \"architect\" could be accessed, but user fails test for this role." + + "This should not be possible", + response.contains("web user has role \"architect\": true") + ); + } + +} \ No newline at end of file diff --git a/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationPublicTest.java b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationPublicTest.java new file mode 100644 index 0000000..14583fd --- /dev/null +++ b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationPublicTest.java @@ -0,0 +1,67 @@ +package ee.jakarta.tck.authentication.test.basic; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that we can login from a public page (a page for which no security constraints have been set). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class BasicAuthenticationPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testPublicPageNotLoggedin() throws IOException { + + String response = getFromServerPath("public/servlet"); + + // Not logged-in + assertTrue( + "Not authenticated, but a username other than null was encountered. " + + "This is not correct.", + response.contains("web username: null") + ); + assertTrue( + "Not authenticated, but the user seems to have the role \"architect\". " + + "This is not correct.", + response.contains("web user has role \"architect\": false") + ); + } + + @Test + public void testPublicPageLoggedin() throws IOException { + + // JASPIC has to be able to authenticate a user when accessing a public (non-protected) resource. + + String response = getFromServerPath("public/servlet?doLogin=true"); + + // Now has to be logged-in + assertTrue( + "User should have been authenticated and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "User should have been authenticated and given role \"architect\", " + + " but does not appear to have this role", + response.contains("web user has role \"architect\": true") + ); + } + +} \ No newline at end of file diff --git a/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationStatelessTest.java b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationStatelessTest.java new file mode 100644 index 0000000..e6edf0e --- /dev/null +++ b/tck/basic-authentication/src/test/java/ee/jakarta/tck/authentication/test/basic/BasicAuthenticationStatelessTest.java @@ -0,0 +1,201 @@ +package ee.jakarta.tck.authentication.test.basic; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class BasicAuthenticationStatelessTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + /** + * Tests that access to a protected page does not depend on the authenticated identity that was established in a previous + * request. + */ + @Test + public void testProtectedAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 2 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // If the following fails but "testProtectedPageLoggedin" has succeeded, + // the container has probably remembered the "unauthenticated identity", e.g. it has remembered that + // we're not authenticated and it will deny further attempts to authenticate. This may happen when + // the container does not correctly recognize The Jakarta Authentication protocol for "do nothing". + + response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + + // -------------------- Request 3 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // In the following method we do a call without logging in after one where we did login. + // The container should not remember this login and has to deny access. + response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse( + "Could access protected page, but should not be able to. " + + "Did the container remember the authenticated identity that was set in previous request?", + response.contains("This is a protected servlet") + ); + } + + /** + * Tests that access to a protected page does not depend on the authenticated identity that was established in a previous + * request, but use a different request order than the previous test. + */ + @Test + public void testProtectedAccessIsStateless2() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Start with doing a login + String response = getFromServerPath("protected/servlet?doLogin=true"); + + + // -------------------- Request 2 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // In the following method we do a call without logging in after one where we did login. + // The container should not remember this login and has to deny access. + + // Accessing protected page without login + response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse( + "Could access protected page, but should not be able to. " + + "Did the container remember the authenticated identity that was set in the previous request?", + response.contains("This is a protected servlet") + ); + } + + /** + * Tests that access to a public page does not depend on the authenticated identity that was established in a previous + * request. + */ + @Test + public void testPublicAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + String response = getFromServerPath("public/servlet"); + + // Establish that we're initially not logged-in + assertTrue( + "Not authenticated, but a username other than null was encountered. " + + "This is not correct.", + response.contains("web username: null") + ); + assertTrue( + "Not authenticated, but the user seems to have the role \"architect\". " + + "This is not correct.", + response.contains("web user has role \"architect\": false") + ); + + + // -------------------- Request 2 --------------------------- + + response = getFromServerPath("public/servlet?doLogin=true"); + + // Now has to be logged-in + assertTrue( + "User should have been authenticated and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue(response.contains("web user has role \"architect\": true")); + + + // -------------------- Request 3 --------------------------- + + // Accessing public page without login + response = getFromServerPath("public/servlet"); + + // No details should linger around + assertTrue( + "Should not be authenticated, but a username other than null was encountered. " + + "Did the container remember the authenticated identity that was set in the previous request?", + response.contains("web username: null") + ); + assertTrue( + "The unauthenticated user has the role 'architect', which should not be the case. " + + "The container seemed to have remembered it from the previous request.", + response.contains("web user has role \"architect\": false") + ); + } + + /** + * Tests independently from being able to access a protected resource if any details of a previously established + * authenticated identity are remembered + */ + @Test + public void testProtectedThenPublicAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page with login + String response = getFromServerPath("protected/servlet?doLogin=true"); + + + // -------------------- Request 2 --------------------------- + + // Accessing public page without login + response = getFromServerPath("public/servlet"); + + // No details should linger around + assertFalse( + "User principal was 'test', but it should be null here. " + + "The container seemed to have remembered it from the previous request.", + response.contains("web username: test") + ); + assertTrue( + "User principal was not null, but it should be null here. ", + response.contains("web username: null") + ); + assertTrue( + "The unauthenticated user has the role 'architect', which should not be the case. " + + "The container seemed to have remembered it from the previous request.", + response.contains("web user has role \"architect\": false") + ); + } + +} \ No newline at end of file diff --git a/tck/common/pom.xml b/tck/common/pom.xml new file mode 100644 index 0000000..76ef1b0 --- /dev/null +++ b/tck/common/pom.xml @@ -0,0 +1,72 @@ + + + + 4.0.0 + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + jar + + Jakarta Authentication TCK - common + + + UTF-8 + 11 + 11 + + + + + + org.jboss.arquillian + arquillian-bom + 1.1.14.Final + pom + import + + + + + + org.jboss.arquillian.junit + arquillian-junit-container + provided + + + junit + junit + 4.11 + provided + + + net.sourceforge.htmlunit + htmlunit + 2.37.0 + provided + + + org.jsoup + jsoup + 1.9.1 + + + diff --git a/tck/common/src/main/java/ee/jakarta/tck/authentication/test/common/ArquillianBase.java b/tck/common/src/main/java/ee/jakarta/tck/authentication/test/common/ArquillianBase.java new file mode 100644 index 0000000..51c977b --- /dev/null +++ b/tck/common/src/main/java/ee/jakarta/tck/authentication/test/common/ArquillianBase.java @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.common; + +import static java.lang.Boolean.getBoolean; +import static java.util.logging.Level.SEVERE; +import static org.jboss.shrinkwrap.api.ShrinkWrap.create; +import static org.jsoup.Jsoup.parse; +import static org.jsoup.parser.Parser.xmlParser; + +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.util.Map; +import java.util.logging.Logger; + +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ArchivePath; +import org.jboss.shrinkwrap.api.Node; +import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestWatcher; +import org.junit.runner.Description; + +import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; +import com.gargoylesoftware.htmlunit.WebClient; + +/** + * + * @author Arjan Tijms + * + */ +public class ArquillianBase { + + private static final String WEBAPP_SRC = "src/main/webapp"; + private static final Logger logger = Logger.getLogger(ArquillianBase.class.getName()); + + private WebClient webClient; + private String response; + + @Rule + public TestWatcher ruleExample = new TestWatcher() { + @Override + protected void failed(Throwable e, Description description) { + super.failed(e, description); + + logger.log(SEVERE, + "\n\nTest failed: " + + description.getClassName() + "." + description.getMethodName() + + + "\nMessage: " + e.getMessage() + + + "\nLast response: " + + + "\n\n" + formatHTML(response) + "\n\n"); + + } + }; + + public static String formatHTML(String html) { + try { + return parse(html, "", xmlParser()).toString(); + } catch (Exception e) { + return html; + } + } + + public static Archive defaultArchive() { + return tryWrapEAR(defaultWebArchive()); + } + + public static WebArchive defaultWebArchive() { + return + removeTestClasses( + create(WebArchive.class, "test.war") + .addPackages(true, "ee.jakarta.tck.authentication.test") + .addAsWebInfResource(resource("web.xml")) + ); + } + + private static WebArchive removeTestClasses(WebArchive archive) { + for (Map.Entry content : archive.getContent().entrySet()) { + if (content.getKey().get().endsWith("Test.class")) { + archive.delete(content.getKey().get()); + } + } + archive.deleteClass(ArquillianBase.class); + + return archive; + } + + public static Archive tryWrapEAR(WebArchive webArchive) { + if (getBoolean("useEarForJaspic")) { + return + // EAR archive + create(EnterpriseArchive.class, "test.ear") + + // Web module + // This is needed to prevent Arquillian generating an illegal application.xml + .addAsModule( + webArchive + ); + } else { + return webArchive; + } + } + + public static File resource(String name) { + return new File(WEBAPP_SRC + "/WEB-INF", name); + } + + public static File web(String name) { + return new File(WEBAPP_SRC, name); + } + + @ArquillianResource + private URL base; + + @Before + public void setUp() { + webClient = new WebClient(); + webClient.getOptions().setThrowExceptionOnFailingStatusCode(false); + if (System.getProperty("glassfish.suspend") != null) { + webClient.getOptions().setTimeout(0); + } + } + + @After + public void tearDown() { + webClient.getCookieManager().clearCookies(); + webClient.close(); + } + + + + protected WebClient getWebClient() { + return webClient; + } + + protected URL getBase() { + return base; + } + + /** + * Gets content from the path that's relative to the base URL on which the Arquillian test + * archive is deployed. + * + * @param path the path relative to the URL on which the Arquillian test is deployed + * @return the raw content as a string as returned by the server + */ + protected String getFromServerPath(final String path) { + response = null; + for (int i=0; i<=3; i++) { + try { + response = webClient.getPage(base + path).getWebResponse().getContentAsString(); + if (!response.contains("The response wrapper must wrap the response obtained from getResponse()")) { + return response; + } + } catch (FailingHttpStatusCodeException | IOException e) { + throw new IllegalStateException(e); + } + } + + return response; + } + +} diff --git a/tck/custom-principal/pom.xml b/tck/custom-principal/pom.xml new file mode 100644 index 0000000..b75f778 --- /dev/null +++ b/tck/custom-principal/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + custom-principal + war + + Jakarta Authentication TCK - custom principal + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/MyPrincipal.java b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/MyPrincipal.java new file mode 100644 index 0000000..c6a5b49 --- /dev/null +++ b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/MyPrincipal.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal.sam; + +import java.security.Principal; + +/** + * + * @author Arjan Tijms + * + */ +public class MyPrincipal implements Principal { + + private final String name; + + public MyPrincipal(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + +} diff --git a/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/SamAutoRegistrationListener.java b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..83489d6 --- /dev/null +++ b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/TestServerAuthModule.java b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/TestServerAuthModule.java new file mode 100644 index 0000000..530959b --- /dev/null +++ b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/sam/TestServerAuthModule.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Variant of the SAM used by the basic-authentication test, where the so-called "Principal form" of the + * CallerPrincipalCallback is used. Here we pass in a custom Principal instead of a string. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getParameter("doLogin") != null) { + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user *** VIA A CUSTOM PRINCIPAL ***. + // This is the main variant of this test vs basic-authentication + new CallerPrincipalCallback(clientSubject, new MyPrincipal("test")), + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) + }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/ProtectedServlet.java b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/ProtectedServlet.java new file mode 100644 index 0000000..2ca7464 --- /dev/null +++ b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/ProtectedServlet.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.customprincipal.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a protected servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = request.getUserPrincipal().getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/PublicServlet.java b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/PublicServlet.java new file mode 100644 index 0000000..82e0ff5 --- /dev/null +++ b/tck/custom-principal/src/main/java/ee/jakarta/tck/authentication/test/customprincipal/servlet/PublicServlet.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.customprincipal.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a public servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = principal.getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + } + +} diff --git a/tck/custom-principal/src/main/webapp/WEB-INF/web.xml b/tck/custom-principal/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/custom-principal/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalProtectedTest.java b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalProtectedTest.java new file mode 100644 index 0000000..ee84851 --- /dev/null +++ b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalProtectedTest.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that we can login from a protected resource (a resource for which security constraints have been set), then + * access it and that for this type of page the custom principal correctly arrives in a Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class CustomPrincipalProtectedTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testProtectedPageLoggedin() throws IOException { + + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // Target resource should be accessible + assertTrue( + "Authentication seems to have failed, as the expected response from the requested resource is not correct.", + response.contains("This is a protected servlet") + ); + + // Has to be logged-in with the right principal + assertTrue( + "Authentication but username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Authentication succeeded and username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true")); + + assertTrue( + "Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.", + response.contains("isCustomPrincipal: true") + ); + } + +} \ No newline at end of file diff --git a/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalPublicTest.java b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalPublicTest.java new file mode 100644 index 0000000..3508e0d --- /dev/null +++ b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalPublicTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that we can login from a public page (a page for which no security constraints have been set) + * and that for this type of page the custom principal correctly arrives in a Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class CustomPrincipalPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testPublicPageLoggedin() throws IOException { + + // JASPIC has to be able to authenticate a user when accessing a public (non-protected) resource. + + String response = getFromServerPath("public/servlet?doLogin=true"); + + // Has to be logged-in with the right principal + assertTrue( + "Username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true") + ); + assertTrue( + "Username and roles are correct, but principal type is not the expected custom type.", + response.contains("isCustomPrincipal: true") + ); + } + +} \ No newline at end of file diff --git a/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalStatelessTest.java b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalStatelessTest.java new file mode 100644 index 0000000..7a33e4e --- /dev/null +++ b/tck/custom-principal/src/test/java/ee/jakarta/tck/authentication/test/customprincipal/CustomPrincipalStatelessTest.java @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.customprincipal; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * Idential test as in basic-authentication, but now performed against a SAM which sets a custom principal. + * Therefore tests that for this kind of usage of the PrincipalCallback JASPIC is stateless just as well. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class CustomPrincipalStatelessTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + /** + * Tests that access to a protected page does not depend on the authenticated identity that was established in a previous + * request. + */ + @Test + public void testProtectedAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + // -------------------- Request 2 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // If the following fails but "testProtectedPageLoggedin" has succeeded, + // the container has probably remembered the "unauthenticated identity", e.g. it has remembered that + // we're not authenticated and it will deny further attempts to authenticate. This may happen when + // the container does not correctly recognize The Jakarta Authentication protocol for "do nothing". + + response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue("Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet")); + + // -------------------- Request 3 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // In the following method we do a call without logging in after one where we did login. + // The container should not remember this login and has to deny access. + response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse("Could access protected page, but should not be able to. " + + "Did the container remember the authenticated identity that was set in previous request?", + response.contains("This is a protected servlet")); + } + + /** + * Tests that access to a protected page does not depend on the authenticated identity that was established in a previous + * request, but use a different request order than the previous test. + */ + @Test + public void testProtectedAccessIsStateless2() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Start with doing a login + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // -------------------- Request 2 --------------------------- + + // JASPIC is stateless and login (re-authenticate) has to happen for every request + // + // In the following method we do a call without logging in after one where we did login. + // The container should not remember this login and has to deny access. + + // Accessing protected page without login + response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse( + "Could access protected page, but should not be able to. " + + "Did the container remember the authenticated identity that was set in previous request?", + response.contains("This is a protected servlet") + ); + } + + @Test + public void testPublicAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + String response = getFromServerPath("public/servlet"); + + // Not logged-in + assertTrue(response.contains("web username: null")); + assertTrue(response.contains("web user has role \"architect\": false")); + + // -------------------- Request 2 --------------------------- + + response = getFromServerPath("public/servlet?doLogin=true"); + + // Now has to be logged-in + assertTrue( + "Username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true") + ); + + // -------------------- Request 3 --------------------------- + + response = getFromServerPath("public/servlet"); + + // Not logged-in + assertTrue( + "Should not be authenticated, but username was not null. Did the container remember it from previous request?", + response.contains("web username: null") + ); + assertTrue( + "Request was not authenticated (username correctly null), but unauthenticated user incorrectly has role 'architect'", + response.contains("web user has role \"architect\": false") + ); + } + + /** + * Tests independently from being able to access a protected resource if any details of a previously established + * authenticated identity are remembered + */ + @Test + public void testProtectedThenPublicAccessIsStateless() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page with login + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // -------------------- Request 2 --------------------------- + + // Accessing public page without login + response = getFromServerPath("public/servlet"); + + // No details should linger around + assertFalse( + "User principal was 'test', but it should be null here. " + + "The container seemed to have remembered it from the previous request.", + response.contains("web username: test") + ); + assertTrue( + "User principal was not null, but it should be null here. ", + response.contains("web username: null") + ); + assertTrue( + "The unauthenticated user has the role 'architect', which should not be the case. " + + "The container seemed to have remembered it from the previous request.", + response.contains("web user has role \"architect\": false") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/pom.xml b/tck/dispatching-jsf-cdi/pom.xml new file mode 100644 index 0000000..f8a7993 --- /dev/null +++ b/tck/dispatching-jsf-cdi/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + dispatching-jsf-cdi + war + + Jakarta Authentication TCK - dispatching JSF CDI + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipJSF} + + + + + diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/bean/MyBean.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/bean/MyBean.java new file mode 100644 index 0000000..fb24d96 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/bean/MyBean.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.bean; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.servlet.http.HttpServletRequest; + +@Named +@RequestScoped +public class MyBean { + + @Inject + private HttpServletRequest request; + + public String getText() { + return "Called from CDI\n"; + } + + public String getServletPath() { + return request.getServletPath(); + } + +} diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..b2280c8 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java new file mode 100644 index 0000000..d5512f7 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_CONTINUE; +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { + + try { + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if ("include".equals(request.getParameter("dispatch"))) { + + String target = "/includedServlet"; + if ("jsf".equals(request.getParameter("tech"))) { + target = "/include.jsf"; + } else if ("jsfcdi".equals(request.getParameter("tech"))) { + target = "/include-cdi.jsf"; + } + + request.getRequestDispatcher(target) + .include(request, response); + + // "Do nothing", required protocol when returning SUCCESS + handler.handle(new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }); + + // When using includes, the response stays open and the main + // resource can also + // write to the response + return SUCCESS; + + } else { + + String target = "/forwardedServlet"; + if ("jsf".equals(request.getParameter("tech"))) { + target = "/forward.jsf"; + } else if ("jsfcdi".equals(request.getParameter("tech"))) { + target = "/forward-cdi.jsf"; + } + + request.getRequestDispatcher(target) + .forward(request, response); + + // MUST NOT invoke the resource, so CAN NOT return SUCCESS here. + return SEND_CONTINUE; + } + + } catch (IOException | ServletException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java new file mode 100644 index 0000000..aba7662 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.dispatching.bean.MyBean; +import jakarta.inject.Inject; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/forwardedServlet") +public class ForwardedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + private final static Logger logger = Logger.getLogger(ForwardedServlet.class.getName()); + + @Inject + private MyBean myBean; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("response from forwardedServlet - " + myBean.getText()); + response.getWriter().write("servletPath via Servlet - " + request.getServletPath() + "\n"); + try { + response.getWriter().write("servletPath via CDI - " + myBean.getServletPath()); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java new file mode 100644 index 0000000..f0060b5 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; + +import java.io.IOException; + +import ee.jakarta.tck.authentication.test.dispatching.bean.MyBean; +import jakarta.inject.Inject; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/includedServlet") +public class IncludedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Inject + private MyBean myBean; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("response from includedServlet - " + myBean.getText()); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java new file mode 100644 index 0000000..a646b10 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java new file mode 100644 index 0000000..e255b8c --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/beans.xml b/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..e69de29 diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/faces-config.xml b/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/faces-config.xml new file mode 100644 index 0000000..75e5888 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/faces-config.xml @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/web.xml b/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/forward-cdi.xhtml b/tck/dispatching-jsf-cdi/src/main/webapp/forward-cdi.xhtml new file mode 100644 index 0000000..9acd6c0 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/forward-cdi.xhtml @@ -0,0 +1,11 @@ + + + + + Forward with CDI + + + response from JSF forward - #{myBean.text} + + diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/forward.xhtml b/tck/dispatching-jsf-cdi/src/main/webapp/forward.xhtml new file mode 100644 index 0000000..0004cbb --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/forward.xhtml @@ -0,0 +1,11 @@ + + + + + Forward + + + response from JSF forward + + diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/include-cdi.xhtml b/tck/dispatching-jsf-cdi/src/main/webapp/include-cdi.xhtml new file mode 100644 index 0000000..af263f8 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/include-cdi.xhtml @@ -0,0 +1,27 @@ + + + + + + Include with CDI + + + response from JSF include - #{myBean.text} + + diff --git a/tck/dispatching-jsf-cdi/src/main/webapp/include.xhtml b/tck/dispatching-jsf-cdi/src/main/webapp/include.xhtml new file mode 100644 index 0000000..7afdc44 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/main/webapp/include.xhtml @@ -0,0 +1,27 @@ + + + + + + Include + + + response from JSF include + + diff --git a/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIForwardTest.java b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIForwardTest.java new file mode 100644 index 0000000..6dace46 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIForwardTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The basic forward test tests that a SAM is able to forward to a simple Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class CDIForwardTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("beans.xml")) + ); + } + + /** + * Tests that the forwarded resource can utilize a CDI bean + * + * @throws IOException + */ + @Test + public void testCDIForwardViaPublicResource() throws IOException { + String response = getFromServerPath("public/servlet"); + + assertTrue( + "Response did not contain output from public Servlet with CDI that SAM forwarded to.", + response.contains("response from forwardedServlet - Called from CDI") + ); + } + + /** + * Tests that the forwarded resource can utilize a CDI bean + * + * @throws IOException + */ + @Test + public void testCDIForwardViaProtectedResource() throws IOException { + String response = getFromServerPath("protected/servlet"); + + assertTrue( + "Response did not contain output from protected Servlet with CDI that SAM forwarded to.", + response.contains("response from forwardedServlet - Called from CDI") + ); + } + + /** + * Tests that the forwarded resource has the correct servlet path + * + * @throws IOException + */ + @Test + public void testCDIForwardWithRequestPublic() throws IOException { + String response = getFromServerPath("public/servlet"); + + assertTrue( + "Servletpath reported by servlet request after forward from SAM not as expected.", + response.contains("servletPath via Servlet - /forwardedServlet") + ); + } + + /** + * Tests that the forwarded resource has the correct servlet path + * + * @throws IOException + */ + @Test + public void testCDIForwardWithRequestProtected() throws IOException { + String response = getFromServerPath("protected/servlet"); + + assertTrue( + "Servletpath reported by servlet request after forward from SAM not as expected.", + response.contains("servletPath via Servlet - /forwardedServlet") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIIncludeTest.java b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIIncludeTest.java new file mode 100644 index 0000000..0bf241b --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/CDIIncludeTest.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The basic forward test tests that a SAM is able to forward to a simple Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class CDIIncludeTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testCDIIncludeViaPublicResource() throws IOException { + + String response = getFromServerPath("public/servlet?dispatch=include"); + + assertTrue( + "Response did not contain output from public Servlet with CDI that SAM included to.", + response.contains("response from includedServlet - Called from CDI") + ); + + assertTrue( + "Response did not contain output from target Servlet after included one.", + response.contains("Resource invoked") + ); + + assertTrue( + "Output from included Servlet with CDI and target Servlet in wrong order.", + response.indexOf("response from includedServlet - Called from CDI") < response.indexOf("Resource invoked") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIForwardTest.java b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIForwardTest.java new file mode 100644 index 0000000..659ed3f --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIForwardTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The JSF with CDI forward test tests that a SAM is able to forward to a JSF view + * that uses a CDI backing bean. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class JSFCDIForwardTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("beans.xml")) + .addAsWebInfResource(resource("faces-config.xml")) + .addAsWebResource(web("forward-cdi.xhtml")) + ); + } + + @Test + public void testJSFwithCDIForwardViaPublicResource() throws IOException { + + String response = getFromServerPath("public/servlet?tech=jsfcdi"); + assertTrue( + "Response did not contain output from JSF view with CDI that SAM forwarded to.", + response.contains("response from JSF forward - Called from CDI") + ); + } + + @Test + public void testJSFwithCDIForwardViaProtectedResource() throws IOException { + + String response = getFromServerPath("protected/servlet?tech=jsfcdi"); + assertTrue( + "Response did not contain output from JSF view with CDI that SAM forwarded to.", + response.contains("response from JSF forward - Called from CDI") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIIncludeTest.java b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIIncludeTest.java new file mode 100644 index 0000000..f52430a --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFCDIIncludeTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.shrinkwrap.api.Archive; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The JSF with CDI forward test tests that a SAM is able to include a JSF view + * that uses a CDI backing bean. + * + * Excluded for now as it fails, but the failure is not JASPIC related + * + * @author Arjan Tijms + * + */ +//@RunWith(Arquillian.class) +public class JSFCDIIncludeTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("beans.xml")) + .addAsWebInfResource(resource("faces-config.xml")) + .addAsWebResource(web("include-cdi.xhtml")) + ); + } + + //@Test + public void testJSFwithCDIIncludeViaPublicResource() throws IOException { + + String response = getFromServerPath("public/servlet?dispatch=include&tech=jsfcdi"); + + assertTrue( + "Response did not contain output from JSF view that SAM included.", + response.contains("response from JSF include - Called from CDI") + ); + + assertTrue( + "Response did not contain output from target Servlet after included JSF view.", + response.contains("Resource invoked") + ); + + assertTrue( + "Output from included JSF view and target Servlet in wrong order.", + response.indexOf("response from JSF include - Called from CDI") < response.indexOf("Resource invoked") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFForwardTest.java b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFForwardTest.java new file mode 100644 index 0000000..a974411 --- /dev/null +++ b/tck/dispatching-jsf-cdi/src/test/java/ee/jakarta/tck/authentication/test/dispatching/JSFForwardTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The JSF with CDI forward test tests that a SAM is able to forward to a plain JSF view. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class JSFForwardTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("faces-config.xml")) + .addAsWebResource(web("forward.xhtml")) + ); + } + + @Test + public void testJSFForwardViaPublicResource() throws IOException { + + String response = getFromServerPath("public/servlet?tech=jsf"); + assertTrue( + "Response did not contain output from JSF view that SAM forwarded to.", + response.contains("response from JSF forward") + ); + } + + @Test + public void testJSFForwardViaProtectedResource() throws IOException { + + String response = getFromServerPath("protected/servlet?tech=jsf"); + assertTrue( + "Response did not contain output from JSF view that SAM forwarded to.", + response.contains("response from JSF forward") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching/pom.xml b/tck/dispatching/pom.xml new file mode 100644 index 0000000..46cabbc --- /dev/null +++ b/tck/dispatching/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + dispatching + war + + Jakarta Authentication TCK - dispatching + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..b2280c8 --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java new file mode 100644 index 0000000..0b458b8 --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/sam/TestServerAuthModule.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_CONTINUE; +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { + try { + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if ("include".equals(request.getParameter("dispatch"))) { + request.getRequestDispatcher("/includedServlet") + .include(request, response); + + // "Do nothing", required protocol when returning SUCCESS + handler.handle(new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }); + + // When using includes, the response stays open and the main + // resource can also write to the response + return SUCCESS; + + } else { + request.getRequestDispatcher("/forwardedServlet") + .forward(request, response); + + // MUST NOT invoke the resource, so CAN NOT return SUCCESS here. + return SEND_CONTINUE; + } + + } catch (IOException | ServletException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java new file mode 100644 index 0000000..5cbdff1 --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ForwardedServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/forwardedServlet") +public class ForwardedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("response from forwardedServlet"); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java new file mode 100644 index 0000000..9c1de28 --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/IncludedServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/includedServlet") +public class IncludedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("response from includedServlet"); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java new file mode 100644 index 0000000..a646b10 --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/ProtectedServlet.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java new file mode 100644 index 0000000..e255b8c --- /dev/null +++ b/tck/dispatching/src/main/java/ee/jakarta/tck/authentication/test/dispatching/servlet/PublicServlet.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/main/webapp/WEB-INF/web.xml b/tck/dispatching/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/dispatching/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicForwardTest.java b/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicForwardTest.java new file mode 100644 index 0000000..ddb616e --- /dev/null +++ b/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicForwardTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The basic forward test tests that a SAM is able to forward to a simple Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class BasicForwardTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testBasicForwardViaPublicResource() throws IOException { + + String response = getFromServerPath("public/servlet"); + assertTrue( + "Response did not contain output from public Servlet that SAM forwarded to.", + response.contains("response from forwardedServlet") + ); + } + + @Test + public void testBasicForwardViaProtectedResource() throws IOException { + + String response = getFromServerPath("protected/servlet"); + assertTrue( + "Response did not contain output from protected Servlet that SAM forwarded to.", + response.contains("response from forwardedServlet") + ); + } + +} \ No newline at end of file diff --git a/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicIncludeTest.java b/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicIncludeTest.java new file mode 100644 index 0000000..11d7209 --- /dev/null +++ b/tck/dispatching/src/test/java/ee/jakarta/tck/authentication/test/dispatching/BasicIncludeTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.dispatching; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * The basic include test tests that a SAM is able to include a simple Servlet. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class BasicIncludeTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testBasicIncludeViaPublicResource() throws IOException { + String response = getFromServerPath("public/servlet?dispatch=include"); + + assertTrue( + "Response did not contain output from public Servlet that SAM included to.", + response.contains("response from includedServlet") + ); + + assertTrue( + "Response did not contain output from target Servlet after included one.", + response.contains("Resource invoked") + ); + + assertTrue( + "Output from included Servler and target Servlet in wrong order.", + response.indexOf("response from includedServlet") < response.indexOf("Resource invoked") + ); + } + +} \ No newline at end of file diff --git a/tck/ejb-propagation/pom.xml b/tck/ejb-propagation/pom.xml new file mode 100644 index 0000000..e86ed58 --- /dev/null +++ b/tck/ejb-propagation/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + ejb-propagation + war + + Jakarta Authentication TCK - ejb-propagation + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipEJB} + + + + + diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/ProtectedEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/ProtectedEJB.java new file mode 100644 index 0000000..ba59fde --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/ProtectedEJB.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.ejb; + +import jakarta.annotation.Resource; +import jakarta.annotation.security.DeclareRoles; +import jakarta.annotation.security.PermitAll; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ejb.EJBContext; +import jakarta.ejb.Stateless; + +/** + * This is a "protected" EJB in the sense that there is role checking done prior to accessing (some) methods. + *

+ * In JBoss EAP 6.1+ the use of any declarative security annotation switches the bean to a different mode, called "secured" in + * JBoss terms. + *

+ * GlassFish requires the @DeclareRoles annotation when programmatic role checking is done (making dynamic role + * checking impossible). + * + * @author Arjan Tijms + */ +@Stateless +//Required by GlassFish +@DeclareRoles({ "architect" }) +//JBoss EAP 6.1+ defaults unchecked methods to DenyAll +@PermitAll +public class ProtectedEJB { + + @Resource + private EJBContext ejbContext; + + @RolesAllowed("architect") + public String getUserName() { + try { + return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public boolean isUserArchitect() { + try { + return ejbContext.isCallerInRole("architect"); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + + } + +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/PublicEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/PublicEJB.java new file mode 100644 index 0000000..6d78774 --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/ejb/PublicEJB.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.ejb; + +import jakarta.annotation.Resource; +import jakarta.ejb.EJBContext; +import jakarta.ejb.Stateless; + +/** + * This is a "public" EJB in the sense that all its methods should be accessible and there is no declarative role checking prior + * to accessing a method. + * + * @author Arjan Tijms + * + */ +@Stateless +public class PublicEJB { + + @Resource + private EJBContext ejbContext; + + public String getUserName() { + try { + return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/SamAutoRegistrationListener.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..8b62cb5 --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/TestServerAuthModule.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/TestServerAuthModule.java new file mode 100644 index 0000000..9889ae7 --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/sam/TestServerAuthModule.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic SAM that returns a single hardcoded user named "test" with role "architect" when the request parameter + * doLogin is present. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getParameter("doLogin") != null) { + + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "test"), + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + handler.handle(callbacks); + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletProtectedEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletProtectedEJB.java new file mode 100644 index 0000000..7fa55ed --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletProtectedEJB.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.ejbpropagation.ejb.ProtectedEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet-protected-ejb") +public class ProtectedServletProtectedEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(ProtectedServletProtectedEJB.class.getName()); + + @EJB + private ProtectedEJB protectedEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = protectedEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + boolean webHasRole = request.isUserInRole("architect"); + + boolean ejbHasRole = false; + try { + ejbHasRole = protectedEJB.isUserArchitect(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write( + "web user has role \"architect\": " + webHasRole + "\n" + "EJB user has role \"architect\": " + ejbHasRole + + "\n"); + + } + +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletPublicEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletPublicEJB.java new file mode 100644 index 0000000..7428651 --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/ProtectedServletPublicEJB.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.ejbpropagation.ejb.PublicEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet-public-ejb") +public class ProtectedServletPublicEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(ProtectedServletPublicEJB.class.getName()); + + @EJB + private PublicEJB publicEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = publicEJB.getUserName(); + try { + ejbName = publicEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + } + +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletProtectedEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletProtectedEJB.java new file mode 100644 index 0000000..857196a --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletProtectedEJB.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.ejbpropagation.ejb.ProtectedEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet-protected-ejb") +public class PublicServletProtectedEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(PublicServletProtectedEJB.class.getName()); + + @EJB + private ProtectedEJB protectedEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = protectedEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + boolean webHasRole = request.isUserInRole("architect"); + + boolean ejbHasRole = false; + try { + ejbHasRole = protectedEJB.isUserArchitect(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write( + "web user has role \"architect\": " + webHasRole + "\n" + "EJB user has role \"architect\": " + ejbHasRole + + "\n"); + + } + +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJB.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJB.java new file mode 100644 index 0000000..c546ea6 --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJB.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.ejbpropagation.ejb.PublicEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet-public-ejb") +public class PublicServletPublicEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(PublicServletPublicEJB.class.getName()); + + @EJB + private PublicEJB publicEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = publicEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + } + +} diff --git a/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJBLogout.java b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJBLogout.java new file mode 100644 index 0000000..840ae4a --- /dev/null +++ b/tck/ejb-propagation/src/main/java/ee/jakarta/tck/authentication/test/ejbpropagation/servlet/PublicServletPublicEJBLogout.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation.servlet; + +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.ejbpropagation.ejb.PublicEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet-public-ejb-logout") +public class PublicServletPublicEJBLogout extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(PublicServletPublicEJBLogout.class.getName()); + + @EJB + private PublicEJB publicEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = publicEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + request.logout(); + HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + + String webNameAfterLogout = null; + if (request.getUserPrincipal() != null) { + webNameAfterLogout = request.getUserPrincipal().getName(); + } + + String ejbNameAfterLogout = ""; + try { + ejbNameAfterLogout = publicEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + response.getWriter().write("web username after logout: " + webNameAfterLogout + "\n" + "EJB username after logout: " + ejbNameAfterLogout + "\n"); + + } + +} diff --git a/tck/ejb-propagation/src/main/webapp/WEB-INF/web.xml b/tck/ejb-propagation/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/ejb-propagation/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/ProtectedEJBPropagationTest.java b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/ProtectedEJBPropagationTest.java new file mode 100644 index 0000000..1f537c5 --- /dev/null +++ b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/ProtectedEJBPropagationTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the established authenticated identity propagates correctly from the web layer to a "protected" EJB (an EJB + * with declarative role checking). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class ProtectedEJBPropagationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void protectedServletCallingProtectedEJB() throws IOException { + + String response = getFromServerPath("protected/servlet-protected-ejb?doLogin=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see that the + // user has the role "architect". + assertTrue(response.contains("web user has role \"architect\": true")); + assertTrue("Web user principal has role \"architect\", but one in EJB doesn't.", + response.contains("EJB user has role \"architect\": true")); + } + + /** + * A small variation on the testProtectedServletWithLoginCallingEJB that tests if for authentication that happened for + * public resources the security context also propagates to EJB. + * + */ + @Test + public void publicServletCallingProtectedEJB() throws IOException { + + String response = getFromServerPath("public/servlet-protected-ejb?doLogin=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see that the + // user has the role "architect". + assertTrue(response.contains("web user has role \"architect\": true")); + assertTrue("Web user principal has role \"architect\", but one in EJB doesn't.", + response.contains("EJB user has role \"architect\": true")); + } + +} \ No newline at end of file diff --git a/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationLogoutTest.java b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationLogoutTest.java new file mode 100644 index 0000000..81f6202 --- /dev/null +++ b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationLogoutTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the established authenticated identity propagates correctly + * from the web layer to a "public" EJB (an EJB without declarative role + * checking) and that after logging out but still within the same request this + * identity is cleared. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class PublicEJBPropagationLogoutTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void publicServletCallingPublicEJBThenLogout() { + + String response = getFromServerPath("public/servlet-public-ejb-logout?doLogin=true"); + + System.out.println(response); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the + // same user name. + + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + + // After logging out, both the web and EJB should no longer see the user + // name + + assertFalse( + "Web module did not clear authenticated identity after logout", + response.contains("web username after logout: test") + ); + assertFalse( + "EJB did not clear authenticated identity after logout", + response.contains("EJB username after logout: test") + ); + + } + +} \ No newline at end of file diff --git a/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationTest.java b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationTest.java new file mode 100644 index 0000000..9bfda59 --- /dev/null +++ b/tck/ejb-propagation/src/test/java/ee/jakarta/tck/authentication/test/ejbpropagation/PublicEJBPropagationTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.ejbpropagation; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the established authenticated identity propagates correctly from the web layer to a "public" EJB (an EJB + * without declarative role checking). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class PublicEJBPropagationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void protectedServletCallingPublicEJB() { + + String response = getFromServerPath("protected/servlet-public-ejb?doLogin=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + } + +} \ No newline at end of file diff --git a/tck/ejb-register-session/pom.xml b/tck/ejb-register-session/pom.xml new file mode 100644 index 0000000..b5a3b03 --- /dev/null +++ b/tck/ejb-register-session/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + ejb-register-session + war + + Jakarta Authentication TCK - ejb-register-session + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipEJB} + + + + + diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/ProtectedEJB.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/ProtectedEJB.java new file mode 100644 index 0000000..6d30d10 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/ProtectedEJB.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.ejb; + +import jakarta.annotation.Resource; +import jakarta.annotation.security.DeclareRoles; +import jakarta.annotation.security.PermitAll; +import jakarta.annotation.security.RolesAllowed; +import jakarta.ejb.EJBContext; +import jakarta.ejb.Stateless; + +/** + * This is a "protected" EJB in the sense that there is role checking done prior to accessing (some) methods. + *

+ * In JBoss EAP 6.1+ the use of any declarative security annotation switches the bean to a different mode, called "secured" in + * JBoss terms. + *

+ * GlassFish requires the @DeclareRoles annotation when programmatic role checking is done (making dynamic role + * checking impossible). + * + * @author Arjan Tijms + */ +@Stateless +//Required by GlassFish +@DeclareRoles({ "architect" }) +//JBoss EAP 6.1+ defaults unchecked methods to DenyAll +@PermitAll +public class ProtectedEJB { + + @Resource + private EJBContext ejbContext; + + @RolesAllowed("architect") + public String getUserName() { + try { + return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + public boolean isUserArchitect() { + try { + return ejbContext.isCallerInRole("architect"); + } catch (Exception e) { + e.printStackTrace(); + } + return false; + + } + +} diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/PublicEJB.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/PublicEJB.java new file mode 100644 index 0000000..a136a64 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/ejb/PublicEJB.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.ejb; +import jakarta.annotation.Resource; +import jakarta.ejb.EJBContext; +import jakarta.ejb.Stateless; + +/** + * This is a "public" EJB in the sense that all its methods should be accessible and there is no declarative role checking prior + * to accessing a method. + * + * @author Arjan Tijms + * + */ +@Stateless +public class PublicEJB { + + @Resource + private EJBContext ejbContext; + + public String getUserName() { + try { + return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null; + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } +} \ No newline at end of file diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java new file mode 100644 index 0000000..81a8991 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import java.security.Principal; + +/** + * + * @author Arjan Tijms + * + */ +public class MyPrincipal implements Principal { + + private final String name; + + public MyPrincipal(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + +} diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..8bcbdba --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java new file mode 100644 index 0000000..c007d8f --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; +import static java.lang.Boolean.TRUE; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + Callback[] callbacks; + + Principal userPrincipal = request.getUserPrincipal(); + if (userPrincipal != null && request.getParameter("continueSession") != null) { + + // ### If already authenticated before, continue this session + + // Execute protocol to signal container registered authentication session be used. + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, userPrincipal) }; + + } else if (request.getParameter("doLogin") != null) { + + // ### If not authenticated before, do a new login if so requested + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user + + request.getParameter("customPrincipal") == null? + // Name based Callback + new CallerPrincipalCallback(clientSubject, "test") : + + // Custom principal based Callback + new CallerPrincipalCallback(clientSubject, new MyPrincipal("test")), + + + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }; + + // Tell container to register an authentication session. + messageInfo.getMap().put("jakarta.servlet.http.registerSession", TRUE.toString()); + } else { + + // ### If no registered session and no login request "do nothing" + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java new file mode 100644 index 0000000..d12b3e3 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.registersession.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a protected servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = request.getUserPrincipal().getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java new file mode 100644 index 0000000..0cf7d72 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.registersession.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a public servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = principal.getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletProtectedEJB.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletProtectedEJB.java new file mode 100644 index 0000000..0fb0e62 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletProtectedEJB.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.servlet; +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.registersession.ejb.ProtectedEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet-protected-ejb") +public class PublicServletProtectedEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(PublicServletProtectedEJB.class.getName()); + + @EJB + private ProtectedEJB protectedEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = protectedEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + boolean webHasRole = request.isUserInRole("architect"); + + boolean ejbHasRole = false; + try { + ejbHasRole = protectedEJB.isUserArchitect(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write( + "web user has role \"architect\": " + webHasRole + "\n" + "EJB user has role \"architect\": " + ejbHasRole + + "\n"); + + } + +} diff --git a/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletPublicEJB.java b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletPublicEJB.java new file mode 100644 index 0000000..af89313 --- /dev/null +++ b/tck/ejb-register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServletPublicEJB.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.servlet; +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.logging.Logger; + +import ee.jakarta.tck.authentication.test.registersession.ejb.PublicEJB; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet-public-ejb") +public class PublicServletPublicEJB extends HttpServlet { + + private static final long serialVersionUID = 1L; + private final static Logger logger = Logger.getLogger(PublicServletPublicEJB.class.getName()); + + @EJB + private PublicEJB publicEJB; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + String ejbName = ""; + try { + ejbName = publicEJB.getUserName(); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n"); + + } + +} \ No newline at end of file diff --git a/tck/ejb-register-session/src/main/webapp/WEB-INF/web.xml b/tck/ejb-register-session/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..bbbe7fd --- /dev/null +++ b/tck/ejb-register-session/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java b/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java new file mode 100644 index 0000000..5c3d2f0 --- /dev/null +++ b/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalEJBPropagationTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * Variant of the RegisterSessionCustomPrincipalTest, where it's tested + * if the authenticated identity restored by the runtime correctly propagates + * to EJB. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class RegisterSessionCustomPrincipalEJBPropagationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testRemembersSession() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 2 --------------------------- + + // We access the protected page again and now login + + response = getFromServerPath("protected/servlet?doLogin=true&customPrincipal=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 3 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + + checkAuthenticatedIdentity(response); + + + // -------------------- Request 4 --------------------------- + + // The session should also be remembered and propagated to a public EJB + + response = getFromServerPath("public/servlet-public-ejb?continueSession=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + + // -------------------- Request 5 --------------------------- + + // The session should also be remembered and propagated to a protected EJB + + response = getFromServerPath("public/servlet-protected-ejb?continueSession=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see that the + // user has the role "architect". + assertTrue(response.contains("web user has role \"architect\": true")); + assertTrue("Web user principal has role \"architect\", but one in EJB doesn't.", + response.contains("EJB user has role \"architect\": true")); + + } + + private void checkAuthenticatedIdentity( String response) { + + // Has to be logged-in with the right principal + assertTrue( + "Authenticated but username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Authentication succeeded and username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true")); + + assertTrue( + "Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.", + response.contains("isCustomPrincipal: true") + ); + } + + + +} \ No newline at end of file diff --git a/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionEJBPropagationTest.java b/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionEJBPropagationTest.java new file mode 100644 index 0000000..f47ac8d --- /dev/null +++ b/tck/ejb-register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionEJBPropagationTest.java @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * Variant of the RegisterSessionTest, where it's tested + * if the authenticated identity restored by the runtime correctly propagates + * to EJB. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class RegisterSessionEJBPropagationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testRemembersSession() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 2 --------------------------- + + // We access the protected page again and now login + + response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 3 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + + checkAuthenticatedIdentity(response); + + + // -------------------- Request 4 --------------------------- + + // The session should also be remembered and propagated to a public EJB + + response = getFromServerPath("public/servlet-public-ejb?continueSession=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + + // -------------------- Request 5 --------------------------- + + // The session should also be remembered and propagated to a protected EJB + + response = getFromServerPath("public/servlet-protected-ejb?continueSession=true"); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see the same + // user name. + assertTrue( + "User should have been authenticated in the web layer and given name \"test\", " + + " but does not appear to have this name", + response.contains("web username: test") + ); + assertTrue( + "Web has user principal set, but EJB not.", + response.contains("EJB username: test") + ); + + // Both the web (HttpServletRequest) and EJB (EJBContext) should see that the + // user has the role "architect". + assertTrue(response.contains("web user has role \"architect\": true")); + assertTrue("Web user principal has role \"architect\", but one in EJB doesn't.", + response.contains("EJB user has role \"architect\": true")); + + } + + private void checkAuthenticatedIdentity( String response) { + + // Has to be logged-in with the right principal + assertTrue( + "Authenticated but username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Authentication succeeded and username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true")); + + assertTrue( + "Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.", + response.contains("isCustomPrincipal: false") + ); + } + + + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/pom.xml b/tck/invoke-ejb-cdi/pom.xml new file mode 100644 index 0000000..9d26a28 --- /dev/null +++ b/tck/invoke-ejb-cdi/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + invoke-ejb-cdi + war + + Jakarta Authentication TCK - invoke EJB and CDI + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipEJB} + + + + + diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/CDIBean.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/CDIBean.java new file mode 100644 index 0000000..ac73903 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/CDIBean.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.bean; + +import jakarta.enterprise.context.RequestScoped; +import jakarta.inject.Inject; +import jakarta.inject.Named; +import jakarta.servlet.http.HttpServletRequest; + +@Named +@RequestScoped +public class CDIBean { + + @Inject + private HttpServletRequest request; + + public String getText() { + return "Called from CDI"; + } + + public void setTextViaInjectedRequest() { + request.setAttribute("text", "Called from CDI via injected request"); + } + +} diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/EJBBean.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/EJBBean.java new file mode 100644 index 0000000..80c0c12 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/bean/EJBBean.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.bean; + +import jakarta.ejb.Stateless; + +@Stateless +public class EJBBean { + + public String getText() { + return "Called from EJB"; + } + +} diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/SamAutoRegistrationListener.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..0152d55 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/TestServerAuthModule.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/TestServerAuthModule.java new file mode 100644 index 0000000..6fd3ae1 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/sam/TestServerAuthModule.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_SUCCESS; +import static jakarta.security.auth.message.AuthStatus.SUCCESS; +import static java.util.logging.Level.SEVERE; + +import java.io.IOException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.naming.InitialContext; +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import ee.jakarta.tck.authentication.test.invoke.bean.CDIBean; +import ee.jakarta.tck.authentication.test.invoke.bean.EJBBean; +import jakarta.enterprise.inject.spi.CDI; +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private final static Logger logger = Logger.getLogger(TestServerAuthModule.class.getName()); + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if ("cdi".equals(request.getParameter("tech"))) { + callCDIBean(request, response, "validateRequest"); + } else if ("ejb".equals(request.getParameter("tech"))) { + callEJBBean(response, "validateRequest"); + } + + try { + handler.handle(new Callback[] { + new CallerPrincipalCallback(clientSubject, "test"), + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) + }); + + return SUCCESS; + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if ("cdi".equals(request.getParameter("tech"))) { + callCDIBean(request, response, "secureResponse"); + } else if ("ejb".equals(request.getParameter("tech"))) { + callEJBBean(response, "secureResponse"); + } + + return SEND_SUCCESS; + } + + @Override + public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if ("cdi".equals(request.getParameter("tech"))) { + callCDIBean(request, response, "cleanSubject"); + } else if ("ejb".equals(request.getParameter("tech"))) { + callEJBBean(response, "cleanSubject"); + } + } + + private void callCDIBean(HttpServletRequest request, HttpServletResponse response, String phase) { + try { + CDIBean cdiBean = CDI.current().select(CDIBean.class).get(); + response.getWriter().write(phase + ": " + cdiBean.getText() + "\n"); + + cdiBean.setTextViaInjectedRequest(); + + response.getWriter().write(phase + ": " + request.getAttribute("text")+ "\n"); + + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + } + + private void callEJBBean(HttpServletResponse response, String phase) { + try { + EJBBean ejbBean = (EJBBean) new InitialContext().lookup("java:module/EJBBean"); + response.getWriter().write(phase + ": " + ejbBean.getText() + "\n"); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + } + + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/ProtectedServlet.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/ProtectedServlet.java new file mode 100644 index 0000000..c0f09ee --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/ProtectedServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + request.logout(); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/PublicServlet.java b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/PublicServlet.java new file mode 100644 index 0000000..a3a1640 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/java/ee/jakarta/tck/authentication/test/invoke/servlet/PublicServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke.servlet; +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + request.logout(); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/beans.xml b/tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 0000000..e69de29 diff --git a/tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/web.xml b/tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanProtectedTest.java b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanProtectedTest.java new file mode 100644 index 0000000..e54f332 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanProtectedTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that a SAM is able to obtain and call a CDI bean when the request is to a protected resource + * (a resource for which security constraints have been set). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class InvokeCDIBeanProtectedTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("beans.xml")) + ); + } + + @Test + public void protectedInvokeCDIFromValidateRequest() { + String response = getFromServerPath("protected/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for validateRequest for protected resource. (note: this is not required by the spec)", + response.contains("validateRequest: Called from CDI") + ); + } + + @Test + public void protectedInvokeCDIFromCleanSubject() { + String response = getFromServerPath("protected/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for cleanSubject for protected resource. (note: this is not required by the spec)", + response.contains("cleanSubject: Called from CDI") + ); + } + + @Test + public void protectedInvokeCDIFromSecureResponse() { + String response = getFromServerPath("protected/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for secureResponse for protected resource. (note: this is not required by the spec)", + response.contains("secureResponse: Called from CDI") + ); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanPublicTest.java b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanPublicTest.java new file mode 100644 index 0000000..f2020a6 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeCDIBeanPublicTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that a SAM is able to obtain and call a CDI bean when the request is to a public resource + * (a resource for which no security constraints have been set). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class InvokeCDIBeanPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return tryWrapEAR( + defaultWebArchive() + .addAsWebInfResource(resource("beans.xml")) + ); + } + + @Test + public void publicInvokeCDIFromValidateRequest() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for validateRequest for public resource. (note: this is not required by the spec)", + response.contains("validateRequest: Called from CDI") + ); + } + + @Test + public void publicInvokeCDIFromCleanSubject() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for cleanSubject for public resource. (note: this is not required by the spec)", + response.contains("cleanSubject: Called from CDI") + ); + } + + @Test + public void publicInvokeCDIFromSecureResponse() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean for secureResponse for public resource. (note: this is not required by the spec)", + response.contains("secureResponse: Called from CDI") + ); + } + + @Test + public void publicInvokeCDIUseInjectedRequestFromValidateRequest() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean using an inject request for validateRequest for public resource. (note: this is not required by the spec)", + response.contains("validateRequest: Called from CDI via injected request") + ); + } + + @Test + public void publicInvokeCDIUseInjectedRequestFromCleanSubject() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean using an inject request for cleanSubject for public resource. (note: this is not required by the spec)", + response.contains("cleanSubject: Called from CDI via injected request") + ); + } + + @Test + public void publicInvokeCDIUseInjectedRequestFromSecureResponse() { + String response = getFromServerPath("public/servlet?tech=cdi"); + + assertTrue( + "Response did not contain output from CDI bean using an inject request for secureResponse for public resource. (note: this is not required by the spec)", + response.contains("secureResponse: Called from CDI via injected request") + ); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanProtectedTest.java b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanProtectedTest.java new file mode 100644 index 0000000..d8012b0 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanProtectedTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that a SAM is able to obtain and call an EJB bean when the request is to a protected resource + * (a resource for which security constraints have been set). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class InvokeEJBBeanProtectedTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void protectedInvokeEJBFromValidateRequest() { + String response = getFromServerPath("protected/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for validateRequest for protected resource. (note: spec is silent on this, but it should work)", + response.contains("validateRequest: Called from EJB") + ); + } + + @Test + public void protectedInvokeEJBFromCleanSubject() { + String response = getFromServerPath("protected/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for cleanSubject for protected resource. (note: spec is silent on this, but it should work)", + response.contains("cleanSubject: Called from EJB") + ); + } + + @Test + public void protectedInvokeEJBFromSecureResponse() { + String response = getFromServerPath("protected/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for secureResponse for protected resource. (note: spec is silent on this, but it should work)", + response.contains("secureResponse: Called from EJB") + ); + } + +} \ No newline at end of file diff --git a/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanPublicTest.java b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanPublicTest.java new file mode 100644 index 0000000..b861da1 --- /dev/null +++ b/tck/invoke-ejb-cdi/src/test/java/ee/jakarta/tck/authentication/test/invoke/InvokeEJBBeanPublicTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.invoke; + +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that a SAM is able to obtain and call an EJB bean when the request is to a public resource + * (a resource for which no security constraints have been set). + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class InvokeEJBBeanPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void publicInvokeEJBFromValidateRequest() { + String response = getFromServerPath("public/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for validateRequest for public resource.", + response.contains("validateRequest: Called from EJB") + ); + } + + @Test + public void publicInvokeEJBFromCleanSubject() { + String response = getFromServerPath("public/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for cleanSubject for public resource.", + response.contains("cleanSubject: Called from EJB") + ); + } + + @Test + public void publicInvokeEJBFromSecureResponse() { + String response = getFromServerPath("public/servlet?tech=ejb"); + + assertTrue( + "Response did not contain output from EJB bean for secureResponse for public resource.", + response.contains("secureResponse: Called from EJB") + ); + } + +} \ No newline at end of file diff --git a/tck/jacc-propagation/pom.xml b/tck/jacc-propagation/pom.xml new file mode 100644 index 0000000..5de9bdb --- /dev/null +++ b/tck/jacc-propagation/pom.xml @@ -0,0 +1,51 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + authorization-propagation + war + + Jakarta Authentication TCK - authorization-propagation + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipJACC} + + + + + diff --git a/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/jacc/JakartaAuthorization.java b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/jacc/JakartaAuthorization.java new file mode 100644 index 0000000..3cf4bc5 --- /dev/null +++ b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/jacc/JakartaAuthorization.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.authzpropagation.jacc; + +import static java.security.Policy.getPolicy; +import static java.util.logging.Level.SEVERE; + +import java.security.CodeSource; +import java.security.Principal; +import java.security.ProtectionDomain; +import java.security.cert.Certificate; +import java.util.logging.Logger; + +import javax.security.auth.Subject; + +import jakarta.security.jacc.PolicyContext; +import jakarta.security.jacc.WebResourcePermission; + +/** + * + * @author Arjan Tijms + * + */ +public class JakartaAuthorization { + + private final static Logger logger = Logger.getLogger(JakartaAuthorization.class.getName()); + + public static Subject getSubject() { + try { + return (Subject) PolicyContext.getContext("javax.security.auth.Subject.container"); + } catch (Exception e) { + logger.log(SEVERE, "", e); + } + + return null; + } + + public static boolean hasAccess(String uri, Subject subject) { + return getPolicy().implies( + new ProtectionDomain( + new CodeSource(null, (Certificate[]) null), + null, null, + subject.getPrincipals().toArray(new Principal[subject.getPrincipals().size()]) + ), + new WebResourcePermission(uri, "GET") + ); + } +} diff --git a/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/SamAutoRegistrationListener.java b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..26f10eb --- /dev/null +++ b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.authzpropagation.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/TestServerAuthModule.java b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/TestServerAuthModule.java new file mode 100644 index 0000000..5e5cb1d --- /dev/null +++ b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/sam/TestServerAuthModule.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.authzpropagation.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic SAM that returns a single hardcoded user named "test" with role "architect" when the request parameter + * doLogin is present. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getParameter("doLogin") != null) { + + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, "test"), + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + handler.handle(callbacks); + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/ProtectedServlet.java b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/ProtectedServlet.java new file mode 100644 index 0000000..1ca178c --- /dev/null +++ b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/ProtectedServlet.java @@ -0,0 +1,42 @@ +package ee.jakarta.tck.authentication.test.authzpropagation.servlet; + +import static ee.jakarta.tck.authentication.test.authzpropagation.jacc.JakartaAuthorization.getSubject; +import static ee.jakarta.tck.authentication.test.authzpropagation.jacc.JakartaAuthorization.hasAccess; + +import java.io.IOException; + +import javax.security.auth.Subject; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + // Obtain the active subject via a JACC policy handler + Subject subject = getSubject(); + + if (subject == null) { + response.getWriter().write("Can't get Subject. JACC doesn't seem to be available."); + return; + } + + // Check with JACC if the caller has access to this Servlet. As we're + // currently in this very Servlet the answer can't be anything than "true" if + // JASPIC, JACC and role propagation all work correctly. + response.getWriter().write("Has access to /protected/servlet: " + hasAccess("/protected/servlet", subject)); + } + +} diff --git a/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/PublicServlet.java b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/PublicServlet.java new file mode 100644 index 0000000..66612f2 --- /dev/null +++ b/tck/jacc-propagation/src/main/java/ee/jakarta/tck/authentication/test/authzpropagation/servlet/PublicServlet.java @@ -0,0 +1,49 @@ +package ee.jakarta.tck.authentication.test.authzpropagation.servlet; + +import static ee.jakarta.tck.authentication.test.authzpropagation.jacc.JakartaAuthorization.getSubject; +import static ee.jakarta.tck.authentication.test.authzpropagation.jacc.JakartaAuthorization.hasAccess; + +import java.io.IOException; + +import javax.security.auth.Subject; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + // Obtain the active subject via a JACC policy handler + Subject subject = getSubject(); + + if (subject == null) { + response.getWriter().write("Can't get Subject. JACC doesn't seem to be available."); + return; + } + + // Check with JACC if the caller has access to this Servlet. As we're + // currently in this very Servlet and it's a public Servlet,the answer can't be anything + // than "true". + + response.getWriter().write("Has access to /public/servlet: " + hasAccess("/public/servlet", subject)); + + // Check with JACC if the caller has access to another (protected) Servlet. If JACC + // works correctly and we're authenticated this should be true. + + response.getWriter().write( + "\nHas access to /protected/servlet: " + hasAccess("/protected/servlet", subject)); + } + +} diff --git a/tck/jacc-propagation/src/main/webapp/WEB-INF/web.xml b/tck/jacc-propagation/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/jacc-propagation/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationProtectedTest.java b/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationProtectedTest.java new file mode 100644 index 0000000..a629213 --- /dev/null +++ b/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationProtectedTest.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.authzpropagation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the established authenticated identity set from JASPIC propagates correctly + * to a JACC provider. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class AuthzPropagationProtectedTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void callingJACCWhenAuthenticated() { + + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // This can basically only fail if JACC itself somehow doesn't work. + // Unfortunately this is the case for a bunch of certified servers, which + // either demand some activation of JACC, or don't ship with a default + // provider at all (which are both spec violations) + assertFalse( + "JACC doesn't seem to be available.", + response.contains("JACC doesn't seem to be available.") + ); + + // Test if we have access to protected/servlet from within that servlet. + // If this fails role propagation and/or JACC failed, since this is obviously + // impossible. + assertTrue( + "Did not have access to protected servlet from within that Servlet. " + + " Perhaps the roles did not propogate from JASPIC to JACC and the" + + " server didn't use JACC to grant access to invoking said Servlet?", + response.contains("Has access to /protected/servlet: true") + ); + } + +} \ No newline at end of file diff --git a/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationPublicTest.java b/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationPublicTest.java new file mode 100644 index 0000000..fe67a44 --- /dev/null +++ b/tck/jacc-propagation/src/test/java/ee/jakarta/tck/authentication/test/authzpropagation/AuthzPropagationPublicTest.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.authzpropagation; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the established authenticated identity set from JASPIC propagates correctly + * to a JACC provider. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class AuthzPropagationPublicTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void callingJACCWhenAuthenticated() { + + String response = getFromServerPath("public/servlet?doLogin=true"); + + // This can basically only fail if JACC itself somehow doesn't work. + // Unfortunately this is the case for a bunch of certified servers, which + // either demand some activation of JACC, or don't ship with a default + // provider at all (which are both spec violations) + assertFalse( + "JACC doesn't seem to be available.", + response.contains("JACC doesn't seem to be available.") + ); + + // Test if we have access to public/servlet. This would be rare to fail + assertTrue( + "Did not have access to public servlet from within that Servlet. " + + " Something is seriously wrong.", + response.contains("Has access to /public/servlet: true") + ); + + // Test if we have access to protected/servlet. Since we authenticated with JASPIC + // with a role that this path is protected with, we should have access if those + // roles were indeed propagated correctly. + assertTrue( + "Did not have access to protected servlet from within public servlet. " + + " Perhaps the roles did not propogate from JASPIC to JACC?", + response.contains("Has access to /protected/servlet: true") + ); + } + + @Test + public void callingJACCWhenNotAuthenticated() { + + String response = getFromServerPath("public/servlet"); + + // This can basically only fail if JACC itself somehow doesn't work. + // Unfortunately this is the case for a bunch of certified servers, which + // either demand some activation of JACC, or don't ship with a default + // provider at all (which are both spec violations) + assertFalse( + "JACC doesn't seem to be available.", + response.contains("JACC doesn't seem to be available.") + ); + + // Test if we have access to public/servlet. This would be rare to fail + assertTrue( + "Did not have access to public servlet from within that Servlet. " + + " Something is seriously wrong.", + response.contains("Has access to /public/servlet: true") + ); + + // Test that we do NOT have access to protected/servlet. Passing this test + // doesn't necessarily means JASPIC to JACC propagation works correctly, as it will also pass if + // JACC doesn't work at all. Failing this test does indicate that something is wrong. + assertTrue( + "Has access to protected servlet from within public servlet without being authenticated. " + + " This should not be the case.", + response.contains("Has access to /protected/servlet: false") + ); + } + +} \ No newline at end of file diff --git a/tck/lifecycle/pom.xml b/tck/lifecycle/pom.xml new file mode 100644 index 0000000..09d1331 --- /dev/null +++ b/tck/lifecycle/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + lifecycle + war + + Jakarta Authentication TCK - lifecycle + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/SamAutoRegistrationListener.java b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..3804ba8 --- /dev/null +++ b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestLifecycleAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/TestLifecycleAuthModule.java b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/TestLifecycleAuthModule.java new file mode 100644 index 0000000..360ecd0 --- /dev/null +++ b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/sam/TestLifecycleAuthModule.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_SUCCESS; +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * A test SAM that always authenticates a hard-coded user "test" with role "architect" for every request. + * + * @author Arjan Tijms + * + */ +public class TestLifecycleAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + try { + response.getWriter().write("validateRequest invoked\n"); + + boolean isMandatory = Boolean.valueOf((String) messageInfo.getMap().get("jakarta.security.auth.message.MessagePolicy.isMandatory")); + + response.getWriter().write("isMandatory: " + isMandatory + "\n"); + + handler.handle(new Callback[] { + new CallerPrincipalCallback(clientSubject, "test"), + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }); + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { + + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + try { + response.getWriter().write("secureResponse invoked\n"); + } catch (IOException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SEND_SUCCESS; + } + + @Override + public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + try { + response.getWriter().write("cleanSubject invoked\n"); + } catch (IOException e) { + throw (AuthException) new AuthException().initCause(e); + } + } +} \ No newline at end of file diff --git a/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/ProtectedServlet.java b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/ProtectedServlet.java new file mode 100644 index 0000000..2f270ed --- /dev/null +++ b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/ProtectedServlet.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Resource invoked\n"); + + if (request.getParameter("doLogout") != null) { + request.logout(); + } + } + +} diff --git a/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/PublicServlet.java b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/PublicServlet.java new file mode 100644 index 0000000..2cc9ca1 --- /dev/null +++ b/tck/lifecycle/src/main/java/ee/jakarta/tck/authentication/test/lifecycle/servlet/PublicServlet.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("Public resource invoked\n"); + + if (request.getParameter("doLogout") != null) { + request.logout(); + } + } + +} diff --git a/tck/lifecycle/src/main/webapp/WEB-INF/web.xml b/tck/lifecycle/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/lifecycle/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/AuthModuleMethodInvocationTest.java b/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/AuthModuleMethodInvocationTest.java new file mode 100644 index 0000000..f3cd01c --- /dev/null +++ b/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/AuthModuleMethodInvocationTest.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; + +/** + * This tests that the two main methods of a SAM, {@link ServerAuthModule#validateRequest} and + * {@link ServerAuthModule#secureResponse} are called at the right time, which is resp. before and after the resource (e.g. a + * Servlet) is invoked. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class AuthModuleMethodInvocationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + /** + * Test that the main SAM methods are called and are called in the correct order. + * + * The rule seems simple: + *

    + *
  • First call validateRequest() in the SAM. + *
  • Then invoke the requested resource (e.g. a Servlet or JSP page) + *
  • Finally call secureResponse() in the SAM + *
+ */ + @Test + public void testBasicSAMMethodsCalled() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // First test if individual methods are called + assertTrue("SAM method validateRequest not called, but should have been.", + response.contains("validateRequest invoked")); + assertTrue("Resource (Servlet) not invoked, but should have been.", response.contains("Resource invoked")); + + // The previous two methods are rare to not be called, but secureResponse is more likely to fail. Seemingly it's hard + // to understand what this method should do exactly. + assertTrue("SAM method secureResponse not called, but should have been.", + response.contains("secureResponse invoked")); + + int validateRequestIndex = response.indexOf("validateRequest invoked"); + int resourceIndex = response.indexOf("Resource invoked"); + int secureResponseIndex = response.indexOf("secureResponse invoked"); + + // Finally the order should be correct. More than a few implementations call secureResponse before the resource is + // invoked. + assertTrue("SAM methods called in wrong order", + validateRequestIndex < resourceIndex && resourceIndex < secureResponseIndex); + } + + /** + * Test that the SAM's cleanSubject method is called following a call to {@link HttpServletRequest#logout()}. + */ + @Test + public void testLogout() throws IOException { + + // Note that we don't explicitly log-in; the test SAM uses for this test does that automatically before the resource + // (servlet) + // is invoked. Once we reach the Servlet we should be logged-in and can proceed to logout. + String response = getFromServerPath("protected/servlet?doLogout=true"); + + assertTrue("SAM method cleanSubject not called, but should have been.", + response.contains("cleanSubject invoked")); + } + +} \ No newline at end of file diff --git a/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/IsMandatoryTest.java b/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/IsMandatoryTest.java new file mode 100644 index 0000000..0968c1c --- /dev/null +++ b/tck/lifecycle/src/test/java/ee/jakarta/tck/authentication/test/lifecycle/IsMandatoryTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.lifecycle; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the "jakarta.security.auth.message.MessagePolicy.isMandatory" key + * in the message info map is "true" for a protected resource, and not "true" for + * a public resource. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class IsMandatoryTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testPublicIsNonMandatory() throws IOException { + String response = getFromServerPath("public/servlet"); + + assertTrue("Resource (Servlet) not invoked, but should have been.", response.contains("Public resource invoked")); + + assertTrue("isMandatory should be false for public resource, but was not.", + response.contains("isMandatory: false")); + } + + @Test + public void testProtectedIsMandatory() throws IOException { + String response = getFromServerPath("protected/servlet"); + + assertTrue("Resource (Servlet) not invoked, but should have been.", response.contains("Resource invoked")); + + assertTrue("isMandatory should be true for protected resource, but was not.", + response.contains("isMandatory: true")); + } + + +} \ No newline at end of file diff --git a/tck/pom.xml b/tck/pom.xml new file mode 100644 index 0000000..b715e61 --- /dev/null +++ b/tck/pom.xml @@ -0,0 +1,643 @@ + + + + + 4.0.0 + + + org.eclipse.ee4j + project + 1.0.6 + + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + pom + + Jakarta Authentication TCK - main + + + + common + + + basic-authentication + + + custom-principal + + + programmatic-authentication + + + lifecycle + + + wrapping + + + register-session + + + async-authentication + + + status-codes + + + dispatching + + + dispatching-jsf-cdi + + + ejb-propagation + + + ejb-register-session + + + jacc-propagation + + + invoke-ejb-cdi + + + + + 11 + UTF-8 + + false + false + + + 7.0.0-SNAPSHOT + 9.0.12 + + + + + + org.jboss.arquillian + arquillian-bom + 1.7.0.Alpha10 + pom + import + + + org.jboss.arquillian.container + arquillian-container-test-api + 1.7.0.Alpha10 + + + fish.payara.arquillian + payara-client-ee8 + 2.3.1 + test + + + + + + jakarta.authentication + jakarta.authentication-api + 3.0.0 + + + + jakarta.authorization + jakarta.authorization-api + 2.1.0 + + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + + + + jakarta.el + jakarta.el-api + 5.0.0 + provided + + + + jakarta.enterprise + jakarta.enterprise.cdi-api + 4.0.0.Beta3 + provided + + + + jakarta.validation + jakarta.validation-api + 3.0.1 + provided + + + + jakarta.ejb + jakarta.ejb-api + 4.0.0 + provided + true + + + + jakarta.annotation + jakarta.annotation-api + 2.0.0 + + + + + + junit + junit + 4.13.2 + test + + + org.jboss.arquillian.junit + arquillian-junit-container + test + + + org.jboss.arquillian.protocol + arquillian-protocol-servlet + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven + jar + test + + + org.jboss.shrinkwrap.resolver + shrinkwrap-resolver-impl-maven-archive + test + + + xmlunit + xmlunit + 1.6 + test + + + net.sourceforge.htmlunit + htmlunit + 2.58.0 + test + + + + + + jakarta-staging + + https://jakarta.oss.sonatype.org/content/repositories/staging + + + + + ${project.artifactId} + + + src/test/resources + true + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M5 + + + + + + org.apache.maven.plugins + maven-enforcer-plugin + 3.0.0 + + + + 3.6.3 + + + ${java.min.version} + + + + + + + enforce + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + ${java.min.version} + ${java.min.version} + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 3.0.0-M5 + + true + true + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M5 + + false + -XX:+ShowCodeDetailsInExceptionMessages + + + + org.apache.maven.plugins + maven-war-plugin + 3.3.2 + + true + false + + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.apache.maven.plugins + maven-resources-plugin + 3.2.0 + + + org.apache.maven.plugins + maven-failsafe-plugin + + + + integration-test + verify + + + + + + ${project.build.finalName} + + + + + org.apache.maven.plugins + maven-assembly-plugin + false + + + package + + single + + + true + false + + zip.xml + + + + + + + + + + + + org.apache.maven.plugins + maven-surefire-report-plugin + 2.19.1 + + true + true + + + + + + + + + + custom + + + + + + + glassfish-ci-managed + + + true + + + + ${maven.multiModuleProjectDirectory}/target + + + + + + org.omnifaces.arquillian + arquillian-glassfish-server-managed + 1.0 + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack + process-test-classes + + unpack + + + ${glassfish.root} + ${glassfish.root}/dependency-maven-plugin-markers + + + org.glassfish.main.distributions + glassfish + ${glassfish.version} + zip + false + ${glassfish.root} + + + + + + + + maven-surefire-plugin + + + ${glassfish.root}/glassfish7 + + + + + + + + + + + + + piranha-embedded-micro + + + + + + + fish.payara.arquillian + payara-client-ee8 + test + + + + cloud.piranha.arquillian + piranha-arquillian-server + 21.6.0-SNAPSHOT + test + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + true + 1000 + false + + + + + + + + + + + + + tomcat-remote + + + true + true + true + true + + + + + org.jboss.arquillian.container + arquillian-tomcat-remote-7 + 1.1.0.Final + test + + + + + + + maven-surefire-plugin + + + tomcat-remote + + + + + + + + + + tomcat-ci-managed + + + true + true + true + true + + + + + + apache.public + https://repository.apache.org/content/repositories/public/ + + true + + + false + + + + + + apache.staging + https://repository.apache.org/content/repositories/staging/ + + true + + + false + + + + + + + org.jboss.arquillian.container + arquillian-tomcat-managed-7 + 1.1.0.Final + test + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + unpack-tomcat + process-test-classes + + unpack + + + + + org.apache.tomcat + tomcat + ${tomcat.version} + zip + false + ${project.build.directory} + + + + + + unpack-tomcat-users + process-test-classes + + unpack + + + + + org.javaee8 + test-utils + ${project.version} + jar + true + ${project.build.directory}/apache-tomcat-${tomcat.version}/conf + tomcat-users.xml + + + + + + + + org.apache.maven.plugins + maven-surefire-plugin + + + tomcat-ci-managed + ${project.build.directory}/apache-tomcat-${tomcat.version} + + + + + + + + + diff --git a/tck/programmatic-authentication/pom.xml b/tck/programmatic-authentication/pom.xml new file mode 100644 index 0000000..baf0465 --- /dev/null +++ b/tck/programmatic-authentication/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + programmatic-authentication + war + + Jakarta Authentication TCK - programmatic-authentication + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/SamAutoRegistrationListener.java b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..de59ed1 --- /dev/null +++ b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.programmaticauthentication.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/TestServerAuthModule.java b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/TestServerAuthModule.java new file mode 100644 index 0000000..15156b0 --- /dev/null +++ b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/sam/TestServerAuthModule.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.programmaticauthentication.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic SAM that returns a single hardcoded user named "test" with role "architect" when the request *attribute* + * doLogin is present. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + Callback[] callbacks; + + if (request.getAttribute("doLogin") != null) { // notice "getAttribute" here, this is set by the Servlet + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user + new CallerPrincipalCallback(clientSubject, "test"), + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) + }; + } else { + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/servlet/AuthenticateServlet.java b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/servlet/AuthenticateServlet.java new file mode 100644 index 0000000..d87e8ad --- /dev/null +++ b/tck/programmatic-authentication/src/main/java/ee/jakarta/tck/authentication/test/programmaticauthentication/servlet/AuthenticateServlet.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.programmaticauthentication.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/authenticate") +public class AuthenticateServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a public servlet \n"); + + String webName = null; + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + response.getWriter().write("before web username: " + webName + "\n"); + boolean webHasRole = request.isUserInRole("architect"); + response.getWriter().write("before web user has role \"architect\": " + webHasRole + "\n"); + + // By *not* setting the "doLogin" request attribute the request.authenticate call + // would do nothing. request.authenticate is a mandatory authentication, so doing + // nothing is not allowed. But one or more initial failures should not prevent + // a later successful authentication. + if (request.getParameter("failFirst") != null) { + try { + request.authenticate(response); + } catch (IOException | ServletException e) { + // GlassFish returns false when either authentication is in progress or authentication + // failed (or was not done at all), but JBoss throws an exception. + // TODO: Get clarification what is actually expected, likely exception is most correct. + // Then test for the correct return value. + } + } + + if ("2".equals(request.getParameter("failFirst"))) { + try { + request.authenticate(response); + } catch (IOException | ServletException e) { + } + } + + // Programmatically trigger the authentication chain + request.setAttribute("doLogin", true); + boolean authenticateOutcome = request.authenticate(response); + + if (request.getUserPrincipal() != null) { + webName = request.getUserPrincipal().getName(); + } + + response.getWriter().write("request.authenticate outcome: " + authenticateOutcome + "\n"); + + response.getWriter().write("after web username: " + webName + "\n"); + webHasRole = request.isUserInRole("architect"); + response.getWriter().write("after web user has role \"architect\": " + webHasRole + "\n"); + + } + +} diff --git a/tck/programmatic-authentication/src/main/webapp/WEB-INF/web.xml b/tck/programmatic-authentication/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/programmatic-authentication/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/programmatic-authentication/src/test/java/ee/jakarta/tck/authentication/test/programmaticauthentication/ProgrammaticAuthenticationTest.java b/tck/programmatic-authentication/src/test/java/ee/jakarta/tck/authentication/test/programmaticauthentication/ProgrammaticAuthenticationTest.java new file mode 100644 index 0000000..71d48f0 --- /dev/null +++ b/tck/programmatic-authentication/src/test/java/ee/jakarta/tck/authentication/test/programmaticauthentication/ProgrammaticAuthenticationTest.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.programmaticauthentication; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that a call from a Servlet to HttpServletRequest#authenticate can result + * in a successful authentication. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class ProgrammaticAuthenticationTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testAuthenticate() throws IOException { + assertAuthenticated(getFromServerPath("public/authenticate")); + } + + @Test + public void testAuthenticateFailFirstOnce() throws IOException { + // Before authenticating successfully, call request.authenticate which + // is known to fail (do nothing) + assertAuthenticated(getFromServerPath("public/authenticate?failFirst=1")); + } + + @Test + public void testAuthenticateFailFirstTwice() throws IOException { + // Before authenticating successfully, call request.authenticate twice which + // are both known to fail (do nothing) + assertAuthenticated(getFromServerPath("public/authenticate?failFirst=2")); + } + + private void assertAuthenticated(String response) { + + // Should not be authenticated in the "before" case, which is + // before request.authentiate is called + assertTrue( + "Should not be authenticated yet, but a username other than null was encountered. " + + "This is not correct.", + response.contains("before web username: null") + ); + assertTrue( + "Should not be authenticated yet, but the user seems to have the role \"architect\". " + + "This is not correct.", + response.contains("before web user has role \"architect\": false") + ); + + // The main request.authenticate causes the SAM to be called which always authenticates + assertTrue( + "Calling request.authenticate should have returned true, but did not.", + response.contains("request.authenticate outcome: true") + ); + + // Should be authenticated in the "after" case, which is + // after request.authentiate is called + assertTrue( + "User should have been authenticated and given name \"test\", " + + " but does not appear to have this name", + response.contains("after web username: test") + ); + assertTrue( + "User should have been authenticated and given role \"architect\", " + + " but does not appear to have this role", + response.contains("after web user has role \"architect\": true") + ); + } + + +} \ No newline at end of file diff --git a/tck/register-session/pom.xml b/tck/register-session/pom.xml new file mode 100644 index 0000000..3e63ca7 --- /dev/null +++ b/tck/register-session/pom.xml @@ -0,0 +1,40 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + register-session + war + + Jakarta Authentication TCK - register-session + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + + diff --git a/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java new file mode 100644 index 0000000..81a8991 --- /dev/null +++ b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/MyPrincipal.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import java.security.Principal; + +/** + * + * @author Arjan Tijms + * + */ +public class MyPrincipal implements Principal { + + private final String name; + + public MyPrincipal(String name) { + this.name = name; + } + + @Override + public String getName() { + return name; + } + +} diff --git a/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..8bcbdba --- /dev/null +++ b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java new file mode 100644 index 0000000..c007d8f --- /dev/null +++ b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/sam/TestServerAuthModule.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession.sam; + +import static jakarta.security.auth.message.AuthStatus.SUCCESS; +import static java.lang.Boolean.TRUE; + +import java.io.IOException; +import java.security.Principal; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + + +/** + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + Callback[] callbacks; + + Principal userPrincipal = request.getUserPrincipal(); + if (userPrincipal != null && request.getParameter("continueSession") != null) { + + // ### If already authenticated before, continue this session + + // Execute protocol to signal container registered authentication session be used. + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, userPrincipal) }; + + } else if (request.getParameter("doLogin") != null) { + + // ### If not authenticated before, do a new login if so requested + + // For the test perform a login by directly "returning" the details of the authenticated user. + // Normally credentials would be checked and the details fetched from some repository + + callbacks = new Callback[] { + // The name of the authenticated user + + request.getParameter("customPrincipal") == null? + // Name based Callback + new CallerPrincipalCallback(clientSubject, "test") : + + // Custom principal based Callback + new CallerPrincipalCallback(clientSubject, new MyPrincipal("test")), + + + // the roles of the authenticated user + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }; + + // Tell container to register an authentication session. + messageInfo.getMap().put("jakarta.servlet.http.registerSession", TRUE.toString()); + } else { + + // ### If no registered session and no login request "do nothing" + + // The Jakarta Authentication protocol for "do nothing" + callbacks = new Callback[] { new CallerPrincipalCallback(clientSubject, (Principal) null) }; + } + + try { + + // Communicate the details of the authenticated user to the container. In many + // cases the handler will just store the details and the container will actually handle + // the login after we return from this method. + handler.handle(callbacks); + + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + +} \ No newline at end of file diff --git a/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java new file mode 100644 index 0000000..3cbc17f --- /dev/null +++ b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/ProtectedServlet.java @@ -0,0 +1,53 @@ +package ee.jakarta.tck.authentication.test.registersession.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.registersession.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a protected servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = request.getUserPrincipal().getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + HttpSession session = request.getSession(false); + if (session != null) { + response.getWriter().write("Session ID: " + session.getId()); + } else { + response.getWriter().write("No session"); + } + + } + +} diff --git a/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java new file mode 100644 index 0000000..294a79f --- /dev/null +++ b/tck/register-session/src/main/java/ee/jakarta/tck/authentication/test/registersession/servlet/PublicServlet.java @@ -0,0 +1,53 @@ +package ee.jakarta.tck.authentication.test.registersession.servlet; + +import java.io.IOException; +import java.security.Principal; + +import ee.jakarta.tck.authentication.test.registersession.sam.MyPrincipal; +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; + + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + response.getWriter().write("This is a public servlet \n"); + + String webName = null; + boolean isCustomPrincipal = false; + if (request.getUserPrincipal() != null) { + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = principal.getName(); + } + + boolean webHasRole = request.isUserInRole("architect"); + + response.getWriter().write("isCustomPrincipal: " + isCustomPrincipal + "\n"); + response.getWriter().write("web username: " + webName + "\n"); + response.getWriter().write("web user has role \"architect\": " + webHasRole + "\n"); + + HttpSession session = request.getSession(false); + if (session != null) { + response.getWriter().write("Session ID: " + session.getId()); + } else { + response.getWriter().write("No session"); + } + + } + +} diff --git a/tck/register-session/src/main/webapp/WEB-INF/web.xml b/tck/register-session/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..bbbe7fd --- /dev/null +++ b/tck/register-session/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,37 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalTest.java b/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalTest.java new file mode 100644 index 0000000..cab6a05 --- /dev/null +++ b/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionCustomPrincipalTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * Variant of the {@link RegisterSessionTest}, where a custom principal is used instead + * of a container provided one. This is particularly challenging since the SAM has to + * pass the principal obtained from HttpServletRequest into the CallbackHandler, which + * then somehow has to recognize this as the signal to continue an authenticated session. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class RegisterSessionCustomPrincipalTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testRemembersSession() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 2 --------------------------- + + // We access the protected page again and now login + + response = getFromServerPath("protected/servlet?doLogin=true&customPrincipal=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 3 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + + checkAuthenticatedIdentity(response); + + // -------------------- Request 4 --------------------------- + + // The session should also be remembered for other resources, including public ones + + response = getFromServerPath("public/servlet?continueSession=true"); + + // This test almost can't fail, but include for clarity + assertTrue(response.contains("This is a public servlet")); + + // When accessing the public page, the username and roles should be restored and be available + // just as on protected pages + checkAuthenticatedIdentity(response); + } + + @Test + public void testJoinSessionIsOptional() throws IOException { + + // -------------------- Request 1 --------------------------- + + // We access a protected page and login + // + + String response = getFromServerPath("protected/servlet?doLogin=true&customPrincipal=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + + + // -------------------- Request 2 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 3 --------------------------- + + // Although the container remembers the authentication session, the SAM needs to OPT-IN to it. + // If the SAM instead "does nothing", we should not have access to the protected resource anymore + // even within the same HTTP session. + + response = getFromServerPath("protected/servlet"); + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 4 --------------------------- + + // Access to a public page is unaffected by joining or not joining the session, but if we do not join the + // session we shouldn't see the user's name and roles. + + response = getFromServerPath("public/servlet"); + + assertTrue( + "Could not access public page, but should be able to. " + + "Does the container have an automatic session fixation prevention?", + response.contains("This is a public servlet") + ); + assertFalse( + "SAM did not join authentication session and should be anonymous, but username is name of session identity.", + response.contains("web username: test") + ); + assertFalse( + "SAM did not join authentication session and should be anonymous without roles, but has role of session identity.", + response.contains("web user has role \"architect\": true") + ); + } + + private void checkAuthenticatedIdentity( String response) { + + // Has to be logged-in with the right principal + assertTrue( + "Authenticated but username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Authentication succeeded and username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true")); + + assertTrue( + "Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.", + response.contains("isCustomPrincipal: true") + ); + } + + + +} \ No newline at end of file diff --git a/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionTest.java b/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionTest.java new file mode 100644 index 0000000..0da1bbc --- /dev/null +++ b/tck/register-session/src/test/java/ee/jakarta/tck/authentication/test/registersession/RegisterSessionTest.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.registersession; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +@RunWith(Arquillian.class) +public class RegisterSessionTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testRemembersSession() throws IOException { + + // -------------------- Request 1 --------------------------- + + // Accessing protected page without login + String response = getFromServerPath("protected/servlet"); + + // Not logged-in thus should not be accessible. + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 2 --------------------------- + + // We access the protected page again and now login + + response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + + // -------------------- Request 3 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 4 --------------------------- + + // The session should also be remembered for other resources, including public ones + + response = getFromServerPath("public/servlet?continueSession=true"); + + // This test almost can't fail, but include for clarity + assertTrue(response.contains("This is a public servlet")); + + // When accessing the public page, the username and roles should be restored and be available + // just as on protected pages + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + } + + @Test + public void testJoinSessionIsOptional() throws IOException { + + // -------------------- Request 1 --------------------------- + + // We access a protected page and login + // + + String response = getFromServerPath("protected/servlet?doLogin=true"); + + // Now has to be logged-in so page is accessible + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container remember the previously set 'unauthenticated identity'?", + response.contains("This is a protected servlet") + ); + + + // -------------------- Request 2 --------------------------- + + // JASPIC is normally stateless, but for this test the SAM uses the register session feature so now + // we should be logged-in when doing a call without explicitly logging in again. + + response = getFromServerPath("protected/servlet?continueSession=true"); + + // Logged-in thus should be accessible. + assertTrue( + "Could not access protected page, but should be able to. " + + "Did the container not remember the authenticated identity via 'jakarta.servlet.http.registerSession'?", + response.contains("This is a protected servlet") + ); + + // Both the user name and roles/groups have to be restored + + // *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that + // this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly. + // Intuitively it should make sense though that the authenticated identity is fully restored and not partially, + // but again the spec should make this clear to avoid ambiguity. + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + + + // -------------------- Request 3 --------------------------- + + // Although the container remembers the authentication session, the SAM needs to OPT-IN to it. + // If the SAM instead "does nothing", we should not have access to the protected resource anymore + // even within the same HTTP session. + + response = getFromServerPath("protected/servlet"); + assertFalse(response.contains("This is a protected servlet")); + + + // -------------------- Request 4 --------------------------- + + // Access to a public page is unaffected by joining or not joining the session, but if we do not join the + // session we shouldn't see the user's name and roles. + + response = getFromServerPath("public/servlet"); + + assertTrue( + "Could not access public page, but should be able to. " + + "Does the container have an automatic session fixation prevention?", + response.contains("This is a public servlet") + ); + assertFalse( + "SAM did not join authentication session and should be anonymous, but username is name of session identity.", + response.contains("web username: test") + ); + assertFalse( + "SAM did not join authentication session and should be anonymous without roles, but has role of session identity.", + response.contains("web user has role \"architect\": true") + ); + } + + private void checkAuthenticatedIdentity(String response) { + + // Has to be logged-in with the right principal + assertTrue( + "Authenticated but username is not the expected one 'test'", + response.contains("web username: test") + ); + assertTrue( + "Authentication succeeded and username is correct, but the expected role 'architect' is not present.", + response.contains("web user has role \"architect\": true")); + + // Note, for this test if the following fails if would be most likely be an error in the test setup code + assertTrue( + "Authentication succeeded and username and roles are correct, but principal type should not be the custom one", + response.contains("isCustomPrincipal: false") + ); + } +} \ No newline at end of file diff --git a/tck/status-codes/pom.xml b/tck/status-codes/pom.xml new file mode 100644 index 0000000..a67a728 --- /dev/null +++ b/tck/status-codes/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + status-codes + war + + Jakarta Authentication TCK - status-codes + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/SamAutoRegistrationListener.java b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..3499f4a --- /dev/null +++ b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/SamAutoRegistrationListener.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes.sam; + +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestServerAuthModule(), sce.getServletContext()); + } + +} \ No newline at end of file diff --git a/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/TestServerAuthModule.java b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/TestServerAuthModule.java new file mode 100644 index 0000000..e5a7245 --- /dev/null +++ b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/sam/TestServerAuthModule.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_FAILURE; +import static jakarta.servlet.http.HttpServletResponse.SC_NOT_FOUND; + +import java.io.IOException; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.CallbackHandler; + +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * Very basic SAM that just sets an HTTP status code into the response and then returns SEND_FAILURE. + * + * @author Arjan Tijms + * + */ +public class TestServerAuthModule implements ServerAuthModule { + + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) throws AuthException { + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) throws AuthException { + + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + try { + response.sendError(SC_NOT_FOUND); + return SEND_FAILURE; + } catch (IOException e) { + throw (AuthException) new AuthException().initCause(e); + } + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } +} \ No newline at end of file diff --git a/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/ProtectedServlet.java b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/ProtectedServlet.java new file mode 100644 index 0000000..539705b --- /dev/null +++ b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/ProtectedServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("This is a protected servlet \n"); + } + +} diff --git a/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/PublicServlet.java b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/PublicServlet.java new file mode 100644 index 0000000..515b05d --- /dev/null +++ b/tck/status-codes/src/main/java/ee/jakarta/tck/authentication/test/statuscodes/servlet/PublicServlet.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes.servlet; + +import java.io.IOException; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/public/servlet") +public class PublicServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + response.getWriter().write("This is a public servlet \n"); + } + +} diff --git a/tck/status-codes/src/main/webapp/WEB-INF/web.xml b/tck/status-codes/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/status-codes/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/ProtectedStatusCodesTest.java b/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/ProtectedStatusCodesTest.java new file mode 100644 index 0000000..bff3374 --- /dev/null +++ b/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/ProtectedStatusCodesTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + + +/** + * This tests that a SAM can set a 404 response code when a protected resource is requested. + * Note the resource is not actual invoked, as the SAM returns SEND_FAILURE. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class ProtectedStatusCodesTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void test404inResponse() throws IOException { + + int code = getWebClient().getPage(getBase() + "protected/servlet") + .getWebResponse() + .getStatusCode(); + + assertEquals( + "Response should have 404 not found as status code, but did not.", + 404, code + ); + } + +} \ No newline at end of file diff --git a/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/PublicStatusCodesTest.java b/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/PublicStatusCodesTest.java new file mode 100644 index 0000000..e09d102 --- /dev/null +++ b/tck/status-codes/src/test/java/ee/jakarta/tck/authentication/test/statuscodes/PublicStatusCodesTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.statuscodes; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + + +/** + * This tests that a SAM can set a 404 response code when a public resource is requested. + * Note the resource is not actual invoked, as the SAM returns SEND_FAILURE. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class PublicStatusCodesTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void test404inResponse() throws IOException { + + int code = getWebClient().getPage(getBase() + "public/servlet") + .getWebResponse() + .getStatusCode(); + + assertEquals( + "Response should have 404 not found as status code, but did not.", + 404, code + ); + } + +} \ No newline at end of file diff --git a/tck/wrapping/pom.xml b/tck/wrapping/pom.xml new file mode 100644 index 0000000..cdbfdb5 --- /dev/null +++ b/tck/wrapping/pom.xml @@ -0,0 +1,39 @@ + + + + 4.0.0 + + + org.eclipse.ee4j.tck.authentication + jakarta-authentication-tck + 3.0.0-SNAPSHOT + + + wrapping + war + + Jakarta Authentication TCK - wrapping + + + + org.jakartaee + jaspic-common + 1.0-SNAPSHOT + + + diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/SamAutoRegistrationListener.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/SamAutoRegistrationListener.java new file mode 100644 index 0000000..8c02c94 --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/SamAutoRegistrationListener.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.sam; + +import static java.util.EnumSet.allOf; + +import ee.jakarta.tck.authentication.test.wrapping.servlet.ProgrammaticFilter; +import jakarta.security.auth.message.config.AuthConfigFactory; +import jakarta.servlet.DispatcherType; +import jakarta.servlet.ServletContextEvent; +import jakarta.servlet.ServletContextListener; +import jakarta.servlet.annotation.WebListener; + +/** + * + * @author Arjan Tijms + * + */ +@WebListener +public class SamAutoRegistrationListener implements ServletContextListener { + + @Override + public void contextInitialized(ServletContextEvent sce) { + AuthConfigFactory.getFactory() + .registerServerAuthModule(new TestWrappingServerAuthModule(), sce.getServletContext()); + + sce.getServletContext() + .addFilter("Programmatic filter", ProgrammaticFilter.class) + .addMappingForUrlPatterns(allOf(DispatcherType.class), false, "/*"); + } + +} \ No newline at end of file diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/TestWrappingServerAuthModule.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/TestWrappingServerAuthModule.java new file mode 100644 index 0000000..6492c5e --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/sam/TestWrappingServerAuthModule.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.sam; + +import static jakarta.security.auth.message.AuthStatus.SEND_SUCCESS; +import static jakarta.security.auth.message.AuthStatus.SUCCESS; + +import java.io.IOException; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.UnsupportedCallbackException; + +import ee.jakarta.tck.authentication.test.wrapping.servlet.TestHttpServletRequestWrapper; +import ee.jakarta.tck.authentication.test.wrapping.servlet.TestHttpServletResponseWrapper; +import jakarta.security.auth.message.AuthException; +import jakarta.security.auth.message.AuthStatus; +import jakarta.security.auth.message.MessageInfo; +import jakarta.security.auth.message.MessagePolicy; +import jakarta.security.auth.message.callback.CallerPrincipalCallback; +import jakarta.security.auth.message.callback.GroupPrincipalCallback; +import jakarta.security.auth.message.module.ServerAuthModule; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * + * @author Arjan Tijms + * + */ +public class TestWrappingServerAuthModule implements ServerAuthModule { + + private CallbackHandler handler; + private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; + + @Override + public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, + @SuppressWarnings("rawtypes") Map options) throws AuthException { + this.handler = handler; + } + + @Override + public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) + throws AuthException { + + try { + handler.handle(new Callback[] { + new CallerPrincipalCallback(clientSubject, "test"), + new GroupPrincipalCallback(clientSubject, new String[] { "architect" }) }); + } catch (IOException | UnsupportedCallbackException e) { + throw (AuthException) new AuthException().initCause(e); + } + + // Wrap the request - the resource to be invoked should get to see this + messageInfo.setRequestMessage(new TestHttpServletRequestWrapper( + (HttpServletRequest) messageInfo.getRequestMessage()) + ); + + // Wrap the response - the resource to be invoked should get to see this + messageInfo.setResponseMessage(new TestHttpServletResponseWrapper( + (HttpServletResponse) messageInfo.getResponseMessage()) + ); + + return SUCCESS; + } + + @Override + public Class[] getSupportedMessageTypes() { + return supportedMessageTypes; + } + + @Override + public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) throws AuthException { + + HttpServletRequest request = (HttpServletRequest) messageInfo.getRequestMessage(); + + // Unwrap the request + if (request instanceof TestHttpServletRequestWrapper) { + messageInfo.setRequestMessage(((TestHttpServletRequestWrapper) request).getRequest()); + } + + HttpServletResponse response = (HttpServletResponse) messageInfo.getResponseMessage(); + + if (response instanceof TestHttpServletResponseWrapper) { + messageInfo.setResponseMessage(((TestHttpServletResponseWrapper) response).getResponse()); + } + + return SEND_SUCCESS; + } + + @Override + public void cleanSubject(MessageInfo messageInfo, Subject subject) throws AuthException { + + } +} \ No newline at end of file diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/DeclaredFilter.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/DeclaredFilter.java new file mode 100644 index 0000000..1afe32b --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/DeclaredFilter.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.servlet; + +import java.io.IOException; +import java.io.Writer; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.annotation.WebFilter; +import jakarta.servlet.http.HttpServletResponse; + +/** + * This Filter tests that the request and response objects it receives are the ones marked as wrapped by the SAM that executed + * before the Servlet was called. + * + * @author Arjan Tijms + * + */ +@WebFilter(urlPatterns="/*") +public class DeclaredFilter implements Filter { + + @Override + public void init(FilterConfig fConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + Writer writer = response.getWriter(); + + writer.write("declared filter request isWrapped: " + request.getAttribute("isWrapped")); + writer.write("\n"); + writer.write("declared filter response isWrapped: " + ((HttpServletResponse)response).getHeader("isWrapped")); + writer.write("\n"); + + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + +} diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProgrammaticFilter.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProgrammaticFilter.java new file mode 100644 index 0000000..3370027 --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProgrammaticFilter.java @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.servlet; + +import java.io.IOException; +import java.io.Writer; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletResponse; + +/** + * This Filter tests that the request and response objects it receives are the ones marked as wrapped by the SAM that executed + * before the Servlet was called. + * + * @author Arjan Tijms + * + */ +public class ProgrammaticFilter implements Filter { + + @Override + public void init(FilterConfig fConfig) throws ServletException { + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + + Writer writer = response.getWriter(); + + writer.write("programmatic filter request isWrapped: " + request.getAttribute("isWrapped")); + writer.write("\n"); + writer.write("programmatic filter response isWrapped: " + ((HttpServletResponse)response).getHeader("isWrapped")); + writer.write("\n"); + + chain.doFilter(request, response); + } + + @Override + public void destroy() { + } + +} diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProtectedServlet.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProtectedServlet.java new file mode 100644 index 0000000..0b9065c --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/ProtectedServlet.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.servlet; + +import java.io.IOException; +import java.io.Writer; + +import jakarta.servlet.ServletException; +import jakarta.servlet.annotation.WebServlet; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +/** + * This Servlet tests that the request and response objects it receives are the ones marked as wrapped by the SAM that executed + * before the Servlet was called. + * + * @author Arjan Tijms + * + */ +@WebServlet(urlPatterns = "/protected/servlet") +public class ProtectedServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + + @Override + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { + + Writer writer = response.getWriter(); + + writer.write("servlet request isWrapped: " + request.getAttribute("isWrapped")); + writer.write("\n"); + writer.write("servlet response isWrapped: " + response.getHeader("isWrapped")); + } + +} diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletRequestWrapper.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletRequestWrapper.java new file mode 100644 index 0000000..3d6ea49 --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletRequestWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.servlet; + +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequestWrapper; + +/** + * + * @author Arjan Tijms + * + */ +public class TestHttpServletRequestWrapper extends HttpServletRequestWrapper { + + public TestHttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public Object getAttribute(String name) { + + if ("isWrapped".equals(name)) { + return Boolean.TRUE; + } + + return super.getAttribute(name); + } + +} diff --git a/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletResponseWrapper.java b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletResponseWrapper.java new file mode 100644 index 0000000..d020dd0 --- /dev/null +++ b/tck/wrapping/src/main/java/ee/jakarta/tck/authentication/test/wrapping/servlet/TestHttpServletResponseWrapper.java @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping.servlet; + +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpServletResponseWrapper; + +/** + * + * @author Arjan Tijms + * + */ +public class TestHttpServletResponseWrapper extends HttpServletResponseWrapper { + + public TestHttpServletResponseWrapper(HttpServletResponse response) { + super(response); + } + + @Override + public String getHeader(String name) { + + if ("isWrapped".equals(name)) { + return "true"; + } + + return super.getHeader(name); + } + +} diff --git a/tck/wrapping/src/main/webapp/WEB-INF/web.xml b/tck/wrapping/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..d1bbf60 --- /dev/null +++ b/tck/wrapping/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,36 @@ + + + + + + + Test + /protected/* + + + architect + + + + + architect + + + \ No newline at end of file diff --git a/tck/wrapping/src/test/java/ee/jakarta/tck/authentication/test/wrapping/WrappingTest.java b/tck/wrapping/src/test/java/ee/jakarta/tck/authentication/test/wrapping/WrappingTest.java new file mode 100644 index 0000000..e18ef75 --- /dev/null +++ b/tck/wrapping/src/test/java/ee/jakarta/tck/authentication/test/wrapping/WrappingTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2022-2022 Contributors to the Eclipse Foundation + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0, which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the + * Eclipse Public License v. 2.0 are satisfied: GNU General Public License, + * version 2 with the GNU Classpath Exception, which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + */ +package ee.jakarta.tck.authentication.test.wrapping; + +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.shrinkwrap.api.Archive; +import org.junit.Test; +import org.junit.runner.RunWith; + +import ee.jakarta.tck.authentication.test.common.ArquillianBase; + +/** + * This tests that the wrapped request and response a SAM puts into the MessageInfo structure reaches the Servlet that's + * invoked as well as all filters executed before that. + * + * @author Arjan Tijms + * + */ +@RunWith(Arquillian.class) +public class WrappingTest extends ArquillianBase { + + @Deployment(testable = false) + public static Archive createDeployment() { + return defaultArchive(); + } + + @Test + public void testProgrammaticFilterRequestWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a request so that it always contains the request attribute "isWrapped" with value true. + assertTrue("Request wrapped by SAM did not arrive in programmatic Filter.", + response.contains("programmatic filter request isWrapped: true")); + } + + @Test + public void testProgrammaticFilterResponseWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a response so that it always contains the header "isWrapped" with value true. + assertTrue("Response wrapped by SAM did not arrive in programmatic Filter.", + response.contains("programmatic filter response isWrapped: true")); + } + + @Test + public void testDeclaredFilterRequestWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a request so that it always contains the request attribute "isWrapped" with value true. + assertTrue("Request wrapped by SAM did not arrive in declared Filter.", + response.contains("declared filter request isWrapped: true")); + } + + @Test + public void testDeclaredFilterResponseWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a response so that it always contains the header "isWrapped" with value true. + assertTrue("Response wrapped by SAM did not arrive in declared Filter.", + response.contains("declared filter response isWrapped: true")); + } + + @Test + public void testRequestWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a request so that it always contains the request attribute "isWrapped" with value true. + assertTrue("Request wrapped by SAM did not arrive in Servlet.", + response.contains("servlet request isWrapped: true")); + } + + @Test + public void testResponseWrapping() throws IOException { + + String response = getFromServerPath("protected/servlet"); + + // The SAM wrapped a response so that it always contains the header "isWrapped" with value true. + assertTrue("Response wrapped by SAM did not arrive in Servlet.", + response.contains("servlet response isWrapped: true")); + } + +} \ No newline at end of file diff --git a/tck/zip.xml b/tck/zip.xml new file mode 100644 index 0000000..4b28108 --- /dev/null +++ b/tck/zip.xml @@ -0,0 +1,38 @@ + + + + zip + true + + + zip + + + + + ${project.basedir}/ + + **/target/** + + + + + \ No newline at end of file