Skip to content

Commit e7a3b43

Browse files
committed
Added JASPIC tests for EJB propagation after register session
1 parent b4bfc05 commit e7a3b43

6 files changed

Lines changed: 489 additions & 0 deletions

File tree

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package org.javaee7.jaspic.registersession.ejb;
2+
3+
import javax.annotation.Resource;
4+
import javax.annotation.security.DeclareRoles;
5+
import javax.annotation.security.PermitAll;
6+
import javax.annotation.security.RolesAllowed;
7+
import javax.ejb.EJBContext;
8+
import javax.ejb.Stateless;
9+
10+
/**
11+
* This is a "protected" EJB in the sense that there is role checking done prior to accessing (some) methods.
12+
* <p>
13+
* In JBoss EAP 6.1+ the use of any declarative security annotation switches the bean to a different mode, called "secured" in
14+
* JBoss terms.
15+
* <p>
16+
* GlassFish requires the <code>@DeclareRoles</code> annotation when programmatic role checking is done (making dynamic role
17+
* checking impossible).
18+
*
19+
* @author Arjan Tijms
20+
*/
21+
@Stateless
22+
//Required by GlassFish
23+
@DeclareRoles({ "architect" })
24+
//JBoss EAP 6.1+ defaults unchecked methods to DenyAll
25+
@PermitAll
26+
public class ProtectedEJB {
27+
28+
@Resource
29+
private EJBContext ejbContext;
30+
31+
@RolesAllowed("architect")
32+
public String getUserName() {
33+
try {
34+
return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null;
35+
} catch (Exception e) {
36+
e.printStackTrace();
37+
}
38+
return null;
39+
}
40+
41+
public boolean isUserArchitect() {
42+
try {
43+
return ejbContext.isCallerInRole("architect");
44+
} catch (Exception e) {
45+
e.printStackTrace();
46+
}
47+
return false;
48+
49+
}
50+
51+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.javaee7.jaspic.registersession.ejb;
2+
import javax.annotation.Resource;
3+
import javax.ejb.EJBContext;
4+
import javax.ejb.Stateless;
5+
6+
/**
7+
* This is a "public" EJB in the sense that all its methods should be accessible and there is no declarative role checking prior
8+
* to accessing a method.
9+
*
10+
* @author Arjan Tijms
11+
*
12+
*/
13+
@Stateless
14+
public class PublicEJB {
15+
16+
@Resource
17+
private EJBContext ejbContext;
18+
19+
public String getUserName() {
20+
try {
21+
return ejbContext.getCallerPrincipal() != null ? ejbContext.getCallerPrincipal().getName() : null;
22+
} catch (Exception e) {
23+
e.printStackTrace();
24+
}
25+
return null;
26+
}
27+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.javaee7.jaspic.registersession.servlet;
2+
import static java.util.logging.Level.SEVERE;
3+
4+
import java.io.IOException;
5+
import java.util.logging.Logger;
6+
7+
import javax.ejb.EJB;
8+
import javax.servlet.ServletException;
9+
import javax.servlet.annotation.WebServlet;
10+
import javax.servlet.http.HttpServlet;
11+
import javax.servlet.http.HttpServletRequest;
12+
import javax.servlet.http.HttpServletResponse;
13+
14+
import org.javaee7.jaspic.registersession.ejb.ProtectedEJB;
15+
16+
17+
/**
18+
*
19+
* @author Arjan Tijms
20+
*
21+
*/
22+
@WebServlet(urlPatterns = "/public/servlet-protected-ejb")
23+
public class PublicServletProtectedEJB extends HttpServlet {
24+
25+
private static final long serialVersionUID = 1L;
26+
private final static Logger logger = Logger.getLogger(PublicServletProtectedEJB.class.getName());
27+
28+
@EJB
29+
private ProtectedEJB protectedEJB;
30+
31+
@Override
32+
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
33+
34+
String webName = null;
35+
if (request.getUserPrincipal() != null) {
36+
webName = request.getUserPrincipal().getName();
37+
}
38+
39+
String ejbName = "";
40+
try {
41+
ejbName = protectedEJB.getUserName();
42+
} catch (Exception e) {
43+
logger.log(SEVERE, "", e);
44+
}
45+
46+
response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n");
47+
48+
boolean webHasRole = request.isUserInRole("architect");
49+
50+
boolean ejbHasRole = false;
51+
try {
52+
ejbHasRole = protectedEJB.isUserArchitect();
53+
} catch (Exception e) {
54+
logger.log(SEVERE, "", e);
55+
}
56+
57+
response.getWriter().write(
58+
"web user has role \"architect\": " + webHasRole + "\n" + "EJB user has role \"architect\": " + ejbHasRole
59+
+ "\n");
60+
61+
}
62+
63+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.javaee7.jaspic.registersession.servlet;
2+
import static java.util.logging.Level.SEVERE;
3+
4+
import java.io.IOException;
5+
import java.util.logging.Logger;
6+
7+
import javax.ejb.EJB;
8+
import javax.servlet.ServletException;
9+
import javax.servlet.annotation.WebServlet;
10+
import javax.servlet.http.HttpServlet;
11+
import javax.servlet.http.HttpServletRequest;
12+
import javax.servlet.http.HttpServletResponse;
13+
14+
import org.javaee7.jaspic.registersession.ejb.PublicEJB;
15+
16+
17+
/**
18+
*
19+
* @author Arjan Tijms
20+
*
21+
*/
22+
@WebServlet(urlPatterns = "/public/servlet-public-ejb")
23+
public class PublicServletPublicEJB extends HttpServlet {
24+
25+
private static final long serialVersionUID = 1L;
26+
private final static Logger logger = Logger.getLogger(PublicServletPublicEJB.class.getName());
27+
28+
@EJB
29+
private PublicEJB publicEJB;
30+
31+
@Override
32+
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
33+
34+
String webName = null;
35+
if (request.getUserPrincipal() != null) {
36+
webName = request.getUserPrincipal().getName();
37+
}
38+
39+
String ejbName = "";
40+
try {
41+
ejbName = publicEJB.getUserName();
42+
} catch (Exception e) {
43+
logger.log(SEVERE, "", e);
44+
}
45+
46+
response.getWriter().write("web username: " + webName + "\n" + "EJB username: " + ejbName + "\n");
47+
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package org.javaee7.jaspic.registersession;
2+
3+
import static org.junit.Assert.assertFalse;
4+
import static org.junit.Assert.assertTrue;
5+
6+
import java.io.IOException;
7+
8+
import org.javaee7.jaspic.common.ArquillianBase;
9+
import org.jboss.arquillian.container.test.api.Deployment;
10+
import org.jboss.arquillian.junit.Arquillian;
11+
import org.jboss.shrinkwrap.api.Archive;
12+
import org.junit.Test;
13+
import org.junit.runner.RunWith;
14+
import org.xml.sax.SAXException;
15+
16+
/**
17+
* Variant of the {@link RegisterSessionCustomPrincipalTest}, where it's tested
18+
* if the authenticated identity restored by the runtime correctly propagates
19+
* to EJB.
20+
*
21+
* @author Arjan Tijms
22+
*
23+
*/
24+
@RunWith(Arquillian.class)
25+
public class RegisterSessionCustomPrincipalEJBPropagationTest extends ArquillianBase {
26+
27+
@Deployment(testable = false)
28+
public static Archive<?> createDeployment() {
29+
return defaultArchive();
30+
}
31+
32+
@Test
33+
public void testRemembersSession() throws IOException, SAXException {
34+
35+
// -------------------- Request 1 ---------------------------
36+
37+
// Accessing protected page without login
38+
String response = getFromServerPath("protected/servlet");
39+
40+
// Not logged-in thus should not be accessible.
41+
assertFalse(response.contains("This is a protected servlet"));
42+
43+
44+
// -------------------- Request 2 ---------------------------
45+
46+
// We access the protected page again and now login
47+
48+
response = getFromServerPath("protected/servlet?doLogin=true&customPrincipal=true");
49+
50+
// Now has to be logged-in so page is accessible
51+
assertTrue(
52+
"Could not access protected page, but should be able to. " +
53+
"Did the container remember the previously set 'unauthenticated identity'?",
54+
response.contains("This is a protected servlet")
55+
);
56+
57+
// Check principal has right name and right type and roles are available
58+
checkAuthenticatedIdentity(response);
59+
60+
61+
// -------------------- Request 3 ---------------------------
62+
63+
// JASPIC is normally stateless, but for this test the SAM uses the register session feature so now
64+
// we should be logged-in when doing a call without explicitly logging in again.
65+
66+
response = getFromServerPath("protected/servlet?continueSession=true");
67+
68+
// Logged-in thus should be accessible.
69+
assertTrue(
70+
"Could not access protected page, but should be able to. " +
71+
"Did the container not remember the authenticated identity via 'javax.servlet.http.registerSession'?",
72+
response.contains("This is a protected servlet")
73+
);
74+
75+
// Both the user name and roles/groups have to be restored
76+
77+
// *** NOTE ***: The JASPIC 1.1 spec is NOT clear about remembering roles, but spec lead Ron Monzillo clarified that
78+
// this should indeed be the case. The next JASPIC revision of the spec will have to mention this explicitly.
79+
// Intuitively it should make sense though that the authenticated identity is fully restored and not partially,
80+
// but again the spec should make this clear to avoid ambiguity.
81+
82+
checkAuthenticatedIdentity(response);
83+
84+
85+
// -------------------- Request 4 ---------------------------
86+
87+
// The session should also be remembered and propagated to a public EJB
88+
89+
response = getFromServerPath("public/servlet-public-ejb?continueSession=true");
90+
91+
// Both the web (HttpServletRequest) and EJB (EJBContext) should see the same
92+
// user name.
93+
assertTrue(
94+
"User should have been authenticated in the web layer and given name \"test\", " +
95+
" but does not appear to have this name",
96+
response.contains("web username: test")
97+
);
98+
assertTrue(
99+
"Web has user principal set, but EJB not.",
100+
response.contains("EJB username: test")
101+
);
102+
103+
104+
// -------------------- Request 5 ---------------------------
105+
106+
// The session should also be remembered and propagated to a protected EJB
107+
108+
response = getFromServerPath("public/servlet-protected-ejb?continueSession=true");
109+
110+
// Both the web (HttpServletRequest) and EJB (EJBContext) should see the same
111+
// user name.
112+
assertTrue(
113+
"User should have been authenticated in the web layer and given name \"test\", " +
114+
" but does not appear to have this name",
115+
response.contains("web username: test")
116+
);
117+
assertTrue(
118+
"Web has user principal set, but EJB not.",
119+
response.contains("EJB username: test")
120+
);
121+
122+
// Both the web (HttpServletRequest) and EJB (EJBContext) should see that the
123+
// user has the role "architect".
124+
assertTrue(response.contains("web user has role \"architect\": true"));
125+
assertTrue("Web user principal has role \"architect\", but one in EJB doesn't.",
126+
response.contains("EJB user has role \"architect\": true"));
127+
128+
}
129+
130+
private void checkAuthenticatedIdentity( String response) {
131+
132+
// Has to be logged-in with the right principal
133+
assertTrue(
134+
"Authenticated but username is not the expected one 'test'",
135+
response.contains("web username: test")
136+
);
137+
assertTrue(
138+
"Authentication succeeded and username is correct, but the expected role 'architect' is not present.",
139+
response.contains("web user has role \"architect\": true"));
140+
141+
assertTrue(
142+
"Authentication succeeded and username and roles are correct, but principal type is not the expected custom type.",
143+
response.contains("isCustomPrincipal: true")
144+
);
145+
}
146+
147+
148+
149+
}

0 commit comments

Comments
 (0)