I'm trying to implement a REST API for my Spring application. As there are resources which might not be accessed by everyone, I need a security layer.
Within this application I'm already using Spring Security (which works perfectly fine) for securing my web application.
I've added the following http configuration to my spring-security.xml:
<http pattern = "/api/**" use-expressions = "true" disable-url-rewriting = "true">
<http-basic />
</http>
So I would assume that all request that are made to URLs starting with api/ will be secured.
Problem is that I can access my secured methods without any authentications. But if I use a REST client to access it, I receive this error:
message: Full authentication is required to access this resource
description: This request requires HTTP authentication.
I have no idea how to proceed. What is the best way to secure a REST API using Spring Security?
If you use Spring Security in your application, you, probably, already have an <http> section in one of your Spring config files. You can use this section to secure your REST API.
The <http> does not secure anything on its own. You have to add <intercept-url> rules inside it:
<intercept-url pattern="/api/**" access="hasRole('ROLE_USER')" />
There is a tuto on the official site of Spring. It is a little more complicated :
Official Spring Tuto
Just use Spring Security. In <http> tag add: <security:intercept-url pattern="your url" access="hasAnyRole('Your_User_Role1', 'Your_User_Role2')" />.
Or try use annotations. In your spring-config.xml enable security annotations: <security:global-method-security jsr250-annotations="enabled" pre-post-annotations="enabled" secured-annotations="enabled"/>
and in Controller add #PreAuthorize :
#PreAuthorize("hasAnyRole('Your_User_Role1', 'Your_User_Role2')")
#RequestMapping(value = "/address_planing/load_employee_info")
Related
Environment :
Spring 4
Spring Security 4
Spring MVC 4
Hibernate 4
MySQL
Issue :
Below is the requirement :
1)We are developing a Spring REST service for inventory management.
2)This web service will be consumed by .NET client. (or may be mobile device in future)
3)The users of REST service need to be authenticated. The user will use login form displayed by .NET client and if authentication is successfull , he will be
allowed to consume REST API.
4)If authentication fails , user won't be allowed entry into REST service.
Now we have decided to use Basic Authentication for this.
My question is : How do we achieve this using Spring MVC REST and Spring security ?
Below is my first attempt :
application-security.xml
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/usermanagement/authenticate" access="permitAll"/>
<intercept-url pattern="/abhishek/*" access="hasRole('ROLE_ADMIN')"/>
<http-basic/>
<csrf disabled="true"/>
</http>
<authentication-manager>
<authentication-provider>
<user-service>
<user name="Atul" password="12345" authorities="ROLE_ADMIN" />
</user-service>
</authentication-provider>
</authentication-manager>
Following is the flow happening right now :
1)The /authentication API looks up user in Db and returns Http Status code 201(success ) or 401 (failure) accordingly. (this url is unsecured)
2)If success , client puts username/password as Authorization header (which is used in login) and sends this header for future Http requests.
3)Now once next request comes (this is secured), spring security comes into picture and again authentication happens here.
But this time it will be Spring provided.
4)So there are two authentication mechanism are being used .
5)I know I am messing up here , but not able to decide on what is the correct approach to design this.
6)How can client be provided the authentication capability by hooking into Spring security ? He needs to know authentication success/failure
immediately after he logs in.
Please help since I am struggling a lot on this.
I have a Jersey 2 application which I'm trying to secure using Spring Security 4 and HTTP Basic authentication.
The controller class is a Spring bean and is injected into the Jersey Rest Resource. I'm using Spring Pre-Post-annotations on the controller's methods and tried out the following configs:
<security:global-method-security pre-post-annotations="enabled" />
<security:http>
<security:http-basic />
<security:intercept-url pattern="/**" access="hasRole('USER')" />
<security:csrf disabled="true"/>
</security:http>
Problem: Works fine with http-basic authenticated users, the annotated methods (#PreAuthorize("hasRole('USER')")) are secured and only work when the correct credentials are provided. BUT: Anonymous access on other resources under /** is not possible anymore (which is correct, but which I want to have).
Using
<security:intercept-url pattern="/**" access="permitAll" />
instead, every user is handled as anonymous, even though they are providing the correct credentials via HTTP Basic. So even a user with the correct role cannot access the annotated method, a AccessDeniedException is thrown.
What I want: Every user should be allowed to access all resources under "/**". If he's authenticated via HTTTP Basic and has sufficient rights, the annotated method can be called. If he's not authenticated or authorized, an AccessDeniedException should be thrown.
How do I have to configure the Spring security <http> section?
I am trying to setup pre-authentication authorisation using Spring Security, similar to site minder where an external system does the authentication and saves login information in a cookie. However for that to happen I need to redirect to the external URL.
I tried doing it from an implementation of AbstractPreAuthenticatedProcessingFilter but that doesn't work because the HttpServletResponse object is not available.
A more appropriate way seems to be to just add a custom filter that checks for cookie and does the redirection and once the cookies are available then passes the control forward to Spring Security filter. How can I register this custom filter in a Java configuration based Spring Security application? Any help would be appreciated.
The common way is to redirect user to the external authentication interface using an AuthenticationEntryPoint, for example LoginUrlAuthenticationEntryPoint. The entry point is automatically invoked by Spring Security whenever it determines that user needs to get authenticated.
Once user returns back to your application, it should hit a custom filter which extends the AbstractPreAuthenticatedProcessingFilter and extracts the username from your cookie/header/token (after perhaps some validity and integrity checks) in method getPreAuthenticatedPrincipal.
The Spring configuration could be similar to:
<security:http entry-point-ref="externalAuthentication">
<security:custom-filter after="BASIC_AUTH_FILTER" ref="cookieAuthentication"/>
<security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
</security:http>
<bean id="externalAuthentication" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<constructor-arg value="http://server.local/authenticationService"/>
</bean>
<bean id="cookieAuthentication" class="custom class extending org.springframework.security.web.authentication.preauth.AbstractPreAuthenticatedProcessingFilter">
...
</bean>
Is there any easy way in Spring Security to lock down an #Controller to only accept requests from the same (local) host?
I was looking at this post:
Securing servlet URL without using username password authentication
However, I was wondering if that is actual best practice vs. some other security measure.
You can use hasIpAddress expression in the filter security interceptor.
<http use-expressions="true">
<intercept-url pattern="/**" access="hasIpAddress('127.0.0.1/32')"/>
...
</http>
We have an existing jsf/spring application that uses spring security for authentication and authorization.
Now we want to add a restful web service layer, to be used by a mobile client (native android app.) The existing authentication process uses j_spring_security_check and a custom filter.
Can I handle the restful api authentication and authorization within the same context? If yes, how?
One possibility is to create another security configuration for the API realm. Configure it to HTTP BASIC authentication (if that suits you and if API is served over https).
For example:
<http use-expressions="true" pattern="/api/**" realm="API Realm" create-session="stateless">
...
<http-basic />
...
<logout logout-url="/api/logout" />
</http>
EDIT:
As per commenter's comment, I'm correcting my answer: this method unfortunately won't work in Spring Security 3.0 because multiple http elements in Spring Security config were added in 3.1.