17
  1. What are the advantages to get principal as a parameter Principal principal in spring controller and then pass it to service layer over getting principal in the service layer immediately though SecurityContextHolder.getContext().getAuthentication().getPrincipal() ?
  2. What is the best approach to get principal details in service layer without checking getAuthentication() and getPrincipal() objects for null everywhere (something like a custom wrapper)?
Maksym Demidas
  • 7,707
  • 1
  • 29
  • 36
Alex
  • 11,451
  • 6
  • 37
  • 52
  • 1
    You might find the answers to [this question](http://stackoverflow.com/questions/248562/when-using-spring-security-what-is-the-proper-way-to-obtain-current-username-i) useful. [This answer](http://stackoverflow.com/questions/8764545/best-practice-for-getting-active-users-userdetails/8765597#8765597) could be useful too. – Shaun the Sheep Feb 13 '13 at 14:13
  • Is it a good solution to have abstract class with static method where I can put `SecurityContextHolder.getContext().getAuthentication().getPrincipal()`? After that I can use it in the service layer. – Alex Feb 14 '13 at 00:40
  • Read the second link I gave you again. There's nothing to stop you using that approach in your services and if you use an interface you can also swap it out for testing. – Shaun the Sheep Feb 14 '13 at 01:59
  • Thank you for your solution. But by using interface and implementation I will need to inject this to almost each service or could be to the base service class. How about using static method (from my comment above)? What is better? – Alex Feb 14 '13 at 02:08

1 Answers1

14
    • Your service API will be more easy to use. You will see dependency on principal directly, so you wan't call some service method by mistake in environment where principal does not exist.
    • In general less dependencies on SpringSecurity code means less problems in a case of migration to new Spring Security version.
    • You will be able to reuse your service layer in environment where Spring Security does not exist.
  1. Prepare some wrapper class (for example AuthenticationService). Add getPrincipal() method to it. Implement your checks. Inject AuthenticationService everywhere insted of direct calls to SecurityContextHolder.
Maksym Demidas
  • 7,707
  • 1
  • 29
  • 36
  • If I need to get some data for specific user I think getting a principal (username for example) in the service layer is more secure because there are less layers between this (restriction) and database. So it's the only dao left as opposed to getting principal in the controller (additional service layer between). But on the other hand, as you said, service layer can be more reusable. What do you think about that? – Alex Feb 13 '13 at 00:32
  • 3
    A principal object is hold and kept by web layer. So for me it looks natural that a principal came from contoller to service layer. Another point is that static dependencies are bad for unit testing: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability/. I do not see any security problems because a pincipal instance is immutable (and normally password will be eraised from actual implementation at this moment). Sorry for delay. I was AFK long time. – Maksym Demidas Feb 27 '13 at 18:08
  • Is it safe to use your option 2 in the extended BaseService (in service layer)? – Alex Mar 07 '13 at 12:40
  • What do you mean under "safe"? – Maksym Demidas Mar 08 '13 at 09:36
  • 2
    It is thread safe because the principal is immutable. However you can have one litlle throuble related to multithreading. Imagine that thread A checks that authentication is not null like that: `SecurityContextHolder.getContext().getAuthentication() != null`. Then thread B performs `SecurityContextHolder.clearContext()`. After this thread A may has NPE here: `SecurityContextHolder.getContext().getAuthentication().getPrincipal()`. To avoid this situation always get a reference `Authentication authentication = SecurityContextHolder.getContext().getAuthentication()`. – Maksym Demidas Mar 12 '13 at 09:17
  • Great answer @MaksymDemidas, I am thinking about creating one static method which returns the user's name and authority. I have JPA specifications in which I want to use this static method to create the query and return records based on role. By this, I don't have to pass Authentication from controllers to services and in case of version migration, I have to change only that static method. Is it a good way? – Romil Patel Apr 05 '20 at 14:19