Results 1 to 4 of 4

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

  1. #1

    Default 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: my.test.jsf.LoginBean@eb1882.doLogin()
    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>
    Attached Files Attached Files
    Last edited by tuukka.mustonen; Jul 12th, 2010 at 04:01 AM. Reason: added more version information

  2. #2
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    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.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

  3. #3

    Default

    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?

  4. #4
    Join Date
    Jun 2006
    Location
    The Netherlands
    Posts
    13,695

    Default

    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.
    Marten Deinum
    Java Consultant / Pragmatist / Open Source Enthousiast / Author


    Pro Spring MVC: With Web Flow
    Conspect

    Have you read the reference guide.
    Use the [ code ] tags, young padawan

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •