Urbanleg
Urbanleg

Reputation: 6532

Spring MVC - allowing requests from localhost only to specific controller

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

Upvotes: 18

Views: 26714

Answers (5)

Speedy
Speedy

Reputation: 1554

For people with limited knowledge of Spring or Spring Security, follow these steps (applicable for Spring Security v6):

#1. Add Spring Security into your project. Maven example:

<dependencies>
    <!-- ... other dependency elements ... -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
</dependencies>

#2. Add a Spring Security configuration class to your project, e.g. SecurityConfig. Put all your Spring security configurations there:

@Configuration
@EnableWebSecurity
@EnableMethodSecurity // this will enable the method security required for the @PreAuthorize annotation
public class SecurityConfig {    
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.httpBasic().disable(); // this will disable the login/pass requirement
        return http.build();
    }
}

#3. Use @mbaranauskas solution:

@PreAuthorize("#request.getRemoteAddr().equals(#request.getLocalAddr())")
@GetMapping(path="/test-local")
public @ResponseBody String testLocal(@P("request") HttpServletRequest request) {
    // body of your method
}

Upvotes: 0

mbaranauskas
mbaranauskas

Reputation: 483

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) {
    ...
}

Upvotes: 2

ezer
ezer

Reputation: 1172

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

Upvotes: 8

Krešimir Nesek
Krešimir Nesek

Reputation: 5502

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.

Upvotes: 14

NimChimpsky
NimChimpsky

Reputation: 47290

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.

Upvotes: 6

Related Questions