Is there any way I can access the intercept-url elements from the security schema programmatically?
// JohanCode:<security:http> <security:intercept-url pattern="/**" access="ROLE_USER" /> <security:/http>
Is there any way I can access the intercept-url elements from the security schema programmatically?
// JohanCode:<security:http> <security:intercept-url pattern="/**" access="ROLE_USER" /> <security:/http>
Are you looking for access to the xml or the objects it creates? If it is the XML look at the spring-security-config project. If it is the objects it creates you can do this by using using the suggestion on the FAQ. Note that this describes how to modify the bean, but you can also just access bean(s) and modify another bean if desired.
Thanks for your reply. The end goal is to extract the pattern and access attributes, preferably by poking the objects maintaining this information, but also by accessing the schema itself if the former fails (does spring/spring-security offer any useful tools to manually parse the schema, or should I look to a domparser?).
I already tried to retrieve some of the beans created by the HttpConfigurationBuilder, such as FilterChainProxy. Although it does give me the roles it doesn't provide the url patterns associated with the role.
As a complement to using the postProcessor, I can probably access all beans by
Code:FilterChainProxy filterChain = appContext.getBean(FilterChainProxy.class);
It may be worth trying to understand why you are trying to do this too (i.e. there may be another way of doing it).
Look at the spring-security-config project which provides the namespace handlers for the security namespace.
Curious that you were able to get the roles and not the URL patterns as I would have thought it would be the other way around. A mapping of the url to the role can be found in the FilterSecurityInterceptor's FilterInvocationSecurityMetadataSource (i.e. DefaultFilterInvocationSecurityMetadataSource). Note that the implementation details change quite a bit at 3.1
This along with autowiring can work if the bean you are trying to access is not an anonymous inner bean.
There usually is. I want to use rolemapping for authority, but also to determine visibility. I.e., a user with ROLE_USER should only be able to see in a rendered html-menu the jsp pages he is authorized to see. I figuered I would reuse the role mapping already in place to avoid duplicate configurations.
Interesting, this would be beneficial in a situation were I must parse the schema.
I'm currently looking at 3.0. Interestingly FilterSecurityInterceptor doesn't seem to provide a complete mapping. The FilterInvocationSecurityMetadataSource seems to contain all available roles though.
The other option is I see next to parsing the XML manually, is to actually use something like the PropertyPlaceholderConfigurer to populate the intercept-url elements, and access the configurer programmatically instead. Neither approach seems perfect thoughBtw, I must say I appreciate the effort you put in to help me on a weekend and everything.
[EDIT]: Well, it seems DefaultFilterInvocationSecurityMetadataSource contains both role and url mapping, but only exposes the former. One really hack'ish option here would be to access the private member variable requestMap using reflection. Separation of concerns can surely be a b**** some times.
To further increase the ugliness, what we actually get is Map<RequestMatcher, Collection<ConfigAttribute>>, where we must again use some magic to extract the url-patterns. *sigh*. I'm starting to feel this approach is far inferior .... to most anything.Code:for (FilterChainProxy filterChain : ctx.getBeansOfType(FilterChainProxy.class).values()) { for (Map.Entry<String, List<Filter>> entry : filterChain.getFilterChainMap().entrySet()) { for (Filter filter : entry.getValue()) { if (filter instanceof FilterSecurityInterceptor) { FilterSecurityInterceptor interceptor = (FilterSecurityInterceptor) filter; // hack away to extract the private variable requestmap } } } }
Last edited by Toxic; Jan 29th, 2011 at 12:32 PM.
There are a few options for this. The first is using the provided authorize jsp tag. The second is to @Autowire an instance of WebInvocationPrivilegeEvaluator.
Good thinking, the WebInvocationPrivilegeEvaluator will suffice to meet my end goal. The downside is that I must perform the matching at request-time rather than building up the url-to-role structure in advance. Not too bad of a tradeoff, at least not for the price of avoiding hacking around the framework too much. Thanks for your suggestion.
True in the general sence, but in my case it could be optimized further by knowing all the mappings in advance.
Say I have a list of pages {"index.html", "admin.html",.... } which is known at compile-time. This list is delivered to the view (using model map) which generates a HTML menu from it.
However, each time I need to render a page I must use the WebInvocationPrivilegeEvaluator to extract only those pages from the list that the user is actually authorized to see, and then render the menu based on those pages.
Instead, I would've prefered to retrieve all pages accessible by the role of the current user directly:
Code:@Controller public class AController { // Maps the list of pages each role is authorized to see Map<String, List<String>> roleToPages; @RequestMapping(..) public void controllerRoutine(Map model) { model.put("menu_pages, roleToPages.get(CURRENT_ROLE)); } }
Last edited by Toxic; Jan 30th, 2011 at 06:59 AM.
Ok, I see. It seems that you are assuming a single role for the user, is that correct?
You should still be able to do that. If you know the pages and all the possible roles, then you can just call the WebInvocationPrivilegeEvaluator on initialization. Create a dummy authentication object with each role:
or something similar.Code:Map<String, List<String>> roleToPages = ...; WebInvocationPrivilegeEvaluator wipe = ... List<String> possibleRoles = ... List<String> pages = ... for (String role : possibleRoles) { for (String page : pages) { if (wipe.isAllowed(page, new DummyAuthentication(role))) { List<String> rolePages = roleToPages.get(role); if (rolePages == null) { rolesPages = new ArrayList<String>(); roleToPages.put(role, rolePages); } rolesPages.add(page); } } }