Spring Boot with Spring Security returns 404 on valid login

When activate Spring Security trough custom bean @PreAuthorize("@mySecurity.check(#car)") valid requests will end up in 404, and invalid requests will end up in 200. Without the Pre Authorize all works fine.

The authorisation is done via JWT, and the granted authorities are set correctly.

When I step through the debugger, the Pre Authorize check works correctly returning true or false.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

The Rest controller Implements the Method with the following annotation

    @PreAuthorize("@mySecurity.check(#car)")
    public List<Driver> getAllVersions(String car) {

A Request without security check would look like

2019-09-30 13:34:22.306 DEBUG 26204 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2019-09-30 13:34:42.042 DEBUG 26204 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/foobar", parameters={}
...
2019-09-30 13:34:42.049 DEBUG 26204 --- [nio-8080-exec-4] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-09-30 13:34:42.050 DEBUG 26204 --- [nio-8080-exec-4] m.m.a.RequestResponseBodyMethodProcessor : Writing [{
  "id": "hi",
  "name": "hi",
  "isActive": false
}]
2019-09-30 13:34:42.052 DEBUG 26204 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

When Activating Pre Authorize and doing a valid request, it seems to work partial.

2019-09-30 13:44:22.597 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/foobar", parameters={}
...
2019-09-30 13:44:28.912 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected '*/*' given [*/*]
2019-09-30 13:44:28.938 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView  : View name '/api/v1/car/foobar2', model {configurationVersionList=[{
  "id": "bar",
  "name": "bar",
  "isActive": false
}, {
  "id": "foo",
  "name": "foo",
  "isActive": false
}]}
2019-09-30 13:44:28.946 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView  : Forwarding to [api/v1/car/foobar2]
2019-09-30 13:44:28.950 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "FORWARD" dispatch for GET "/api/v1/car/foobar2/api/v1/car/foobar2", parameters={}
2019-09-30 13:44:28.959 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2019-09-30 13:44:28.963 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2019-09-30 13:44:28.963 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "FORWARD" dispatch, status 404
2019-09-30 13:44:28.970 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND
2019-09-30 13:44:28.981 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}
2019-09-30 13:44:28.984 DEBUG 7400 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2019-09-30 13:44:29.000 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-09-30 13:44:29.001 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Mon Sep 30 13:44:28 CEST 2019, status=404, error=Not Found, message=No message available, (truncated)...]
2019-09-30 13:44:29.027 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 404 

If I do an not allowed Request I receive a 200.

2019-09-30 13:45:53.514 DEBUG 7400 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/%7Bfoobar%7D", parameters={}
...
2019-09-30 13:45:55.660 DEBUG 7400 --- [nio-8080-exec-3] o.s.b.a.audit.listener.AuditListener     : AuditEvent [timestamp=2019-09-30T11:45:55.660Z, principal=JohnDoe, type=AUTHORIZATION_FAILURE, data={details={... snip ...}]
2019-09-30 13:45:55.661 DEBUG 7400 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Failed to complete request: org.springframework.security.access.AccessDeniedException: Zugriff verweigert

pom.xml

...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
...
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web-services</artifactId>
            </dependency>
            <!-- Security  -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>

As requested:

@Component
public class MySecurity {

    public boolean check(String car) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        List<String> givenpermissions = auth.getAuthorities().stream().map(x -> (GrantedAuthority) x)
                .map(GrantedAuthority::getAuthority).filter(authority -> authority.startsWith("car-holder-"))
                .collect(Collectors.toList());
        return !givenpermissions.isEmpty();
    }


}

The endpoint should just verify the JWT ensure the permissions and then return a json answer.

I’ve currently now Idea what the issue could be, so any approach is welcome.

SOLUTION

removed the interface

https://ce455eb961dfe95af4ad8908cb56221e.safeframe.googlesyndication.com/safeframe/1-0-38/html/container.

When I activate Spring Security trough custom bean @PreAuthorize("@mySecurity.check(#car)") valid requests will end up in 404, and invalid requests will end up in 200. Without the PreAuthorize all works fine.

Via JWT, and the granted authorities are set correctly. When I step through the debugger, the Pre Authorize check works correctly returning true or false.

I have the following enabled.

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

The Rest controller implements the Method with the following annotation.

    @PreAuthorize("@mySecurity.check(#car)")
    public List<Driver> getAllVersions(String car) {

A Request without security check would look like.

2019-09-30 13:34:22.306 DEBUG 26204 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Completed 200 OK
2019-09-30 13:34:42.042 DEBUG 26204 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/foobar", parameters={}
...
2019-09-30 13:34:42.049 DEBUG 26204 --- [nio-8080-exec-4] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-09-30 13:34:42.050 DEBUG 26204 --- [nio-8080-exec-4] m.m.a.RequestResponseBodyMethodProcessor : Writing [{
  "id": "hi",
  "name": "hi",
  "isActive": false
}]
2019-09-30 13:34:42.052 DEBUG 26204 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet        : Completed 200 OK

When activating PreAuthorize and doing a valid request, it seems to work partial.

2019-09-30 13:44:22.597 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/foobar", parameters={}
...
2019-09-30 13:44:28.912 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.v.ContentNegotiatingViewResolver : Selected '*/*' given [*/*]
2019-09-30 13:44:28.938 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView  : View name '/api/v1/car/foobar2', model {configurationVersionList=[{
  "id": "bar",
  "name": "bar",
  "isActive": false
}, {
  "id": "foo",
  "name": "foo",
  "isActive": false
}]}
2019-09-30 13:44:28.946 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView  : Forwarding to [api/v1/car/foobar2]
2019-09-30 13:44:28.950 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "FORWARD" dispatch for GET "/api/v1/car/foobar2/api/v1/car/foobar2", parameters={}
2019-09-30 13:44:28.959 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped to ResourceHttpRequestHandler ["classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/", "/"]
2019-09-30 13:44:28.963 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.r.ResourceHttpRequestHandler     : Resource not found
2019-09-30 13:44:28.963 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "FORWARD" dispatch, status 404
2019-09-30 13:44:28.970 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed 404 NOT_FOUND
2019-09-30 13:44:28.981 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}
2019-09-30 13:44:28.984 DEBUG 7400 --- [nio-8080-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2019-09-30 13:44:29.000 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Using 'application/json', given [*/*] and supported [application/json, application/*+json, application/json, application/*+json]
2019-09-30 13:44:29.001 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.s.m.m.a.HttpEntityMethodProcessor  : Writing [{timestamp=Mon Sep 30 13:44:28 CEST 2019, status=404, error=Not Found, message=No message available, (truncated)...]
2019-09-30 13:44:29.027 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Exiting from "ERROR" dispatch, status 404 

If I do an not allowed Request, I receive a 200

2019-09-30 13:45:53.514 DEBUG 7400 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : GET "/api/v1/car/%7Bfoobar%7D", parameters={}
...
2019-09-30 13:45:55.660 DEBUG 7400 --- [nio-8080-exec-3] o.s.b.a.audit.listener.AuditListener     : AuditEvent [timestamp=2019-09-30T11:45:55.660Z, principal=JohnDoe, type=AUTHORIZATION_FAILURE, data={details={... snip ...}]
2019-09-30 13:45:55.661 DEBUG 7400 --- [nio-8080-exec-3] o.s.web.servlet.DispatcherServlet        : Failed to complete request: org.springframework.security.access.AccessDeniedException: Zugriff verweigert

pom.xml

...
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
...
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web-services</artifactId>
            </dependency>
            <!-- Security  -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>

As requested

@Component
public class MySecurity {

    public boolean check(String car) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        List<String> givenpermissions = auth.getAuthorities().stream().map(x -> (GrantedAuthority) x)
                .map(GrantedAuthority::getAuthority).filter(authority -> authority.startsWith("car-holder-"))
                .collect(Collectors.toList());
        return !givenpermissions.isEmpty();
    }


}

The endpoint should just verify the JWT ensure the permissions and then return a josh answer.

I’ve currently now Idea what the issue could be, so any approach is welcome.

SOLUTION

removed the interfacejavaspring-bootspring-securityShareImprove this question MemLeak 3,89444 gold badges

what does @mySecurity.check(#car) do? – Sujay Mohan Sep 30 ’19 at 12:58

Answers

is your Controller annotated with @RestController? if not you’ll need @ResponseBody annotation on your method

@PreAuthorize("@mySecurity.check(#car)")
@ResponseBody
public List<Driver> getAllVersions(String car) {

Without this spring tries to load the actual view which is not present – 404

Or missing PathParam annotation

public List<Driver> getAllVersions(@PathParam("ParamName") String car)

I had some issues in the past with annotations on implemented interfaces instead on the class directly. Pre Authorize does some extra “magic”, just an idea

MemLeak did you try public List<Driver> getAllVersions(@PathParam("ParamName") String car) ? – Marc Stroebel Sep 30 ’19 at 13:35 

Spring Boot 2.1.8 (Spring 5.1.9) – But I doesn’t really get the relation between the path variable and the response – as its working when removing @Pre Authorize 

some log entries are strange 2019-09-30 13:44:28.946 DEBUG 7400 --- [nio-8080-exec-1] o.s.w.servlet.view.InternalResourceView : Forwarding to [api/v1/car/foobar2] 2019-09-30 13:44:28.950 DEBUG 7400 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : for GET "/api/v1/car/foobar2/api/v1/car/foobar2", parameters={}

 I had some issues in the past with annotations on implemented interfaces instead on the class directly. Pre Authorize does some extra “magic”, just an idea 


This Post Has One Comment

  1. Malki Nama

    Controller annotated with @RestController? if not you’ll need @ResponseBody annotation on your method

Leave a Reply