Announcement Announcement Module
Collapse
No announcement yet.
Security annotations fail in JSF managed bean but not in the service layer Page Title Module
Move Remove Collapse
This topic is closed
X
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Security annotations fail in JSF managed bean but not in the service layer

    I am trying to secure a Spring/JSF -web application with Spring Security (3.0.2), Mojarra 2.0.2, EL 2.2. Everything is working ok in the service layer, but adding even a single security annotation into a managed bean (anywhere in it, not necessarily next to something being executed) causes the whole class to fail (the methods cannot be found).

    I have a managed bean like this:

    Code:
    @Component
    @Scope("request")
    public class LoginBean implements Serializable {
    
    	private static final long serialVersionUID = 1L;
    
    	@Autowired SimpleService simpleService;
    
    	public void dummyMethod() {
    		System.out.println("foo");
    	}
    
    	public void doLogin() {
    		System.out.println("bar");
    	}
    }
    My facelet calls this by:

    Code:
    <h:form id="loginForm">
    	<h:commandButton type="submit" id="login" value="Click me" action="#{loginBean.doLogin}">
    	</h:commandButton>
    </h:form>
    This code works ok: when user clicks the button, the doLogin() is executed succesfully in the bean.

    Now, if I annotate the doLogin() with security declaration like this:

    Code:
    	@RolesAllowed({"ROLE_ADMIN"})
    	public void dummyMethod() {
    		System.out.println("foo");
    	}
    Clicking the button now results in:

    Code:
    javax.el.MethodNotFoundException: /login.xhtml @19,106 action="#{loginBean.doLogin}": Method not found: [email protected]()
    If I remove that annotation and put it for dummyMethod() instead (the method that is not even used), the result is the same.

    However, if I inject this simple service that uses security annotations:

    Code:
    @Service
    public class SimpleService {
    
    	@RolesAllowed({"ROLE_ADMIN"})
    	public String getHelloWorld() {
    		return "hello";
    	}
    }
    ...and call it from the managed bean (via doLogin()), the security works ok and I get just "Access is denied" error.

    What might I be missing here? Why isn't Spring Security working in the managed bean and adding an annotation anywhere there fails the whole class? Any pointers would be appreciated, thanks!

    Below is my setup (find this test project also as attached zip-file):

    applicationContext.xml:

    Code:
    <context:annotation-config/>
    <context:component-scan base-package="my.test" />
    applicationContext-security.xml:

    Code:
    	<global-method-security jsr250-annotations="enabled" secured-annotations="enabled" />
    
    	<http auto-config="true" use-expressions="true">
    		<intercept-url pattern="/**" access="permitAll" />
    	</http>
    
    	<authentication-manager alias="authenticationManager">
    		<authentication-provider>
    			<password-encoder hash="plaintext" />
    			<user-service>
    				<user name="testadmin" password="testadmin" authorities="ROLE_ADMIN, ROLE_USER" />
    				<user name="testuser" password="testuser" authorities="ROLE_USER" />
    			</user-service>
    		</authentication-provider>
    	</authentication-manager>
    faces-config.xml

    Code:
    	<name>jsfConf</name>
    	<application>
    		<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
    	</application>
    web.xml:

    Code:
    	<context-param>
    		<param-name>contextConfigLocation</param-name>
    		<param-value>
    			classpath:applicationContext.xml
    			classpath:applicationContext-security.xml
    		</param-value>
    	</context-param>
    	<listener>
    		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    	</listener>
    
    	<filter>
    		<filter-name>springSecurityFilterChain</filter-name>
    		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    	</filter>
    	<filter-mapping>
    		<filter-name>springSecurityFilterChain</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
        <servlet>
            <servlet-name>faces-servlet</servlet-name>
            <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>faces-servlet</servlet-name>
            <url-pattern>*.jsf</url-pattern>
        </servlet-mapping>
    	<context-param>
    		<param-name>javax.faces.PROJECT_STAGE</param-name>
    		<param-value>Development</param-value>
    	</context-param>
    	<!-- For Tomcat/Jetty -->
        <context-param>
            <param-name>com.sun.faces.expressionFactory</param-name>
            <param-value>com.sun.el.ExpressionFactoryImpl</param-value>
        </context-param>
    Last edited by tuukka.mustonen; Jul 12th, 2010, 04:01 AM. Reason: added more version information

  • #2
    I suggest a forum search as these questions have been answered numerous times before.

    Short answer: FORCE class proxies. Spring uses proxy based aop, yuor managed bean implements an interface hence jdk dynamic proxy instead of class proxy is ued.

    Comment


    • #3
      Thanks for the pointers. I did try to Google and forum search this, but propably didn't have the right keywords.

      After reading about Spring AOP and proxies I got the code working either by removing the interface implementations (Serializable), causing Spring to resort back to CGLIB, or by verbosely forcing the CGLIB proxying, declaring:

      Code:
      <aop:config proxy-target-class="true" />
      Spring documentation notes a few drawbacks of CGLIB approach:
      • final methods cannot be advised, as they cannot be overriden: not a problem as I will propably not need this
      • need cglib JAR-package in classpath: not a problem as this is easy to include
      • constructors are called twice, once for proxy, once for instance: just keep this in mind when creating constructors and I'm okay?

      However, the latest release of CGLIB is a bit old, from 2008. Should I be scared of this? Using CGLIB is also not suggested by Spring documentation. Are there some other drawbacks not mentioned there?

      I suppose using CGLIB is totally ok, as Spring by default fallbacks to using it with classes that don't implement any interfaces?

      Comment


      • #4
        Classproxies can be (more) cumbersome that simpler interface based proxies. Next to that cglib is indeed dated/old and is know to have/cause memory leaks. But in general you shouldn't really notice a thing.

        Comment

        Working...
        X