Thymeleaf and Spring Security

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Thymeleaf and Spring Security

CWayman
Hi all,

I have downloaded JAppStart as a basis for starting a spring MVC project on google app engine, which I am hoping to extend into a thymeleaf app.

It uses Jsps at the minute and also spring security in taglib form aswell as in the spring configuration.  Now the spring configuration I know will be fine with thymeleaf but I am wondering about the spring security taglib functions.

Mentioned in the article about the football app it talks about writing property and attribute resolvers.  I could write my own (forgive the JEE term) taglib to wrap the functions I would want to call in the xhtml page to conditionally render some portions of the page. i.e. Admin functions.

Or alternatively I could have my own bean security wrapper bean wired into the page and then use a th:unless to conditionally render it based on boolean responses from my methods?

A third option would possibly be to wire in the security context directly into the controller and then access it's methods?

Would anyone have any preference with which one to go with?

Functions I would want to replicate are operations like:
 - isAnonymous()
 - isAuthenticated()
 - hasRole(role)

So nothing too advanced in terms of functionality, the main spring security work would be behind the scenes securing URLs and methods etc.

Thanks,
Craig.
Reply | Threaded
Open this post in threaded view
|

Re: Thymeleaf and Spring Security

Zemi
Administrator
Ok, that's an interesting question.

I use your "second option". I have one bean with my security methods and I set it in every template via an Spring InterceptorHandler:


        public class ImplicitObjectsInterceptor extends HandlerInterceptorAdapter {

            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response,
                     Object handler, ModelAndView modelAndView) throws Exception {
                if (modelAndView != null && !modelAndView.getViewName().startsWith("redirect:")) {
                    modelAndView.getModel().put("roles", new UserRoles(request));
                }
            }

        }


my UserRoles() class has methods like isAdministrator(), isManager(), matching my business logic requirements, which could be invoked in every template as follows:


       <div th:if="${roles.manager}"> .... </div> 


However, I liked your "third option" and I have just tried the following implementation via an Spring InterceptorHandler:


        public class ImplicitObjectsInterceptor extends HandlerInterceptorAdapter {

            @Override
            public void postHandle(HttpServletRequest request, HttpServletResponse response,
                     Object handler, ModelAndView modelAndView) throws Exception {
                if (modelAndView != null && !modelAndView.getViewName().startsWith("redirect:")) {
                    FilterInvocation filterInvocation = new FilterInvocation(request, response, new FilterChain() {
                        public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
                            throw new UnsupportedOperationException();
                        }
                    });
                    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
                    WebSecurityExpressionRoot sec = new WebSecurityExpressionRoot(authentication, filterInvocation);
                    sec.setTrustResolver(new AuthenticationTrustResolverImpl());
                    modelAndView.getModel().put("sec", sec);
                }
            }

        }


Doing that could invoke all methods of SecurityExpressionRoot from every template as follows:


       <div th:if="${sec.isAnonymous()}"> .... </div> 
       <div th:if="${sec.hasRole('ADMIN')}"> .... </div> 


Note: you could have noticed the awful UnsupportedOperationException above. That is directly copied from Spring's org.springframework.security.taglibs.authz.AbstractAuthorizeTag source code.

Reply | Threaded
Open this post in threaded view
|

Re: Thymeleaf and Spring Security

CWayman
Zemi you are quickly becoming a legend on these forums.  Thank you for your responses (and the code examples!).

Time to set the thymeleaf train into full speed ahead! :)

Craig.
Reply | Threaded
Open this post in threaded view
|

Re: Thymeleaf and Spring Security

danielfernandez
Administrator
In reply to this post by Zemi
Zemi, BIG THANKS for this. You are doing a fantastic job at this forum, especially with your latest answers.

Your solution looks perfectly elegant to me, I have nothing to add. I hope this solves Craig's scenario.

Regards,
Daniel.
Reply | Threaded
Open this post in threaded view
|

Re: Thymeleaf and Spring Security

benr
In reply to this post by Zemi
Zemi wrote
public class ImplicitObjectsInterceptor extends HandlerInterceptorAdapter {

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
            Object handler, ModelAndView modelAndView) throws Exception {
        if (modelAndView != null && !modelAndView.getViewName().startsWith("redirect:")) {
            FilterInvocation filterInvocation = new FilterInvocation(request, response, new FilterChain() {
                public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
                    throw new UnsupportedOperationException();
                }
            });
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            WebSecurityExpressionRoot sec = new WebSecurityExpressionRoot(authentication, filterInvocation);
            sec.setTrustResolver(new AuthenticationTrustResolverImpl());
            modelAndView.getModel().put("sec", sec);
        }
    }
}

In certain circumstances, I get an NPE on the WebSecurityExpressionRoot line because variable authentication is null. I've trawled Google for reasons for this, but none seems to apply.

It is particularly common when an error page is generated, e.g. for a 404 Page Not Found request. What could be causing this?

Reply | Threaded
Open this post in threaded view
|

Re: Thymeleaf and Spring Security

benr
I found the source of the problem:

http://forum.springsource.org/showthread.php?116076