Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 357
Raistlin Avatar asked May 21 '19 11:05

Raistlin


People also ask

Why are my Autowired fields null?

The field annotated @Autowired is null because Spring doesn't know about the copy of MileageFeeCalculator that you created with new and didn't know to autowire it.

Why is @autowired not working?

When @Autowired doesn't work. There are several reasons @Autowired might not work. When a new instance is created not by Spring but by for example manually calling a constructor, the instance of the class will not be registered in the Spring context and thus not available for dependency injection.

Can a bean be null?

Internal representation of a null bean instance, e.g. for a null value returned from FactoryBean. getObject() or from a factory method. Each such null bean is represented by a dedicated NullBean instance which are not equal to each other, uniquely differentiating each bean as returned from all variants of BeanFactory.

How does Autowired work in Spring?

Autowiring happens by placing an instance of one bean into the desired field in an instance of another bean. Both classes should be beans, i.e. they should be defined to live in the application context. What is "living" in the application context? This means that the context instantiates the objects, not you.

Why is my spring @AutoWired field null?

Why is my Spring @Autowired field null? 1 Inject your beans. The most preferable option is to let Spring autowire all of your beans; this requires the least amount of code and is the most maintainable. 2 Use @Configurable. ... 3 Manual bean lookup: not recommended. ...

Why is the @AutoWired field of one of my beans null?

The @Autowired field of one of my beans is null at runtime. The root cause is, instead of using the auto-created bean maintained by the Spring IoC container (whose @Autowired field is indeed properly injected), I am new ing my own instance of that bean type and using it.

How do I create an AutoWired object in spring?

Use @Configurable. If you really need objects created with new to be autowired, you can use the Spring @Configurable annotation along with AspectJ compile-time weaving to inject your objects. This approach inserts code into your object's constructor that alerts Spring that it's being created so that Spring can configure the new instance.

Why is my field null in Spring Boot?

If the application starts and your field appears to be null it is generally due to one of the following issues: Using the HelloWorldService below as a bean in a Spring application would fail, as dependency injection on static fields isn’t supported.


2 Answers

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.

like image 116
Michiel Avatar answered Nov 15 '22 08:11

Michiel


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

Two days wasted.

like image 36
Stefa Avatar answered Nov 15 '22 07:11

Stefa