I am using Spring Security 3 in Struts 2 + Spring IOC project.
I have used Custom Filter, Authentication Provider etc. in my Project.
You can see my security.xml here
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <global-method-security pre-post-annotations="enabled"> <expression-handler ref="expressionHandler" /> </global-method-security> <beans:bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler" > <beans:property name="permissionEvaluator" ref="customPermissionEvaluator" /> </beans:bean> <beans:bean class="code.permission.MyCustomPermissionEvaluator" id="customPermissionEvaluator" /> <!-- User Login --> <http auto-config="true" use-expressions="true" pattern="/user/*" > <intercept-url pattern="/index.jsp" access="permitAll"/> <intercept-url pattern="/user/showLoginPage.action" access="permitAll"/> <intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/> <intercept-url pattern="/user/showSecondUserPage" access="hasRole('ROLE_USER')"/> <intercept-url pattern="/user/showThirdUserPage" access="hasRole('ROLE_VISIT')"/> <intercept-url pattern="/user/showFirstPage" access="hasRole('ROLE_USER') or hasRole('ROLE_VISIT')"/> <form-login login-page="/user/showLoginPage.action" /> <logout invalidate-session="true" logout-success-url="/" logout-url="/user/j_spring_security_logout"/> <access-denied-handler ref="myAccessDeniedHandler" /> <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilter"/> </http> <beans:bean id="myAccessDeniedHandler" class="code.security.MyAccessDeniedHandler" /> <beans:bean id="myApplicationFilter" class="code.security.MyApplicationFilter"> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="authenticationFailureHandler" ref="failureHandler"/> <beans:property name="authenticationSuccessHandler" ref="successHandler"/> </beans:bean> <beans:bean id="successHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <beans:property name="defaultTargetUrl" value="/user/showFirstPage"> </beans:property> </beans:bean> <beans:bean id="failureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/user/showLoginPage.action?login_error=1"/> </beans:bean> <beans:bean id= "myUserDetailServiceImpl" class="code.security.MyUserDetailServiceImpl"> </beans:bean> <beans:bean id="myAuthenticationProvider" class="code.security.MyAuthenticationProvider"> <beans:property name="userDetailsService" ref="myUserDetailServiceImpl"/> </beans:bean> <!-- User Login Ends --> <!-- Admin Login --> <http auto-config="true" use-expressions="true" pattern="/admin/*" > <intercept-url pattern="/index.jsp" access="permitAll"/> <intercept-url pattern="/admin/showSecondLogin" access="permitAll"/> <intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/> <form-login login-page="/admin/showSecondLogin"/> <logout invalidate-session="true" logout-success-url="/" logout-url="/admin/j_spring_security_logout"/> <access-denied-handler ref="myAccessDeniedHandlerForAdmin" /> <custom-filter before="FORM_LOGIN_FILTER" ref="myApplicationFilterForAdmin"/> </http> <beans:bean id="myAccessDeniedHandlerForAdmin" class="code.security.admin.MyAccessDeniedHandlerForAdmin" /> <beans:bean id="myApplicationFilterForAdmin" class="code.security.admin.MyApplicationFilterForAdmin"> <beans:property name="authenticationManager" ref="authenticationManager"/> <beans:property name="authenticationFailureHandler" ref="failureHandlerForAdmin"/> <beans:property name="authenticationSuccessHandler" ref="successHandlerForAdmin"/> </beans:bean> <beans:bean id="successHandlerForAdmin" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> </beans:bean> <beans:bean id="failureHandlerForAdmin" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <beans:property name="defaultFailureUrl" value="/admin/showSecondLogin?login_error=1"/> </beans:bean> <authentication-manager alias="authenticationManager"> <authentication-provider ref="myAuthenticationProviderForAdmin" /> <authentication-provider ref="myAuthenticationProvider" /> </authentication-manager> <beans:bean id="myAuthenticationProviderForAdmin" class="code.security.admin.MyAuthenticationProviderForAdmin"> <beans:property name="userDetailsService" ref="userDetailsServiceForAdmin"/> </beans:bean> <beans:bean id= "userDetailsServiceForAdmin" class="code.security.admin.MyUserDetailsServiceForAdminImpl"> </beans:bean> <!-- Admin Login Ends --> <beans:bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <beans:property name="basenames"> <beans:list> <beans:value>code/security/SecurityMessages</beans:value> </beans:list> </beans:property> </beans:bean>
Uptill now you can see, url-pattern I have mentioned is hard coded. I wanted to know if there is a way to create new ROLES and PERMISSIONS dynamically, not hard coded.
Like creating new roles and permissions and saving them to database and then accessing from database. I have searched on net, but I am not able to find out how to add new entries to code.
hasRole, hasAnyRole. These expressions are responsible for defining the access control or authorization to specific URLs and methods in our application: @Override protected void configure(final HttpSecurity http) throws Exception { ... . antMatchers("/auth/admin/*").
Domain-based Dynamic Access Control enables administrators to apply access-control permissions and restrictions based on well-defined rules that can include the sensitivity of the resources, the job or role of the user, and the configuration of the device that is used to access these resources.
So these are at least two questions:
I will not answer this in great detail, because I believe this theme was discussed often enough.
The easiest way would be to store the complete user information (login, password and roles) in a database (3 Tables: User, Roles, User2Roles) and use the JdbcDetailService
. You can configure the two SQL Statements (for authentication and for granting the roles) very nicely in your xml configuration.
But then the user needs to logout and login to get these new Roles. If this is not acceptable, you must also manipulate the Roles of the current logged in user. They are stored in the users session. I guess the easiest way to do that is to add a filter in the spring security filter chain that updates the Roles for every request, if they need to be changed.
Here you have at last two ways:
FilterSecurityInterceptor
and updating the securityMetadataSource
, the needed Roles should be stored there. At least you must manipulate the output of the method DefaultFilterInvocationSecurityMetadataSource#lookupAttributes(String url, String method)
access
attribute instead of access="hasRole('ROLE_USER')"
. Example: access="isAllowdForUserPages1To3"
. Of course you must create that method. This is called a "custom SpEL expression handler" (If you have the Spring Security 3 Book it's around page 210. Wish they had chapter numbers!). So what you need to do now is to subclass WebSecurityExpressionRoot
and introduce a new method isAllowdForUserPages1To3
. Then you need to subclass DefaultWebSecurityExpressionHandler
and modify the createEvaluationContext
method so that its first request StandartEvaluationContext
calls super (you need to cast the result to StandartEvaluationContext
). Then, replace the rootObject
in the StandartEvaluationContext
using your new CustomWebSecurityExpressionRoot
implementation. That's the hard part! Then, you need to replace the expressionHandler
attribute of the expressionVoter
(WebExpressionVoter
) in the xml configuration with your new subclassed DefaultWebSecurityExpressionHandler
. (This sucks because you first need to write a lot of security configuration explicity as you can't access them directly from the security namespace.)I would like to supplement Ralph's response about creating custom SpEL expression. His explanations helped very much on my attempt to find the right way to do this, but i think that they need to be extended.
Here is a way on how to create custom SpEL expression:
1) Create custom subclass of WebSecurityExpressionRoot class. In this subclass create a new method which you will use in expression. For example:
public class CustomWebSecurityExpressionRoot extends WebSecurityExpressionRoot { public CustomWebSecurityExpressionRoot(Authentication a, FilterInvocation fi) { super(a, fi); } public boolean yourCustomMethod() { boolean calculatedValue = ...; return calculatedValue; } }
2) Create custom subclass of DefaultWebSecurityExpressionHandler class and override method createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) (not createEvaluationContext(...)) in it to return your CustomWebSecurityExpressionRoot instance. For example:
@Component(value="customExpressionHandler") public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler { @Override protected SecurityExpressionRoot createSecurityExpressionRoot( Authentication authentication, FilterInvocation fi) { WebSecurityExpressionRoot expressionRoot = new CustomWebSecurityExpressionRoot(authentication, fi); return expressionRoot; }}
3) Define in your spring-security.xml the reference to your expression handler bean
<security:http access-denied-page="/error403.jsp" use-expressions="true" auto-config="false"> ... <security:expression-handler ref="customExpressionHandler"/> </security:http>
After this, you can use your own custom expression instead of the standard one:
<security:authorize access="yourCustomMethod()">
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With