Spring security/ authorisation levels - java

I am using Spring security within my web application, and I am utilising the 2 standard authorisation levels 'ROLE_USER', and 'ROLE_ADMIN'. Is there any possibility that I can add another level?

Simply add them to your intercept-url tag. For example I have the following configuration:
<security:http auto-config="false" use-expressions="true" access-denied-page="/denied.do"
entry-point-ref="authenticationEntryPoint">
<security:intercept-url pattern="/index.do" access="hasAnyRole('PROGRAM_VIEW', 'PROGRAM_ADMIN')"/>
<security:intercept-url pattern="/**" access="hasAnyRole('PROGRAM_VIEW', 'PROGRAM_ADMIN)"/>
<security:custom-filter ref="authenticationFilter" position="FORM_LOGIN_FILTER"/>
<security:logout invalidate-session="true" logout-success-url="/" logout-url="/logout.do"/>
</security:http>
My additional roles are PROGRAM_VIEW and PROGRAM_ADMIN (I'm not using ROLE_ADMIN and ROLE_USER).
These additional roles are coming from database.

Related

How to use 'Spring EL' in my code?

I am using Spring Security in my project.
In the XML for configuring the security, I want to use 'Spring EL'. Instead of using access="ROLE_ADMIN" I want to use hasRole('ROLE_ADMIN') and isAuthenticated() for the access values mentioned in below code.
For that I used 'use-expressions="true"' in <http> tag. But I am still not getting output. It says that the resource is not available.
The code is currently working properly but I want to use Spring EL.
XML file:
<!-- security configuration -->
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/admin" access="ROLE_ADMIN" />
<security:intercept-url pattern="/welcome" access="ROLE_ADMIN" />
<security:access-denied-handler error-page="/accessdenied403" />
<security:form-login
login-page="/login"
default-target-url="/welcome"
authentication-failure-url="/login?error"
username-parameter="username"
password-parameter="password" />
<security:logout logout-success-url="/login?logout" />
</security:http>
So, how to use Spring EL to set value for access?
does your updated config now looks like
<security:intercept-url pattern="/admin" access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/welcome" access="hasRole('ROLE_ADMIN')" />
Which version of Spring and Spring Security you are using?
What exception you are getting can you set log level to trace and post the log along with any stack trace here?
Are you sure you have all required jar in class path?

Configuring SpringSecurity 3.2.5 Multiple http tag for different login page

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.

Spring logging in with any details

Does anyone know in Spring a way to implement a user-service or authentication provider that will accept any user when logging in?
This is further to my previous question: spring-ws get username & password
I have a basic security setup in my spring-ws project:
<security:http auto-config="true">
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:intercept-url pattern="/*.wsdl" access="ROLE_USER" />
<security:http-basic/>
</security:http>
<security:authentication-manager erase-credentials="false">
<security:authentication-provider user-service-ref="userService">
<security:user-service>
<security:user name="me" password="mypass"
authorities="ROLE_USER" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
I don't want to specify users in the user-service, I want a user with any details to have access, I simply want to make sure the user gives a username and password and to ensure that I can access this from the SecurityContextHolder.
Is it necessary to implement my own user-service or authentication-provider to do this and if so can anyone point in the direction of an example or provide me with one?
Thanks!
You need to provide your own AuthenticationProvider i.e. an implementation of the org.springframework.security.authentication.AuthenticationProvider interface.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="myProvider" />
</security:authentication-manager>
<bean id="myProvider" class="MyProvider"/>
MyProvider can then either delegate to a custom UserDetailsService to set the authorieties (the roles) or set a ROLE_USER directly.
if you change
<security:http auto-config="true">
to
<security:http auto-config="true" use-expressions="true">
you can then set your intercepts from
<security:intercept-url pattern="/**" access="ROLE_USER" />
<security:intercept-url pattern="/*.wsdl" access="ROLE_USER" />
to
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<security:intercept-url pattern="/*.wsdl" access="isAuthenticated()" />
that will allow any authenticated user access to those url patterns.
You need to do the following:
Configure your intercept URL to provide access to any role names. You can do this by doing the following:
<security:http auto-config="true">
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_REMEMBERED" />
<security:intercept-url pattern="/*.wsdl" access="IS_AUTHENTICATED_REMEMBERED" />
<security:http-basic/>
</security:http>
Create your own user service which grants at least one authority to the user for any username and password combination.
Configure spring security to use the service you created.
<bean id="userService" class="com.ek.UserService" />
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userService" />
</authentication-manager>
I hope this gives you the idea on what you need to do. Else, we can work on creating a sample code for you.

How can I disable spring form based login for RESTful endpoints?

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.

Cannot find a jsp view when spring security is applied

I have a java + spring web application and spring security 3.0 is applied to it.
Using the security intercept url I'm trying to apply none filter to a particular view (jobs.jsp) however when I request for that url the request mapping works, but returning the view (ModelAndView as jobs.jsp) does not work.
It gives me an error saying that could not found /WEB-INF/view/jobs.jsp , however the file is right there.
I think the spring security does not allow this resource to be accessed unless authenticated?
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/**" access="hasRole('admin')" />
<security:intercept-url pattern="/resources/static/login.html" filters="none"/>
<security:intercept-url pattern="/resources/static/home.html" filters="none"/>
<security:intercept-url pattern="/home/*" filters="none"/>
<security:intercept-url pattern="/job/all/*" filters="none"/>
<security:intercept-url pattern="/resources/css/*" filters="none"/>
<security:intercept-url pattern="/resources/js/*" filters="none"/>
<security:intercept-url pattern="/resources/images/*" filters="none"/>
<security:form-login login-page ="/resources/static/login.html"
authentication-failure-url="/resources/static/login.html"/>
<security:logout logout-url="/logout"
logout-success-url="/resources/static/home.html"/>
The order of intercept url's caused the problem. This one works.
<security:intercept-url pattern="/job/all/*" access="isAnonymous()"/>
<security:intercept-url pattern="/**" access="hasRole('admin')" />

Categories