Spring MVC - allowing requests from localhost only to specific controller - java

I have a specific controller (among many other controllers).
I would like to allow requests to this controller that are being invoked from localhost only.
Whats the best way to do this?
here is the controller:
#Controller
public class LocalProvider {
#RequestMapping(value = "/someURL", method = RequestMethod.POST)
#ResponseBody
public responseDTO doSomethingForLocalRequest(#RequestBody ReqDTO reqDTO ) {
//do something
}
EDIT :
Succesffuly achieved that by adding the following to spring security.xml:
<intercept-url pattern="/someURL/*" access="hasIpAddress('127.0.0.1')" />

I would create a custom annotation #LocalhostOnly and a MVC interceptor that would check if handler method is annotated with #LocalhostOnly and in that case check if remote ip address fetched from the HttpServletRequest.getRemoteAddr() is indeed localhost.
If you're using spring security then, as NimChimpsky suggested, it might be better plug in remote ip check into that. You could define a custom permission evaluator that checks remote ip address.
You could also use servlet filter and do the localhost check there for a specific URL (e.g. /someURL**).
Lastly, be aware that if you'll be running the application behind a reverse proxy at some point, all the requests will look like they arrived from localhost (that is, if reverse proxy is installed at the same host). In that case you'll need to pick up the ip address from X-Forwarded-For header.
EDIT
Spring security actually has ip checking expression hasIpAddress('127.0.0.1') so NimChimpsky's answer is probably the best way to go.

spring-security provides #PreAuthorize annotation that can be used on type or method so an alternative to <intercept-url>
can be #PreAuthorize("hasIpAddress('127.0.0.1')")

To restrict access to your whole webserveryou could use
<Connector port="8080" address="127.0.0.1" maxHttpHeaderSize="8192"
In server xml of tomcat (or similar in a different app server).
For one app use add allow="localhost" to the context :
<Context>
<Valve className="org.apache.catalina.valves.RemoteHostValve" allow="localhost"/>
</Context>
But for specific controller methods, you'll be best using spring security.

Solution is to use the following expression:
#PreAuthorize("#request.getRemoteAddr().equals(#request.getLocalAddr())")
As first comment suggested, Failed to evaluate expression error will show using #request if #P("request") HttpServletRequest parameter is missing.
Full solution:
#PreAuthorize("#request.getRemoteAddr().equals(#request.getLocalAddr())")
#PostMapping("/doSomething")
public void myMethod(#P("request") HttpServletRequest request) {
...
}

Related

CAS redirect to URL on succesfull login

Here a solution is described to handle redirects to a custom URL based on a condition via use of AccessStrategy.
This however is part of the unauthorized login logical flow therefore results into a still not-logged in user arriving at the end url we redirect to. (via getUnauthorizedUrl)
If we want to redirect the user based on a condition, say via injecting an action to the webflow, how can we manipulate the return URL to be changed into a custom one?
WebUtils.getService(requestContext) include getters of the source/originalUrl but no obvious way to set/manipulate said value through an action bean.
p.s. Currently using CAS version 5.3.x
Responses for normal web applications from CAS are built using WebApplicationServiceResponseBuilder.
If you examine this block you will find that the final response is built using WebApplicationServiceResponseBuilder bean. It is only created conditionally, if an existing bean is not already found in the context by the same name. So to provide your own, you just need to register a bean with the same name using your own #Configuration class.
#Bean
public ResponseBuilder<WebApplicationService> webApplicationServiceResponseBuilder() {
return new MyOwnWebApplicationServiceResponseBuilder(...);
}
...and then proceed to design your own MyOwnWebApplicationServiceResponseBuilder, perhaps even by extending WebApplicationServiceResponseBuilder and overriding what you need where necessary to build the final redirect logic conditionally.
To learn about how #Configuration classes work in general, you can:
Review this post
or this post
or consult the documentation for Spring and/or Spring Boot.

how can i convince spring 4.2 to pass OPTIONS request through to the controller

we have are using spring mvc with #RestController annotations on our controllers, and we're handling authorization in the controller. we use the same code to set the allowed methods in responses to CORS pre-flight request. to achieve this, we have:
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
in the configuration of the dispatcher servlet, and then we have:
#RequestMapping(value="/some/collections", method=RequestMethod.OPTIONS)
public void collectionOptions(
HttpServletRequest req,
HttpServletResponse res) {
List<RequestMethod> methods = new ArrayList<>();
// check actual permissions, add the appropriate methods
CORS.setAllowedMethodHeaders(res,methods);
}
we also have an interceptor that do basic checks on CORS pre-flight to see if the origin can possibly have any permissions at all.
we do it like this mostly because permissions for some requests actually depend on #RequestParams, i.e.:
OPTIONS /api/collections?userId=122
might be allowed if you have administrative privileges OR you actually the user with the ID 122. also, we have API keys, so
OPTIONS /api/collections?userId=122&apiKey=ABC
might be OK for one origin, but not for another one.
this works fine, but spring 4.2 now decides wether or not it handles an OPTIONS request, via a call to:
CorsUtils.isCorsRequest(request);
in AbstractHandlerMapping and then returns
HandlerInterceptor[] interceptors = chain.getInterceptors();
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
instead of the HandlerMethod ...
what we would need is some way to tell spring to let the controller handle OPTIONS requests, no matter what preflight request handlers are present.
We don't seem to be able to find a point where we can EITHER tell the built-in CORS handling to be quiet or to configure some subclass somewhere that would allow us to bypass the newly added code in:
AbstractHandlerMapping.getHandler(HSR request)
Is this in any way possible? Wouldn't it be nice for a feature like this to be quiet until I actively enable it (through WebMvcConfigurerAdapter or via those #CrossOrigin annotations)?
-------- EDIT -------------
the HTTP standard says the following about the OPTIONS method:
The OPTIONS method represents a request for information about the communication options available on the request/response chain identified by the Request-URI. This method allows the client to determine the options and/or requirements associated with a resource, or the capabilities of a server, without implying a resource action or initiating a resource retrieval.
thinking beyong just CORS, i think that intercepting a CORS options call although a corresponding method is mapped on the controller is not the right way to go. yes, CORS is one thing you can do with an OPTIONS call. but it is by no means the only one.
if there is nothing mapped and if a handler method is mapped with a different request method and the #CrossOrigin annotation, the assumptions that i want the built in CORS support to be triggered would be fine, but i do not think that any request that has the origin header set should automatically ONLY go to the CORS handlers.
I just convinced Spring 4.3 to pass CORS preflights to my controller by adding a custom handler mapping:
public class CorsNoopHandlerMapping extends RequestMappingHandlerMapping {
public CorsNoopHandlerMapping() {
setOrder(0); // Make it override the default handler mapping.
}
#Override
protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request,
HandlerExecutionChain chain, CorsConfiguration config) {
return chain; // Return the same chain it uses for everything else.
}
}
Note: you'll still need to tell Spring to dispatch OPTIONS requests to your controller to begin with - that is, set dispatchOptionsRequest to true in dispatcherServlet like it says in this question.
WHY IT WORKS
Sébastien's above answer suggests using your own CorsProcessor. As far as I can tell, this will still not use your controller as the handler; it will just pass a different CorsProcessor to its own CORS handler.
By default, it looks like the method AbstractHandlerMapping#getCorsHandlerExecutionChain will throw out your controller when it detects a preflight. Instead of using your controller as the handler, it instantiates a new PreFlightHandler and uses that instead. See Spring source code. This is the problematic line:
chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors);
What it's doing here is rebuilding the execution chain with a PreFlightHandler instead of your controller. This is not what we want, so we can override it to return the input chain.
As suggested by zeroflagl, I also think that this is not a good idea to mix access control and CORS. And you should keep in mind that only preflight CORS requests are OPTIONS ones.
If you need to customize Spring CORS handling, you can use AbstractHandlerMapping#setCorsProcessor() to provide your own implementation that could eventually extend DefaultCorsProcessor.
Please notice that by default, CORS processing is enabled but no remote origin is allowed so customizing CorsProcessor is rarely needed. More info on this blog post.
Your access control check could be done as a regular HandlerInterceptor since a successful CORS preflight request will be followed by an actual request.

Cookie based authorization before calling controllers method in Spring

Recently I came accross this issue. Let's say that I want to give different authorizations to different methods within my controller. I would like to do this using the cookie that was send with the request and to do that I would like to use annotations. I tried to figure out how force #PreAuthorize annotation to work but I am missing something here.
Does anyone know if it's possible scenario (pseudo-code)
#Controller
class myController
{
#SomeAuthorizationAnnotation
#RequestMapping("/")
void doSth()
{
//something is done after authorization
}
}
And now i'd like to write my custom method which grants me access to http request sent to this controller where i could let's say write something like
HttpServletRequest ht = ....
Optional<Cookie> cookie = getCookie(ht.getCookies(), AUTH_TOKEN);
if (cookie.isPresent()) {
//grant authorization for the method call
}
I hope that this is somewhat understandable.
P.S I don't want to bind filters or sth to url's, i want to bind it to methods.
In way to secure your methods you can use #Secured or #PreAuthorize annotations but also you should declare it <global-method-security secured-annotations="enabled" />
See also method security
Well, my solution to this problem was by simply using Authentication Providers within Spring Security and implement interface of UserDetailsService to match my demands according to this project. So then my sessions are automatically handled without necessity for handling Cookies myself. And of course, annotations work.

What is the equivalent of the method attribute of <intercept-url> in JavaConfig?

I'm trying to secure certain parts of a REST service using Spring Security 3.2 using JavaConfig and no XML. In particular I would like to limit access to an end point to be anonymous for a POST operation, and for all other operations to default to the rest of my configuration.
I've checked the Spring Security API docs and their reference documentation, however, I'm not seeing anything that does the equivalent of restricting an access check based on the HTTP method. For example, in XML you can do something like:
<intercept-url pattern="/users/**" method='POST' />
But I see nothing similar in the JavaConfig builders. Is it possible to do this without XML?
Thanks!
Edited 5/20/2014: Changing sample XML to only show the HTTP method.
You can do something like the following:
.antMatchers(HttpMethod.POST, "/users/**").access("hasRole('ROLE_ADMIN')")
You can use annotation #Secured. For detail , you can scan http://www.studytrails.com/frameworks/spring/spring-security-method-level.jsp

Spring Framework HttpRequestHandler failure

We have an application which communicates via REST requests made by clients.
The REST requests contain "region name" and a "ID" as parameters
So, a request would look something like this (for a DELETE)
http://host:port/regionnameID
These REST requests between regions in a federation are properly URL encoded
I find that these request fail if the region name has a slash ("/") in it.
Then, the request would look like so
http://host:port/region/nameID
This is due to incorrect interpretation of the Rest URL by HttpRequesthandler when there is a '/' in the region name.
Now, we have no control over clients sending REST request with "/" in the Region name.
Is there any method / configuration / workaround that can be done to prevent the HttpRequestHandler from returning 404
you should rewrite your urls with urlrwrite and use query parameters internal.
<rule>
<name>Inbound:</name>
<from>^(.*)ID$</from>
<to last="true">delete?regionName=$1</to>
</rule>
Add your urlrewrite Filter in front of all other filters in web.xml
This is a bit of a dirty problem. What I would try to do here is to use the Spring #RequestMapping annotation. There is some documentation on it here:
http://static.springsource.org/spring/docs/2.5.x/reference/mvc.html
You can specific ant wildcards in the value you pass #RequestMapping. If you have a limited number of regions, then you can map them all to a single method as follows:
#RequestMapping(value={"/region1**","/region2**","/region3**")
In your controller method, you will have to add additional logical for parsing out the nameID.
If you have a large number of regions, I would then create a separate Spring Web app (servlet) just to handle these requests. That app would have a cached lookup table of regions.
Configure your own handlerMapping bean (perhaps based on AbstractUrlHandlerMapping)

Categories