Public & Private REST APIs with Spring Security - spring

I have a REST Web Service written with Spring 3.2 that is secured with CAS via Spring Security, and I would like to have it provide an identical private, internal API that could be consumed by other servers on our private network without requiring authentication.
For example, these two endpoints /app/public/people/{id} and /app/private/people/{id} would both map to the same handler but the latter would bypass security and the former would require CAS authentication.
Can I just put both in the same #RequestMapping annotation and specify different security intercepts? For example,
security intercepts:
<security:intercept-url pattern="/private/**" access="permitAll() />
<security:intercept-url pattern="/public/**" access="isAuthenticated()" requires-channel="https"/>
request mapping:
#RequestMapping(value={"/public/people/{id}", "/private/people/{id}"})

What about using IP address to distinguish between access from private and public network? Then you can define just one endpoint for both. For an example, if you’re private network is 192.168.1.0/24, then:
<security:intercept-url pattern="/**"
access="isAuthenticated() or hasIpAddress('192.168.1.0/24')"
requires-channel="https" />
If you have Servlet container behind a reverse proxy, don’t forget to set X-Forwarded-For (or X-Real-IP) header and configure your container to use it; otherwise Spring Security will see IP of the reverse proxy, not a client.

Related

Spring Security 4: Allowing anonymous access and authenticated access on same url

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?

Spring Security custom filter registration with Java config

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>

Support SAML SSO and normal login

I have an application which is accessed by two types of users, internal and external.
I need to authenticate external users using SAML.
I need to authenticate internal users with the normal form-based login. My application need to support both types of users. I use spring security frame work.
Is it possible to support both types of users? if so can you suggest the approach at high level? Thanks.
You can easily enable support for both form and SAML authentication with configuration similar to this:
<http entry-point-ref="authenticationEntryPoint" authentication-manager-ref="authenticationManager">
<intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
<form-login login-page="/login" />
<custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
<custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</http>
Make sure that your AuthenticationManager contains the samlAuthenticationProvider. And of course include other configuration parts from the Spring SAML sample application.
You can then create your custom login page which presents user with username+password fields for form-based authentication and a link/picture (or multiple of them) which initialize authentication with the IDP (by redirecting user to scheme://host:port/saml/login?idp=selectedIdpEntityId).
Your users then decide which one to use - depending on whether they's internal or external.
The part of Spring SAML documentation touching on this subject is in chapter Spring Security integration.

Securing REST API with Spring Security

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")

spring controller accept only local requests

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>

Resources