views:

351

answers:

3

Hi all,

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:

  1. Implement permission checking in external level API (REST) - bad because plugins will bypass permissions checks.
  2. 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.
  3. 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.

A: 

Hi,

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-)

Yuval
My question was rather conceptual and not technological. We ARE using Spring security and don't have problems with it.
Stas
+2  A: 

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.

Tusc
It's one of the possibilities we examined. The problem with it, besides the plugins issue, is that it means that allowing the primary request implies automatic allowing subsequent API calls that stem from this request.
Stas
As I understand you:You describe a statefull scenario (In the context of "this" first method call, only "these" subsequent method calls are allowed). The problem is, your API is stateless and thus, you have defined a stateless permission model which (naturally) doesn't fit your statefull scenarios.
Tusc
2 solutions: 1) "statefullise" the user of your stateless API (cookie/URLsessionID): the user state on the server reminds you subsequent API calls. You can then choose to allow (or not) execution of this specific stateless API call. Cost: a lot of complex decision logic before real use of your API.
Tusc
2) "statefullise" your API (break it) for use by your stateless users: your api seems "tech" oriented. Make use cases, and build a specific business, app-wide and long-lived statefull object for each scenario. At first call of the statefull object API, the user is registered. On subsequent calls,
Tusc
the user is "recognized" and allowed to proceed. Cost: breaking your whole API, but you'll have a "clean" business interface in front of your "tech" APIs (this is the SOA way).
Tusc
A: 

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.

Caoilte