our product is built on a client-server architecture, with the server implemented in Java (we are using POJO's with Spring framework). We have two API levels on the server:
the external API, which uses REST web services - useful for external clients and integrations with other servers.
the internal API, which uses pure Java classes - useful for the actual code inside (as many times the business logic invokes an API call) and for integration with plusins developed inside out company and deployed as parts of our product. The external REST API also uses the internal API.
We implemented permission checking (using Spring security) in the internal API because we wanted to control access at the lowest API level.
But here comes the problem: there are some operations defined on the API level that are regarded as forbidden for a currently logged user, but which should be performed smoothly by the server itself. For example, deleting some entity could be forbidden for the user, but the server might want to delete this entity as a side effect of some other operation performed by the user and we want this to be allowed.
So what is the best approach for allowing the server to perform an operation (in some kind of super-user mode) that might be forbidden for the actual logged-in user?
As I see it we have several options each of which have its pros and cons:
Implement permission checking in external level API (REST) - bad because plugins will bypass permissions checks.
Turn off permission checking for the current thread after the request was granted - too dangerous, we might allow too many server actions that should be forbidden.
Explicitly ask the internal API level to perform the operation in the privileged mode (just like PrivilegedAction in java security framework) - too verbose.
As none of the above approaches is ideal, I wonder what is the best-practice approach for this problem?
Thanks.
Security is applied at the bounds of a module. If I understand you, your system applies security on two levels of abstraction of the (roughly) same API. It sounds complex, as you have to make a double security check on the whole two APIs.
Consider migrating the REST needed methods from the internal API to the external one, and deleting security stuff in the internal API.
external API will manage security for external clients (at the boundaries of your app)
internal API will be strictly reserved for internal app and plugin use (and you would happy hack it, as no external clients are bounded to it)
Do you really need to control the plugin's permissions to your application logic ? Is there a good reason for it ? Plugins are developped by your company, after all. Maybe a formal document explaining to plugin's developpers what should not be done, or a safety test suite validation for the plugin (e.g. assert plugin does not call "this" method) will do the job either.
If you still need to consider these plugins as "untrusted", add the methods they need to your external API (on your app boundary) and create specific security profile for each use: "restProfile", "clientProfile" & "pluginProfile". Each will have specific rights on your external API methods.
It sounds like you need two levels of internal API, one exposed to plugins and one not.
The best way of enabling that would be using OSGi (or Spring Modules). It allows you to explicitly state which packages and classes can be accessed by other modules (ie REST modules and plugin modules). Those would be the exposed level of your new internal API and you would use Spring Security to further restrict access selectively. The internal packages and classes would contain the methods which did all the low level stuff (like deleting entities) and you wouldn't be able to call them directly. Some of the exposed API would just duplicate the internal API with a security check, but that would be ok.
The problem with the best way is that Spring Modules strikes me as still a bit too immature even to put into a new webapp project. There's no way I'd want to shoehorn it into an old project.
You could probably achieve something similar using Spring Security and AspectJ, but it strikes me that the performance overhead would be prohibitive.
One solution that would be quite cool if you could re-architect your system would be to take tasks requiring security elevation offline, or rather make them asynchronous. Using Quartz and/or Apache Camel (or a proper ESB) you could make the "delete my account" method create an offline task that can at a future date be executed as an atomic unit of work with admin priveliges. That means you can cleanly do your security checks for the user requesting account deletion in a completely separate thread to where the deletion actually takes place. This would have the advantage of making the web thread more responsive, although you'd still want to do somethings immediately to preserve the illusion that the requested action had been completed.
If you're using Spring, you may as well utilize it fully. Spring offers AOP that allows you to use interceptors and perform these cross-system checks, and in the event of an unauthorized action, prevent the action.
You can read more about this in Spring's online documentation here.
Hope this helps...
Yuval =8-)
Related
We have 13 years old monolithic java application using
Struts 2 for handling UI calls
JDBC/Spring JDBC Template for db calls
Spring DI
Tiles/JSP/Jquery for UI
Two deployables are created out of this single source code.
WAR for online application
JAR for running back-end jobs
The current UI is pretty old. Our goal is to redesign the application using microservices. We have identified modules which can run as separate microservice.
We have following questions in our mind
Which UI framework should we go for (Angular/React or a home grown one). Angular seems to be very slow and we need better performance as far as page loading is concerned.
Should UI/Javascript make call to backend web services directly or should there be a spring controller proxy in deployed WAR which kind of forwards UI calls to APIs. This will also help if a single UI calls requires getting/updating data from different microservice.
How should we cover microservice security aspect
Which load balancer should we go for if we want to have multiple instance of same microservice.
Since its a banking application, our organization does not allow using Elastic Search/Lucene for searching. So need suggestion for reporting using Oracle alone.
How should we run backend jobs?
There will also be a main payment microservice which will create payments. Since payments volume is huge hence it will require multiple instances. How will we manage user logged-in session. Should we go for in-memory distributed session store (may be memcache)
This is a very broad question. You need to get a consultant architect to understand your application in depth, because it is unlikely you will get meaningful in-depth answers here.
However as a rough guideline here are some brief answers:
Which UI framework should we go for (Angular/React or a home grown one). Angular seems to be very slow and we need better performance as far as page loading is concerned.
That depends on what the application actually needs to do. Angular is one of the leading frameworks, and is usually not slow at all. You might be doing something wrong (are you doing too many granular calls? is your backend slow?). React is also a strong contender, but seems to be losing popularity, although that is just a subjective opinion and could be wrong. Angular is a more feature complete framework, while React is more of a combination of tools. You would be just crazy if you think you can do a home grown one and bring it to the same maturity of these ready made tools.
Should UI/Javascript make call to backend web services directly or
should there be a spring controller proxy in deployed WAR which kind
of forwards UI calls to APIs. This will also help if a single UI calls
requires getting/updating data from different microservice.
A lot of larger microservice architectures often involve an API gateway. Then again it depends on your use case. You might also have an issue with CORS, so centralising calls through a proxy / API gateway, even if it is a simple reverse proxy (you don't need to develop it) might be a good idea.
How should we cover microservice security aspect.
Again no idea what your setup looks like. JWT is a common approach. I presume the authentication process itself uses some centralised LDAP / Exchange or similar process. Once you authenticate you can sign a token which you give to the client, which is then passed to the respective micro services in the HTTP authorization headers.
Which load balancer should we go for if we want to have multiple
instance of same microservice.
Depends on what you want. Are you deploying on a cloud based solution like AWS (in which case load balancing is provided by the infrastructure)? Are you going to deploy on a Kubernetes setup where load balancing and scaling is handled as part of its deployment fabric? Do you want client-side load balancing (comes part of Spring Cloud)?
Since its a banking application, our organization does not allow using
Elastic Search/Lucene for searching. So need suggestion for reporting
using Oracle alone.
Without knowledge of how the data on Oracle looks like and what the reporting requirements are, all solutions are possible.
How should we run backend jobs?
Depends on the infrastructure you choose. Everything is possible, from simple cron jobs, to cloud scheduling services, or integrated Java scheduling mechanisms like Quartz.
There will also be a main payment microservice which will create
payments. Since payments volume is huge hence it will require
multiple instances. How will we manage user logged-in session. Should
we go for in-memory distributed session store (may be memcache)
Not really. It will defeat the whole purpose of microservices. JWT tokens will be managed by the client's browser and expire automatically. You don't need to manage user logged-in session in such architectures.
As you have mentioned it's a banking site so security will be first priory. Here I have few suggestions for FE and BE.
FE : You better go with preactjs it's a react like library but much lighter and fast as compare to react. For ui you can go with styled components instead of using some heavy third party lib. This will also enhance performance and obviously CDNs for images and big files.
BE : As per your need you better go with hybrid solution node could be a good option.e.g. for sessions.
Setup an auth server and get you services validate user from there and it will be used in future for any kinda service .e.g. you will expose some kinda client API's.
User case for Auth : you can use redis for session info get user validated from auth server and add info to redis later check if user is logged in from redis this will reduce load from auth server. (I have used same strategy for a crypto exchange and went pretty well)
Load balancer : Don't have good familiarity with java but for node JS PM2 will do that for you not a big deal just one command and it will start multiple instances and will balance on it's own.
In case you have enormous traffic then you better go with some messaging service like rabbitmq this will reduce cost of servers by preventing you from scaling your servers.
BE Jobs : I have done that with node for extensive tasks and went quite well there you can use forking or spanning this will start a new instance for particular job and will be killed after completing it and you can easily generate logs along with that.
For further clarification I'm here :)
Within our corporate intranet, we have a few end-point service platforms like BPM, document management system, etc. These end-point services expose REST API. We develop web applications using AngularJS as front end.
There are two options on how we can make calls from AngualJS to these end-point services.
Option 1: Given these end-point services expose REST, call these REST API directly from AngualrJS.
Option 2: Introduce a middle layer (on an application server like WebLogic or Tomcat). Build a Java application layer that calls into the end-point REST API; and host it on this millde layer. The AngularJS calls into REST provided by this middle layer; this middle layer inturn calls into the end-point REST.
I personally prefer the Option 1; however I invite your openion on this matter. I have listed the pros and cons of Option 1 as I see them.
Pros of Option 1:
Better performance (throughput) given one less hop for HTTP requests.
Lesser development/deployment efforts due to one less component.
Lesser number of points of failure. If there is an issue, we know its either in AngualrJs or the end service.
Cons of Option 1:
Security issues? Not sure of this - would like expert comments on this.
CORS: the end services will need to enable Access-Control-Allow-Origin to appropriate domains.
Poor logging? If something goes wrong, the logs will be available only on user machines (IE/Chrome development tool) or on the end service.
Too much processing in AngualJS layer? This processing is mainly parsing the result from end service. This also depends on the kind of end service that is being used.
option 2 in my opinion is a better option in long run. There are few reasons for that.
Security is first and foremost, If you have a middleware in between, you can have inherent security, which means you can expose only those REST APIs which your angular webapp needs. You can also include a security mechanism like oAuth since you control the middleware.
Logging is another one. for sure any application nowadays do need some sort of auditing. both security and logging are layers before your actual REST calls.
You would be able to add some aspects on any key REST API, such that in case if that API is called trigger a mail, it's always handy to have those flexibility even we don't need at the moment.
You can include response transformation and error handling efficiently. Once you get the response from service, in your middleware you can transform the response, remove unnecessary or critical fields, conjure some values etc. This all can be done with angular also but then the real response or error is exposed to the client.
On the downside you rightly mentioned performance is one but imo keeping your REST middlware in sync with services REST is more bane. any new API added by services, needs to be included in middleware, recompiled and redeployed. But it also depends what are the likelihood and frequency of those changes? for any those changes you anyhow might need to change in angular webapp to include it.
You mention "Within our corporate intranet". Depending on how the end-points are secured, option 1 could be challenging.
Angular will run in a web-browser so if those services are only accessible via VPN / intranet, the web-app will only work if your computer is connected to that intranet (i.e. it won't work if you run it from home).
Another security challenge with option 1 is that if the end-points require special authentication "secrets" (API tokens, passwords, certificates, etc.), those secrets will be exposed and visible to anyone who uses the web-app since anyone can see the traffic between their browser and the server. With option 2, those secrets can stay hidden behind your middle layer.
Lastly, even if Angular talks to those end-points directly, you will still need to have the HTML / JS / CSS hosted on some web-server. You may not need a full blown application server but you'll need something to point your web browser at.
If those concerns don't apply to your case, then it's really up to you to pick whichever option you and your team are the most comfortable with.
Thanks for such a nice article.
If you are concern with security and your project requirement is focused on Security. One must go with Option 2.
If Security is not a big concern. Options 2 is better.
I'm spending sometime with DynaTrace.
I'm impressed by its feature related to cross jvm instrumentation.
In simple words, DynaTrace is able to instrument Java code creating trace with some statistical information. This is nothing new.
There is a feature really interesting: when a call to an external JVM is execute, DynaTrace is able to link this new trace to the caller one (i.e. remote session bean, web services, remote RMI and so on).
How could it be possible?
I'm not able to immagine how to implement this feature? Any ideas?
Thank you
Dynatrace actually doesnt rely on information from beans. As you correctly said in your questions - we are using Byte Code Instrumentation such as other tools in the market as well. We instrument key methods of certain frameworks, e.g: Servlet, Axis, JMS, JDBC, ...
In the scenario where you make a call from one JVM to another using e.g: HTTP-based communication we instrument both the sending side of the HTTP Request as well as the receiving side on the other JVM. On the sending side we attach an additional HTTP Header with the ID of the current PurePath. PurePath is our patent technology. So - every PurePath (=every single transaction) gets a unique ID. This ID "travels" with the request, e.g: we put it on the HTTP Request as an HTTP HEader. ON the receiving side - your second JVM - we inspect that HTTP HEader and therefore know that all the data we collect belongs to that PurePath. This allows us to do real end-to-end tracing without relying on things like Beans or without correlating this data based on e.g: timestamps
Makes sense?
If you have more questions let me know. I also recorded some videos and put on YouTube to explain the technology and the product itself: http://bit.ly/dttutorials
This information is normally extracted using MXBeans. Such beans provide a standard API for accessing standard runtime information. Similarly, such applications often scan the class loaders for specific classes and extract relevant information by hard-coded access. This is why less popular solutions are often not supported by monitoring tools.
I am interested in finding a pattern or strategy for identifying which code path called a specific API method (or set of methods).
Here are some examples of differentiation in my application:
Caller calls API via an exposed REST controller
Caller calls API via some other internal API
Caller calls API via a user-created plugin
The application does use Spring for core wiring as well as Spring Security. However, the caller could be any user so using the Spring security context to inspect authentication or their associated granted authorities doesn't appear to be the right fit. The same user could call into the API method via one of the exposed REST URIs or call in via an arbitrary plugin entry-way.
How can one manage this type of identification without exposing additional or semi-duplicated APIs for different entry-points? I would like to be able to identify where a particular call originates. Slight differences in functionality can occur depending on whether the call came from one of our REST endpoints as opposed to one user-generated plugin as opposed to some other user-generated plugin.
This could hint at using some form of interception/aspect, but I do not have control over plugin code since I did not generate it. Plugins do have to register in order to get integrated so there is a programmatic hook there.
Looking for suggestions on how to manage this type of issue whether it's using additional Spring feature functionality or an alternative idea or library.
In fact this is a nice question.
As far as i see there are these options:
semi duplicated API (already mentioned above)
different users (or user-groups)
get callstack using reflection (but hard to do and not really recommended)
instead of user you can use some kind of authorization-token "per session" and see if the session is create via HTTP call or if it is an "internal" session
check some kind of session-id and save inside your session where it was created (internal or external, ...)
For now i don't see any other possibilities.
ps: to "flag" the session as internal/external can be done by adding an own spring handler.
Hope this brings you to the right point and helps you out.
I want to make my web application able to work offline and as soon as it becomes online or gets connected again, then it should be able to transfer the modifications made by user in offline mode.
I have seen Google Gears as an ideal solution for my problem, which is not recommended to be used as it is now deprecated.
What is a good way to make my application work offline, both in terms of technology to use and application design?
Gears is deprecated because the HTML5 standard allows for equivalent features to be present in compliant browsers.
With respect to your current problem at hand of handling offline web application access, you can look into the support offered by HTML5 for offline web applications via support for client-side SQL database access, and the client-side application HTTP cache.
The features will have to be used in conjunction, as the client-side database access will allow for storage of data (generated when the application is offline) in a structured format, while the offline application cache will allow for caching of HTTP responses from the server; you should not be caching responses that are dynamic in nature which depend on any user-provided inputs.
The details of the proposed APIs can be found in the W3C HTML5 specification, which is in draft at the moment, although it appears that certain user-agents have already implemented this feature.
Firstly, you will need some form of offline storage. HTML5's capabilities are the successor to Google Gears, as stated on the google gears developer blog; essentially, the purpose of Google Gears was just to push the development & subsequent adoption of HTML 5 features.
Specifically you should be looking at the HTML5 offline (here's a tutorial) APIs, and the Storage APIs may also come in handy (relevant tutorial).
With regards to design, you will essentially need to maintain your complete web application state client side, and then send over the differences (i.e. update the server-side state) as soon as the connection to the server is available again.
Off the top of my head, there's 2 simple ways to design this:
Explicitly maintain separate application states for the client and server. Essentially, when the user takes an action, it's applied to the client application state first, and then at specified intervals (and/or triggers, e.g. the user clicks the save button), the client sends over the differences between the last known state of the server and the current state of the client. This is probably best suited to highly interactive web applications, and I suspect Google Docs works on this kind of design. Depending on your application (if "conflicting changes" can occur), you'll need to also account for merging application state: do you override with the last received client state, or do you intelligently try to merge? (you'll have to decide which makes more sense for your particular application.)
Record user actions while offline, and replay them once the connection becomes available again. You essentially implement the Command design pattern, and have both your client-side code and server-side code able to handle each command. The client-side code always handles each command, and while the connection to the server is available, your client side code also sends off the commands to the server. You'll probably want to implement some batching, to avoid continual requests to the server, and also some roll-back functionality when requests to the server fail (e.g. conflicting changes). This ends up looking more or less like GMail's main email managment user interface, where you can undo operations.
This has not much to do with J2EE, but rather how you code your web-client. One possible solution would be to use a javascript client that does save the data in the local storage introduced with html5 (see http://diveintohtml5.ep.io/storage.html ). That is also basically the reason why google gears was stopped ...