In Spring Security:
<sec:http pattern="/api/**" create-session="never"
entry-point-ref="oauthAuthenticationEntryPoint"
access-decision-manager-ref="accessDecisionManager"
xmlns="http://www.springframework.org/schema/security">
<anonymous enabled="false" />
<intercept-url pattern="/api/**" access="ROLE_ADMIN" />
<custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</sec:http>
in this line <intercept-url pattern="/api/**" access="ROLE_ADMIN" />
What is difference meaning if I write:
<intercept-url pattern="/api/**" access="hasRole('ROLE_ADMIN')" />
or:
<intercept-url pattern="/api/**" access="hasAnyRole('ROLE_ADMIN')" />
As Spring Security documentation states:
hasRole([role]): Returns true if the current principal has the
specified role
hasAnyRole([role1,role2]): Returns true if the current principal has any of the supplied roles (given as a comma-separated list of strings).
Also, on access attribute, documentation states:
access: Lists the access attributes which will be stored in the
FilterInvocationSecurityMetadataSource for the defined URL
pattern/method combination. This should be a comma-separated list of
the security configuration attributes (such as role names).
But in your case, you're passing a single element list to the hasAnyRole, So:
access="ROLE_ADMIN" Vs access="hasAnyRole('ROLE_ADMIN')
hasRole('ROLE_ADMIN') and hasAnyRole('ROLE_ADMIN') are identical and both means that the current principal should have the ROLE_ADMIN authority.
(a "principal" generally means a user, device or some other system which can perform an action in your application).
Related
Code was working fine now have replaced the below line in security.xml to provide role based security, but getting access denied http status-403
Replaced
<intercept-url pattern="/inputcreate*" access="isAuthenticated()" />
with
<intercept-url pattern="/inputcreate*" access="hasAnyRole('admin','user')" />
spring-security.xml
<http use-expressions="true" auto-config="true">
<!-- <intercept-url pattern="/inputcreate*" access="isAuthenticated()" /> -->
<intercept-url pattern="/inputcreate*" access="hasAnyRole('admin','user')" />
<form-login login-page="/login.html" default-target-url="/inputcreate.html"
authentication-failure-url="/login.html" username-parameter="j_username"
password-parameter="j_password" login-processing-url="/j_spring_security_check" />
<logout logout-url="/j_spring_security_logout"
logout-success-url="/index.html" />
</http>
just Replaced
<intercept-url pattern="/inputcreate*" access="hasAnyRole('admin','user')" />
with
<intercept-url pattern="/inputcreate*" access="hasAnyRole('ROLE_ADMIN','ROLE_USER')" />
After googling 3-4 hour, made this above change
This worked for me!!!!
In the Spring documentation it has been given here, to prefix role
public void setRolePrefix(String rolePrefix)
Allows a default role prefix to be specified. If this is set to a non-empty value, then it is automatically prepended to any roles read in from the db.
This may for example be used to add the ROLE_ prefix expected to exist in role names (by default) by some other Spring Security classes, in the case that the prefix is not already present in the db.
Parameters:
rolePrefix - the new prefix
I am currently exploring the possibility of having two separate log in page for different users.
I am now able to to set most urls according to the two pages. However, i am now having a configuration issue for the entry-point-ref and CONCURRENT_SESSION_FILTER.
As for this security version, ( LoginUrlAuthenticationEntryPoint.class - loginFormUrl ConcurrentSessionFilter.class - expiredUrl ) the setter method for the property are deprecated, left with the constructor injection that is set in the xml.
So I am thinking of two ways to solve this problem:
1. Override or Inject the two classes and change the url base on condition ?
2. Write a seperate http tag that reads in the specific url pattern and apply the configurations accordingly.
Thanks in advance. The working code is below:
<security:global-method-security pre-post-annotations="enabled" />
<security:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/*" requires-channel="any"/>
<security:intercept-url pattern="/**/*.json*" requires-channel="any"/>
<security:intercept-url pattern="/**/dashboard/**" requires-channel="https"/>
<security:intercept-url pattern="/**/rest/**" requires-channel="https"/>
<security:intercept-url pattern="/**/cart/**" requires-channel="https"/>
<security:intercept-url pattern="/**/customer/**" requires-channel="any"/>
<security:intercept-url pattern="/**/api/**" requires-channel="any"/>
<security:intercept-url pattern="/api/**" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<security:custom-filter before="FORM_LOGIN_FILTER" ref="customDeveloperPasswordAutenticationFilter"/>
<security:custom-filter after="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout" success-handler-ref="customLogoutSuccessHandler"/>
</security:http>
The code i'm trying to achieve is:
<security:global-method-security pre-post-annotations="enabled" />
<security:http auto-config="false" use-expressions="true" entry-point-ref="loginUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/*" requires-channel="any"/>
<security:intercept-url pattern="/**/*.json*" requires-channel="any"/>
<security:intercept-url pattern="/**/dashboard/**" requires-channel="https"/>
<security:intercept-url pattern="/**/cart/**" requires-channel="https"/>
<security:intercept-url pattern="/**/customer/**" requires-channel="any"/>
<security:intercept-url pattern="/**/api/**" requires-channel="any"/>
<security:intercept-url pattern="/api/**" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/dashboard/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="concurrencyFilter" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout_user" success-handler-ref="customLogoutSuccessHandlerUser"/>
</security:http>
<security:http auto-config="false" use-expressions="true" entry-point-ref="restUrlAuthenticationEntryPoint">
<security:intercept-url pattern="/**/rest/**" requires-channel="https"/>
<security:intercept-url pattern="/rest/signin" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/rest/signup" requires-channel="https" access="permitAll"/>
<security:intercept-url pattern="/denied" access="permitAll"/>
<security:access-denied-handler error-page="/denied"/>
<security:custom-filter position="CONCURRENT_SESSION_FILTER" ref="restConcurrencyFilter" />
<security:custom-filter position="FORM_LOGIN_FILTER" ref="customDeveloperPasswordAutenticationFilter"/>
<security:logout logout-url="/j_spring_security_logout_developer" success-handler-ref="customLogoutSuccessHandlerDeveloper"/>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="customUserDetailsService">
<security:password-encoder ref="customPasswordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<bean id='customUserDetailsService' class='sg.oddlefnb.common.security.CustomUserDetailServiceImpl'>
<!-- use to DAO to switch for different condition -->
<property name='userDao' ref='userDao' />
<property name='developerDao' ref='developerDao' />
</bean>
However, this could not run.. Any advice?
You should not try to do it that way, it is not the spring security way. Maybe you could succeed (even if I doubt you can ...) but it will be hard to write and to maintain.
You can have multiple <http> blocs in a single config, but it is when you want to apply different filter chains to different URL blocs.
You may have different login pages (and also different authentication methods : login page, basic authentication, ldap, custom ...). But the spring way is to separate authentication and access control. So when a user is authenticated, his authentication is stored in session and will be used for all following requests (until end of session). In your example if someone asks for a user page before authentication, if will be redirected to user login page, authenticated as a user and he will get its page. But if he asks for a developper page on next request, spring security will find a valid authentication in session a permitAll as access rule and will allow the page ... which I assume is not what you want !
The spring security way to do what you want is to use roles. The simple way is to have one single page, and store the roles in a database (or in a in-memory store for developpement and tests). You the use the roles in the access rules. You will find many examples for that in Spring Security Reference Manual.
Edit per OP comment :
It is rather uncommon to assign roles depending on used login page, but it can be done. You simply need to define two different AuthenticationManager beans, and explicitely assign them to the two different <http> blocs where you declare your login pages. In one you explicitely affect a ROLE_USER granted authority, and in the other a ROLE_DEVELOPPER one. You may do it by hand by subclassing a ProviderManager and using same AuthenticationProviderS in both, or you can use plain ProviderManager and customize the UserDetailsService beans of the AuthenticationProviderS. If you showed your current <authentication-manager> bloc, I could easily propose a full solution.
Once you have different roles, it is easy to put all access control in one single <http> bloc, with all the <security:intercept-url .../> inside it.
I have spring-security configured using basic and form based authentication as per auto-config='true'.
I would like the endpoints under /api/** to NOT use form based security. Other endpoints outside of /api/** should use form based login. I would like a 401 response sent to any call for these endpoints who did not provide credentials under /api/**.
UPDATE: Thanks to Luke Taylor's comment below I have come up with the following solution.
NOTE: This technique can only be applied as of spring-security 3.1.
First I single out /api/**. We never create a session though use one if available, this is handled by create-session="never" and the use of <session-management/>.
<http pattern="/api/**" create-session="never" use-expressions="true">
<http-basic />
<session-management />
<intercept-url pattern="/api/**" access="hasRole('API_ACCESS')"/>
</http>
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/" access="permitAll"/>
<intercept-url pattern="/**" access="isAuthenticated()"/>
</http>
With Spring Security 3.1, your best option is to split the restful and non-restful parts of your application into separate filter chains by using two separate <http> elements. The restful API chain can then be configured to be stateless and use basic authentication, while the default chain can use a normal form-login configuration.
You would then have something like:
<http pattern="/api/**" create-session="stateless">
<intercept-url pattern="/api/**" access="ROLE_API_USER" />
<http-basic />
</http>
<!-- No pattern attribute, so defaults to matching any request -->
<http>
<intercept-url pattern="/**" access="ROLE_USER" />
<form-login />
</http>
The chain definitions must be ordered from most specific pattern to most general, so the default chain comes last.
I'm trying to configure spring MVC to not authenticate any pages that have no authentication (enable the use of ROLE_ANONYMOUS as explicitly required for all pages).
But I get this message in the debug logs:
o.s.s.w.a.i.FilterSecurityInterceptor - Public object - authentication not attempted
The FilterSecurityInterceptor is added by the namespace. And I think I need to setRejectPublicInvocations on the filter to disable this.
But I don't see any way to do this through the http namespace. Do I have to abandon using the http namespace entirely just to accomplish this?
In my case I basically did this.
and it's working for anon users.
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/css/**" filters="none" />
<intercept-url pattern="/js/**" filters="none" />
<intercept-url pattern="/img/**" filters="none" />
<intercept-url pattern="/loginform.*" filters="none" />
<intercept-url pattern="/topic/addtopic**"
access="hasAnyRole('USER_ROLE','ADMIN_ROLE','OPER_ROLE')" />
<intercept-url pattern="/user/**"
access="hasAnyRole('USER_ROLE','ADMIN_ROLE','OPER_ROLE')" />
<intercept-url pattern="/admin/**" access="hasRole('ADMIN_ROLE')" />
<intercept-url pattern="/cadastro.*" filters="none" />
<form-login login-page="/loginform.html"
authentication-failure-url="/loginform.html?error=invalido" />
</http>
What is the difference between ROLE_USER and ROLE_ANONYMOUS in a Spring intercept url configuration such as the example below?
<http auto-config="false" access-decision-manager-ref="accessDecisionManager"
use-expressions="true">
<intercept-url pattern="/admin/**" access="hasRole('ROLE_ANONYMOUS')"
requires-channel="http" />
<intercept-url pattern="/login/**" access="hasRole('ROLE_ANONYMOUS')"
requires-channel="${application.secureChannel}" />
<intercept-url pattern="/error/**" access="hasRole('ROLE_ANONYMOUS')"
requires-channel="http" />
<intercept-url pattern="/register/**" access="hasRole('ROLE_ANONYMOUS')"
requires-channel="${application.secureChannel}" />
<intercept-url pattern="/" access="hasRole('ROLE_ANONYMOUS')"
requires-channel="http" />
<intercept-url pattern="/**" access="hasRole('ROLE_USER')"
requires-channel="http" />
<form-login login-page="/login" login-processing-url="/login/submit"
authentication-failure-url="/login/error" />
<logout logout-url="/logout" />
</http>
ROLE_ANONYMOUS is the default role assigned to an unauthenticated (anonymous) user when a configuration uses Spring Security's "anonymous authentication" filter . This is enabled by default. However, it is probably clearer if you use the expression isAnonymous() instead, which has the same meaning.
ROLE_USER has no meaning unless you assign this role to your users when they are authenticated (you are in charge of loading the roles (authorities) for an authenticated user). It isn't a name that is built in to Spring Security's infrastructure. In the given example, presumably that role is assigned to an authenticated user.
ROLE_ANONYMOUS has no user credentials, ROLE_USER has user credentials... has been authenticated.
this is my interpretation based on the configuration provided