[jboss-user] [JBoss Seam] - Re: External Client and Seam Security
agnadello
do-not-reply at jboss.com
Wed Nov 28 08:55:10 EST 2007
Hi again,
Well, I did put a breakpoint at the RootInterceptor.invoke() method and it gets hit.
I've also implemented the manual Identity.login(), even tested with Identity.authenticate().
I've also verified that the @Restrict("#{s:hasRole('user')}") works if I access the method from my JSF after I'm logged in.
Seems like I'm missing something here so I'll give you the whole enchillada!
Here's my Quartz Pojo Job
| public class SampleJob implements Job {
|
| private final Logger LOGGER = Logger.getLogger(this.getClass());
|
| public void execute(final JobExecutionContext theJobExecutionContext)
| throws JobExecutionException {
| this.LOGGER.info("Executing job with description: "
| + theJobExecutionContext.getJobDetail().getDescription());
| LoginContext lc = null;
| try {
| // Begin Seam session
| Lifecycle.beginSession(new java.util.HashMap<String, Object>());
|
| // External client login
| UsernamePasswordHandler handler = new UsernamePasswordHandler(
| "user", "Demo987!");
| lc = new LoginContext("client-login", handler);
| lc.login();
|
| // Lookup EJB
| final TestSeamSecurityService service = (TestSeamSecurityService) new InitialContext()
| .lookup("sio/TestSeamSecurityServiceBean/local");
|
| // Any calls to secured resources now use the username/password
| // identity
| service.login("user", "Demo987!");
|
| // Should fail because 'user' don't have the role 'admin'
| service.secure();
|
| // Clear and restore the previous identity
| service.logout();
| lc.logout();
| } catch (Exception e) {
| e.printStackTrace();
| } finally {
| // End Seam session
| Lifecycle.endSession(new java.util.HashMap<String, Object>());
| }
| }
| }
|
And here's my Seam component using the @Restrict annotation (local business interface omitted):
| @Stateful
| @SecurityDomain("sio")
| @Local(TestSeamSecurityService.class)
| @Name("echoService")
| public class TestSeamSecurityServiceBean implements TestSeamSecurityService {
|
| @Logger
| private transient Log log;
|
| @Resource
| private SessionContext sessionContext;
|
| @RolesAllowed("user")
| public void login(final String theUsername, final String thePassword)
| throws LoginException {
| this.log.info("Entered 'login' method...");
| // Seam login
| Identity.instance().setUsername(theUsername);
| Identity.instance().setPassword(thePassword);
| Identity.instance().login();
| // Identity.instance().authenticate();
| this.log.info("Exiting 'login' method.");
| this.status();
| }
|
| public void logout() {
| Identity.instance().logout();
| }
|
| @Restrict("#{s:hasRole('admin')}")
| public void secure() {
| this.log.info("Entered 'secure' method.");
| this.status();
| }
|
| @Remove
| @Destroy
| public void destroy() {
| }
|
| private void status() {
| this.log.info("-=STATUS=-");
| this.log.info("Caller Principal = #0", this.sessionContext
| .getCallerPrincipal());
| this.log.info("Is Identity Security Enabled = #0", Identity
| .isSecurityEnabled());
| this.log.info("Identity Is Logged In = #0", Identity.instance()
| .isLoggedIn());
| this.log.info("Identity Has Role 'user' = #0", Identity.instance()
| .hasRole("user"));
| this.log.info("Identity Has Role 'admin' = #0", Identity.instance()
| .hasRole("admin"));
| }
|
| }
|
As you can see I've implemented the "standard Java EE security" using @SecurityDomain annotation. The annotation @RolesAllowed works like a charm but not @Restrict.
component.xml
| <?xml version="1.0" encoding="UTF-8"?>
| <components xmlns="http://jboss.com/products/seam/components"
| xmlns:core="http://jboss.com/products/seam/core"
| xmlns:persistence="http://jboss.com/products/seam/persistence"
| xmlns:security="http://jboss.com/products/seam/security"
| xmlns:drools="http://jboss.com/products/seam/drools"
| xmlns:async="http://jboss.com/products/seam/async"
| xmlns:web="http://jboss.com/products/seam/web"
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
| xmlns:framework="http://jboss.com/products/seam/framework"
| xsi:schemaLocation="http://jboss.com/products/seam/core http://jboss.com/products/seam/core-2.0.xsd
| http://jboss.com/products/seam/persistence http://jboss.com/products/seam/persistence-2.0.xsd
| http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.0.xsd
| http://jboss.com/products/seam/security http://jboss.com/products/seam/security-2.0.xsd
| http://jboss.com/products/seam/async http://jboss.com/products/seam/async-2.0.xsd
| http://jboss.com/products/seam/web http://jboss.com/products/seam/web-2.0.xsd
| http://jboss.com/products/seam/framework http://jboss.com/products/seam/framework-2.0.xsd
| http://jboss.com/products/seam/drools http://jboss.com/products/seam/drools-2.0.xsd">
|
| <core:init jndi-pattern="sio/#{ejbName}/local" debug="true"
| transaction-management-enabled="true" />
|
| <persistence:managed-persistence-context name="entityManager"
| auto-create="true"
| persistence-unit-jndi-name="java:/OracleSioEntityManagerFactory" />
|
| <core:manager conversation-timeout="600000"
| concurrent-request-timeout="500" conversation-id-parameter="cid" />
|
| <!-- Default system JAAS configuration -->
| <security:identity
| authenticate-method="#{authenticator.authenticate}"
| jaas-config-name="sio" />
|
| <drools:rule-base name="securityRules">
| <drools:rule-files>
| <value>/META-INF/security.drl</value>
| </drools:rule-files>
| </drools:rule-base>
|
| <framework:entity-query name="roles" ejbql="select r from Role r" />
|
| <event type="org.jboss.seam.notLoggedIn">
| <action execute="#{redirect.captureCurrentView}" />
| </event>
|
| <event type="org.jboss.seam.postAuthenticate">
| <action execute="#{redirect.returnToCapturedView}" />
| </event>
|
| </components>
|
The Drools rules in security.drl only concerns entities not part of this problem so I'm not including it and the orm.xml in this post. Does anyone feel the need to see just tell me :-)
web.xml
| <?xml version="1.0" encoding="UTF-8"?>
|
| <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
| xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
| <!-- Initializes Quartz in the application server -->
|
| <servlet>
| <servlet-name>QuartzInitializer</servlet-name>
| <display-name>Quartz Initializer Servlet</display-name>
| <servlet-class>
| org.quartz.ee.servlet.QuartzInitializerServlet
| </servlet-class>
| <load-on-startup>2</load-on-startup>
| <init-param>
| <param-name>shutdown-on-unload</param-name>
| <param-value>true</param-value>
| </init-param>
| <init-param>
| <param-name>start-scheduler-on-load</param-name>
| <param-value>true</param-value>
| </init-param>
| </servlet>
|
| <!-- BEGIN: RichFaces -->
| <context-param>
| <param-name>org.richfaces.SKIN</param-name>
| <param-value>DEFAULT</param-value>
| </context-param>
|
| <filter>
| <display-name>RichFaces Filter</display-name>
| <filter-name>richfaces</filter-name>
| <filter-class>org.ajax4jsf.Filter</filter-class>
| </filter>
|
| <filter-mapping>
| <filter-name>richfaces</filter-name>
| <servlet-name>Faces Servlet</servlet-name>
| <dispatcher>REQUEST</dispatcher>
| <dispatcher>FORWARD</dispatcher>
| <dispatcher>INCLUDE</dispatcher>
| </filter-mapping>
|
| <!-- END: RichFaces -->
|
| <!-- Seam -->
|
| <listener>
| <listener-class>
| org.jboss.seam.servlet.SeamListener
| </listener-class>
| </listener>
|
| <servlet>
| <servlet-name>Seam Resource Servlet</servlet-name>
| <servlet-class>
| org.jboss.seam.servlet.ResourceServlet
| </servlet-class>
| </servlet>
|
| <servlet-mapping>
| <servlet-name>Seam Resource Servlet</servlet-name>
| <url-pattern>/seam/resource/*</url-pattern>
| </servlet-mapping>
|
| <filter>
| <filter-name>Seam Filter</filter-name>
| <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
| </filter>
|
| <filter-mapping>
| <filter-name>Seam Filter</filter-name>
| <url-pattern>/*</url-pattern>
| </filter-mapping>
|
| <context-param>
| <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
| <param-value>client</param-value>
| </context-param>
|
| <context-param>
| <param-name>facelets.DEVELOPMENT</param-name>
| <param-value>true</param-value>
| </context-param>
|
| <context-param>
| <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
| <param-value>.xhtml</param-value>
| </context-param>
|
| <servlet>
| <servlet-name>Faces Servlet</servlet-name>
| <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
| <load-on-startup>1</load-on-startup>
| </servlet>
|
| <!-- Faces Servlet Mapping -->
|
| <servlet-mapping>
| <servlet-name>Faces Servlet</servlet-name>
| <url-pattern>*.seam</url-pattern>
| </servlet-mapping>
|
| </web-app>
|
ejb-jar.xml
| <?xml version="1.0" encoding="UTF-8"?>
| <ejb-jar xmlns="http://java.sun.com/xml/ns/javaee"
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
| xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/ejb-jar_3_0.xsd"
| version="3.0">
|
| <interceptors>
| <interceptor>
| <interceptor-class>
| org.jboss.seam.ejb.SeamInterceptor
| </interceptor-class>
| </interceptor>
| </interceptors>
|
| <assembly-descriptor>
| <interceptor-binding>
| <ejb-name>*</ejb-name>
| <interceptor-class>
| org.jboss.seam.ejb.SeamInterceptor
| </interceptor-class>
| </interceptor-binding>
| </assembly-descriptor>
|
| </ejb-jar>
|
Here's my login-config.xml:
| <?xml version='1.0'?>
| <!DOCTYPE policy PUBLIC
| "-//JBoss//DTD JBOSS Security Config 3.0//EN"
| "http://www.jboss.org/j2ee/dtd/security_config.dtd">
|
| <policy>
|
| <!-- Used by clients within the application server VM such as mbeans and servlets that access EJBs. -->
| <application-policy name = "client-login">
| <authentication>
| <login-module code = "org.jboss.security.ClientLoginModule"
| flag = "required">
| <!-- Any existing security context will be restored on logout -->
| <module-option name="restore-login-identity">true</module-option>
| <module-option name="multi-threaded">true</module-option>
| </login-module>
| </authentication>
| </application-policy>
|
| <!-- Default JBoss stuff omitted -->
|
| <!-- Security domain for SIO -->
| <application-policy name = "sio">
| <authentication>
| <login-module code = "com.cybercomgroup.security.auth.jboss.SoxDatabaseServerLoginModule" flag = "required">
| <module-option name = "dsJndiName">java:/OracleSio</module-option>
| <module-option name = "rolesQuery">SELECT role_name, 'Roles' FROM principals JOIN roles ON principals.id = roles.id WHERE principals.username=?</module-option>
| <module-option name = "principalsQuery">SELECT Password FROM principals WHERE username=?</module-option>
| </login-module>
| </authentication>
| </application-policy>
|
| </policy>
|
And here the log output from a Quartz job execution:
| 13:41:00,025 INFO [SampleJob] Executing job with description: A sample job doing nothing.
| 13:41:00,025 INFO [Contexts] starting up: org.jboss.seam.web.session
| 13:41:00,025 INFO [Contexts] starting up: org.jboss.seam.security.identity
| 13:41:00,756 INFO [RuleBase] parsing rules: /META-INF/security.drl
| 13:41:05,703 INFO [SoxDatabaseServerLoginModule] started login attempt
| 13:41:06,774 INFO [SoxDatabaseServerLoginModule] principal 'user' is authenticated and active
| 13:41:06,774 INFO [SoxDatabaseServerLoginModule] days since last password change = 65
| 13:41:06,804 INFO [SoxDatabaseServerLoginModule] authentication successful = true
| 13:41:06,894 INFO [TestSeamSecurityServiceBean] Entered 'login' method...
| 13:41:06,894 INFO [SoxDatabaseServerLoginModule] started login attempt
| 13:41:06,945 INFO [SoxDatabaseServerLoginModule] principal 'user' is authenticated and active
| 13:41:06,945 INFO [SoxDatabaseServerLoginModule] days since last password change = 65
| 13:41:06,975 INFO [SoxDatabaseServerLoginModule] authentication successful = true
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Exiting 'login' method.
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] -=STATUS=-
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Caller Principal = user
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Is Identity Security Enabled = true
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Identity Is Logged In = true
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Identity Has Role 'user' = true
| 13:41:08,246 INFO [TestSeamSecurityServiceBean] Identity Has Role 'admin' = false
|
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Entered 'secure' method.
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] -=STATUS=-
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Caller Principal = user
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Is Identity Security Enabled = true
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Identity Is Logged In = false
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Identity Has Role 'user' = false
| 13:41:08,276 INFO [TestSeamSecurityServiceBean] Identity Has Role 'admin' = false
|
As you can see the Identity is populated with the role 'user' when I perform a "manual" login. But between the calls to method 'login' and then method 'secure' the Identity seems to lose its principal information.
And even worse - the @Restrict annotation doesn't kick in at all. Even though the Identity doesn't seem to get its principals between calls the @Restrict annotation should react to it and throw an exception because the Identity doesn't contain the role required to call 'secure'.
Soon I'll have to implement this myself which sucks :-(
Cheers!
Regards, Andreas
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4108471#4108471
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4108471
More information about the jboss-user
mailing list