I have been using spring security with #PreAuthorize on my controller methods. My reasoning was that I wanted the authorization check to happen predictably in one layer, and as early as possible in the request. However, I just read the spring security 3 documentation, and saw that they recommend applying method level security on the service layer (but they don't say why).
My question is: should spring security method level annotations be applied at the controller layer or the service layer? (Or "both", or "it depends"?) More importantly: why?
"It depends" :). If your application has a service layer through which all your business logic is applied then that is usually a clean place to apply your security constraints and be certain that you haven't missed out any corner cases.
Web code is generally messier, there's more of it, it changes more rapidly and you may end up calling the same service methods from multiple places. Someone might add a new controller and forget to secure it properly. Alternatively you might have different types of clients calling the same services.
But it depends on how your application is structured and what your use cases are. You may have a good argument for why you want to secure a controller.
Think in terms of code reuse. Are you going to use your service elsewhere? Not just to feed your web tier?
We also reuse our services with jms bridges so we secure our service layer.
I think the Service is the better place to use it.
Despites some problems that #PreAuthorize could create on Controller and the Spring Security FAQ recommendation to put this kind of annotation on Service, I understand that the authorization for some action is more a business rule than a responsibility for the web tier.
Related
In Spring Security I see URL's secured with:
http
.authorizeRequests()
.antMatchers("/admin").hasRole("ADMIN");
I also see that there is method level security:
#PreAuthorize("hasRole('ADMIN')")
Are the antMatchers used to secure the URL while the #PreAuthorize used to secure interfaces?
If the antMatcher secures the URL that calls the interface already, then why the need to separately secure the interface method?
Could you use method level security on the controller like:
#PreAuthorize("hasRole('ADMIN')")
#GetMapping("/dashboard/person")
public String findEvent(Model model, HttpServletRequest request) {
....
Web security and method security are two different ways to secure your application, see Spring Security Reference:
Why not just use web.xml security?
Let’s assume you’re developing an enterprise application based on Spring. There are four security concerns you typically need to address: authentication, web request security, service layer security (i.e. your methods that implement business logic), and domain object instance security (i.e. different domain objects have different permissions). With these typical requirements in mind:
[...]
Web request security: The servlet specification provides an approach to secure your request URIs. However, these URIs can only be expressed in the servlet specification’s own limited URI path format. Spring Security provides a far more comprehensive approach. For instance, you can use Ant paths or regular expressions, you can consider parts of the URI other than simply the requested page (e.g. you can consider HTTP GET parameters) and you can implement your own runtime source of configuration data. This means your web request security can be dynamically changed during the actual execution of your webapp.
Service layer and domain object security: The absence of support in the servlet specification for services layer security or domain object instance security represent serious limitations for multi-tiered applications. Typically developers either ignore these requirements, or implement security logic within their MVC controller code (or even worse, inside the views). There are serious disadvantages with this approach:
a. Separation of concerns: Authorization is a crosscutting concern and should be implemented as such. MVC controllers or views implementing authorization code makes it more difficult to test both the controller and authorization logic, more difficult to debug, and will often lead to code duplication.
b. Support for rich clients and web services: If an additional client type must ultimately be supported, any authorization code embedded within the web layer is non-reusable. It should be considered that Spring remoting exporters only export service layer beans (not MVC controllers). As such authorization logic needs to be located in the services layer to support a multitude of client types.
c. Layering issues: An MVC controller or view is simply the incorrect architectural layer to implement authorization decisions concerning services layer methods or domain object instances. Whilst the Principal may be passed to the services layer to enable it to make the authorization decision, doing so would introduce an additional argument on every services layer method. A more elegant approach is to use a ThreadLocal to hold the Principal, although this would likely increase development time to a point where it would become more economical (on a cost-benefit basis) to simply use a dedicated security framework.
d. Authorisation code quality: It is often said of web frameworks that they "make it easier to do the right things, and harder to do the wrong things". Security frameworks are the same, because they are designed in an abstract manner for a wide range of purposes. Writing your own authorization code from scratch does not provide the "design check" a framework would offer, and in-house authorization code will typically lack the improvements that emerge from widespread deployment, peer review and new versions.
Spring Security recommends method security, see Spring Security Reference:
10.1.4 Request Matching and HttpFirewall
[...]
In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. You should try and restrict yourself to using a few simple ant paths which are simple to understand. Always try to use a "deny-by-default" approach where you have a catch-all wildcard ( / or ) defined last and denying access.
Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security’s method security options.
Spring Security recommends applying method security at the service layer rather than on individual web controllers, see Spring Security Reference:
I have added Spring Security’s element to my application context but if I add security annotations to my Spring MVC controller beans (Struts actions etc.) then they don’t seem to have an effect.
[...]
Generally we would recommend applying method security at the service layer rather than on individual web controllers.
Suppose I have a Spring application divided into 3 layers: controller, service and repository. In which layer should all the business logic go? From what I have read on the net, the controller should only consume the service and it is the service that should be the one that contains all the business logic. Is this correct? Should I handle the Exception that may occur in the service?, I'm quite new to Spring and not sure which is the correct way to approach and which are the best practices.
Into services.
Repo - interaction with database
Controller - Http communication handling (or other type if interaction like CLI)
Service - bussiness logic.
You should put all your business logic into the Service Layer.
Commonly, exceptions are, also, handled at the Service Layer. This happens mainly because of the reusability. However, in Spring Applications, generally, even the service layer throw the exceptions, so that you can centralize all the errors in a single handler class.
Read more at Spring MVC Exception Handling.
I have a design/architectural problem:
I've started developing a java web application. I thought of using 3 layers: a persistence layer (with jpa and hibernate), a business layer and a presentation layer. My problem now is:
the jpa entities would make the model but can or may I use the entities as business objects?
Is this a practice? My common sense says I shouldn't, but then, I need to duplicate these entities as business objects?
Finally, I'd like the presentation layer to be really decoupled from the other layers. While using spring mvc with jsp at first, I'd like. if it's suitable, at some moment to switch to javascript-based application that communicates with the backend through rest requests.
Yes, you can. Outside the persistence context, the JPA Entities are like simple POJOs. It is legal to use them in business code (actually, as hinted by JB Nizet, you usually ALWAYS use them in your business layer without DAO). If it is tightly related to the Entity, you can even add business logic into your JPA beans. Nevertheless, it will be harder to read and understand what the code does. But if you have a reason to do that - there is nothing illegal. It all comes down to software design practices and what you need most.
When you want to change your app into the REST-powered service, it is not difficult. You will have to change the Servlet you are currently running your app with for a JAX-RS or other framework Servlet which will handle HTTP requests in a REST manner for you. It is done in web.xml. Then, you will place your html-pages in any place, where it is accesible for the remote hosts, and connect them to your REST-service with the Javascript AJAX or sth. You should take care of CORS then.
I am using Java EE for running my backend system and I have a question regarding how to layer it appropriately in terms of creating a web service.
I am pretty much organizing my application after the principles of DDD which means I have a domain layer, repository layer and a service layer. So the service layer are annotated with #Stateless and they are my EJBs.
Now, I could go crazy and annotate this service class with more annotations for the JAX-RS framework...but I don't know if this is correct for several reasons:
Wouldn't this mix the layering a bit?
How could I then version my webservice? Let say that I create a webservice today, and tomorrow I find out that it is really bad, however during the night someone have created an application that uses it and if I trash it the applications could no longer be used. What I want is a webservice that can be found on www.myurl.com/api/v1/customers
and the new webservice on www.myurl.com/api/v2/a_new_customers_webservice
That is what I want in some sort.
There may be other cons too?
So what would the solution be? Am I correct if I say that I create another set of classes that I annotate with JAX-RS annotations and then the methods could internally use the methods from the EJBs in the service layer?
If there is going to be another webservice version I can create another set of classes that uses other URLs and logic. Or am I all wrong? How would you organize this?
The underlying question is how to organize code for reuse. As you pointed out, you can:
annotate your EJB services with JAX-RS to make them web service;
create EJB web services (i.e. with JAX-RS annotations) that reuse other common EJB services (one level of indirection);
create EJB web services that reuse common logic as POJO (one level of indirection).
All three a valid choices to me.
If you're confident about the API of the EJB service, but not the API of the web service (there could be some impedance mismatch), I would go for 2.
If you are not confident about what your EJB service should do, then that's probably the first thing to figure out ;)
If you're confident now, but suspect it might change in the future, I would pick the simplest solution 1 for now, and refactor later as necessary depending on what must be changed. Apply YAGNI.
I have an existing domain model annotated with JPA annotations that I would like to easily expose CRUD operations on via Web Services. I already have DAOs to perform CRUD operations on all of my entities in my domain.
Does anyone know of an way to do this that does not involve a tremendous amount of effort?
It depends on how my operations and services and what you call "a tremendous amount of effort." You're likely to be disappointed if doing anything more than pushing a button and having your wishes come true is too much.
But there are three parts to your problem:
Writing DAOs that expose the CRUD operations. I'd recommend an interface-based approach.
Exposing these as "contract-first" web services, either SOAP or REST.
Mapping HTTP requests and responses to your API.
I'd recommend Spring, because it'll help with DAOs, web services, and mapping. But I don't know if it'll be as effortless as you want it to be.
You can use Apache CXF in combination with Spring ROO to achieve this.
Please see this post for more details: http://forum.springsource.org/showpost.php?p=284028&postcount=4
Throw some annotations on that DAO, like #WebService and #WebMethod and use your JAX-WS implementation of choice. You can use JAX-WS Commons Spring for Spring integration.