From b4bfc05be0da73239e000df14eee7b6fee499bfe Mon Sep 17 00:00:00 2001 From: "arjan.tijms" Date: Fri, 8 Apr 2016 15:33:10 +0200 Subject: [PATCH] Added tests for JASPIC register session with custom principal --- .../registersession/sam/MyPrincipal.java | 23 +++ .../sam/TestServerAuthModule.java | 14 +- .../servlet/ProtectedServlet.java | 15 +- .../servlet/PublicServlet.java | 15 +- .../RegisterSessionCustomPrincipalTest.java | 187 ++++++++++++++++++ .../registersession/RegisterSessionTest.java | 45 ++++- 6 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/MyPrincipal.java create mode 100644 jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java diff --git a/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/MyPrincipal.java b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/MyPrincipal.java new file mode 100644 index 000000000..6cb47c75b --- /dev/null +++ b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/MyPrincipal.java @@ -0,0 +1,23 @@ +package org.javaee7.jaspic.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/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/TestServerAuthModule.java b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/TestServerAuthModule.java index 47e471be1..89ea01287 100644 --- a/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/TestServerAuthModule.java +++ b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/sam/TestServerAuthModule.java @@ -6,7 +6,6 @@ import java.io.IOException; import java.security.Principal; import java.util.Map; -import java.util.logging.Logger; import javax.security.auth.Subject; import javax.security.auth.callback.Callback; @@ -22,6 +21,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + /** * * @author Arjan Tijms @@ -29,8 +29,6 @@ */ public class TestServerAuthModule implements ServerAuthModule { - Logger logger = Logger.getLogger("blalllalala"); - private CallbackHandler handler; private Class[] supportedMessageTypes = new Class[] { HttpServletRequest.class, HttpServletResponse.class }; @@ -65,7 +63,15 @@ public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject callbacks = new Callback[] { // The name of the authenticated user - new CallerPrincipalCallback(clientSubject, "test"), + + 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" }) }; diff --git a/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/ProtectedServlet.java b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/ProtectedServlet.java index 58ea379aa..9b5c06774 100644 --- a/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/ProtectedServlet.java +++ b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/ProtectedServlet.java @@ -1,6 +1,7 @@ package org.javaee7.jaspic.registersession.servlet; import java.io.IOException; +import java.security.Principal; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; @@ -8,6 +9,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.javaee7.jaspic.registersession.sam.MyPrincipal; + + /** * * @author Arjan Tijms @@ -22,16 +26,19 @@ public class ProtectedServlet extends HttpServlet { 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(); } - response.getWriter().write("web username: " + webName + "\n"); - 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/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/PublicServlet.java b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/PublicServlet.java index c47e04826..f1b2812e8 100644 --- a/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/PublicServlet.java +++ b/jaspic/register-session/src/main/java/org/javaee7/jaspic/registersession/servlet/PublicServlet.java @@ -1,6 +1,7 @@ package org.javaee7.jaspic.registersession.servlet; import java.io.IOException; +import java.security.Principal; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; @@ -8,6 +9,9 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.javaee7.jaspic.registersession.sam.MyPrincipal; + + /** * * @author Arjan Tijms @@ -24,14 +28,17 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro response.getWriter().write("This is a public servlet \n"); String webName = null; + boolean isCustomPrincipal = false; if (request.getUserPrincipal() != null) { - webName = request.getUserPrincipal().getName(); + Principal principal = request.getUserPrincipal(); + isCustomPrincipal = principal instanceof MyPrincipal; + webName = principal.getName(); } - - response.getWriter().write("web username: " + webName + "\n"); - + 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/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java b/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java new file mode 100644 index 000000000..80889f5ce --- /dev/null +++ b/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionCustomPrincipalTest.java @@ -0,0 +1,187 @@ +package org.javaee7.jaspic.registersession; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import org.javaee7.jaspic.common.ArquillianBase; +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 org.xml.sax.SAXException; + +/** + * 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, SAXException { + + // -------------------- 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 'javax.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, SAXException { + + // -------------------- 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 'javax.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(response.contains("This is a public servlet")); + assertFalse(response.contains("web username: test")); + assertFalse(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/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java b/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java index 62f3bc989..2311cbf6a 100644 --- a/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java +++ b/jaspic/register-session/src/test/java/org/javaee7/jaspic/registersession/RegisterSessionTest.java @@ -31,7 +31,8 @@ public void testRemembersSession() throws IOException, SAXException { // 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 @@ -44,6 +45,11 @@ public void testRemembersSession() throws IOException, SAXException { "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 --------------------------- @@ -65,8 +71,10 @@ public void testRemembersSession() throws IOException, SAXException { // 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. - assertTrue(response.contains("web username: test")); - assertTrue(response.contains("web user has role \"architect\": true")); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + // -------------------- Request 4 --------------------------- @@ -79,8 +87,9 @@ public void testRemembersSession() throws IOException, SAXException { // When accessing the public page, the username and roles should be restored and be available // just as on protected pages - assertTrue(response.contains("web username: test")); - assertTrue(response.contains("web user has role \"architect\": true")); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); } @Test @@ -99,6 +108,7 @@ public void testJoinSessionIsOptional() throws IOException, SAXException { "Did the container remember the previously set 'unauthenticated identity'?", response.contains("This is a protected servlet") ); + // -------------------- Request 2 --------------------------- @@ -120,8 +130,10 @@ public void testJoinSessionIsOptional() throws IOException, SAXException { // 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. - assertTrue(response.contains("web username: test")); - assertTrue(response.contains("web user has role \"architect\": true")); + + // Check principal has right name and right type and roles are available + checkAuthenticatedIdentity(response); + // -------------------- Request 3 --------------------------- @@ -131,6 +143,7 @@ public void testJoinSessionIsOptional() throws IOException, SAXException { response = getFromServerPath("protected/servlet"); assertFalse(response.contains("This is a protected servlet")); + // -------------------- Request 4 --------------------------- @@ -143,4 +156,22 @@ public void testJoinSessionIsOptional() throws IOException, SAXException { assertFalse(response.contains("web username: test")); assertFalse(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