Raistlin
Raistlin

Reputation: 1127

Spring Method Security causes Null values for autowired objects

I've played a bit with spring securities method security and got a very strange behavior. I have several controller classes and the methods are annotated with @PreAuthorize to restrict access for certain user roles.

There is one Controller Class who's injected objects are null after adding method security. I debugged into my code and found the following:

enter image description here

service and userService are the injected objects

@Controller
public class OrderController {

    @Autowired
    private OrderService service;

    @Autowired
    private UserService userService;

What seems strange to me is the value description of this: OrderController$$EnhancerBySpringCGLIB$$1a7122f6. By removing all MethodSecurity annotations the class works as expected.

When I look at other Controller Classes which also use method security then they work just fine and the variable list in the debugger looks ok:

enter image description here

@Controller
public class UserController {

    @Autowired
    private UserService service;

I also searched for errors I could have made with the annotations but the annotations in OrderController look the same as in the other Controller classes. Here examples of the OrderController Class:

@Controller
public class OrderController {
              .
              .
              .
    @GetMapping("/dispo/dispo")
    @PreAuthorize("hasAuthority('ADMIN') or hasAuthority('DISPATCH')")
    private String showDispoPage() {
        return "/dispo/dispo";
    }

    @GetMapping("/dispo/orderCreate")
    @PreAuthorize("hasAuthority('ADMIN') or hasAuthority('AL_SYNC_ADMIN') or hasAuthority('CLIENT_USER') or hasAuthority('DISPATCH')")
    private String showCreateOrder(Model model) {
        List<MdUser> userList = service.getUsers();
        model.addAttribute("userList", userList);

        return "/dispo/orderCreate";
    }
}

And here an example of another Controller Class which workes as expected:

@Controller
public class UserController {
                 .
                 .
                 .

    @GetMapping("/admin/user")
    @PreAuthorize("hasAuthority('ADMIN') or hasAuthority('DISPATCH') or hasAuthority('WEBTOOL_USER')")
    public String showInvalidUserPage(Model model) {
        List<UserModel> invalidUserList = service.findInvalidUsers(service.getUsers());

        model.addAttribute("userList", invalidUserList);
        return "/admin/user";
    }

    @GetMapping("/admin/userCreate")
    @PreAuthorize("hasAuthority('ADMIN')")
    public String showNewUserPage(Model model) {
        UserModel user = new UserModel();
        model.addAttribute("user", user);
        return "/admin/userCreate";
    }
}

So what could possibly went wrong here? I don't understand why this one class has a different behavior than the other classes.

Upvotes: 8

Views: 912

Answers (2)

Stefa
Stefa

Reputation: 637

For Kotlin users, make sure the method is not final!

Two days wasted.

Upvotes: 4

Michiel
Michiel

Reputation: 3430

Spring Security uses AOP (Aspect Oriented Programming) to "wrap" an annotated method with AOP advice. Once a method with a pre/post security annotation is invoked, the advice checks whether the user is authenticated and authorized. The method is invoked if it successfully verifies, otherwise some unauthorized/unauthenticed flow is traversed.

Spring AOP can only perform runtime weaving on public methods. The showDispoPage and showCreateOrder are both private, which might interfere with the security advice.

I would move the pre/post authorization annotations to the Service layer. Not only does it provide better separation between controller annotations and security annotations, it also safeguards against any future errors. For instance, in your current set up, any calls to the UserService method will not be verified if they are being invoked through a different Controller where the security annotations have been forgotten.

Furthermore, you may also choose to use web security (securing access to URIs, such as securing /some/path) along with the current method level security set up.

Upvotes: 8

Related Questions