Forum OpenACS Development: Permissions on webservices

Collapse
Posted by Malte Sussdorff on
I am curious how people handle permissions in Webservices or remote calls in general. As the request comes from an external site, how do I know which permissions to use?

The easiest approach would be if the external services provides me with the OpenACS user_id, email or username. But that might not work as the user_id might not be stored in the external site, the e-mail might not be unique on the other side and so on.

Also, when you do more "administrative", not user started operations, do you provide the external system with a proxy account that has the privileges to do these operations or do you write code (which might be duplicated) that allows you to bypass the permission system if the IP address matches?

How is this handled "best practice" wise?

Collapse
Posted by Gustaf Neumann on
I would not recommend to invent new mechanisms for remoting, but using existing one as far as possible. Concerning authentification, it seems that HTTP basic authentification is approach is at least a start and provide accounts for the remote sites. We designed the xotcl remoting services to be compatible with xotcl-core policies (e.g. dependent on package_ids). In principle it should not matter, whether a request was submitted via URL, xml-rpc, SOAP or whatever. One might want to offer certain permissions to certain users to one package instance but not to others (e.g. update some xowiki pages of the documentation, but not for some announcements). It should be possible that the package administrator (or community administrator) makes this decision in a decentralized way.
Collapse
Posted by Tom Jackson on
In TWiST, with OpenACS, you use the normal cookies and session to identify the user.

Prior to invoking the service, you have to establish an account for the client.

Then you have two options:

1. create an additional operation for web services for login. They present the credentials and you return the session cookies and other info so that the client can reuse them.

2. Client reuses info above either as a cookie or as part of the request.

For example Google's AdSense web service uses SOAP headers to provide the credentials. But Amazon's S3 web service (the WSDL interface) uses additional params in the Soap body document. Both use a long lived credential (I think). TWiST uses a session and HTTP cookies.

Once the user is identified, the next question is can they perform the operation, first generally on the object type and second on a particular object. If there are different classes of users of an object, how do you control both the definition of the webservice and their access to it?

Query-writer already provides a HTTP/GET/POST interface which handles all of this. Extending it to a remoting interface of any type would not be difficult. One thing missing for extending to WSDL is a mapping of internal types (database or filters) to XML-Schema types. Query-writer can also be configured to run any other permission checks on any other attributes before performing the operation (for instance if you add a wiki page, you need permission on the wiki package, but also, if you can set the owner, you need permission on the value of that attribute as well.

Collapse
Posted by Stefan Sobernig on
As Gustaf Neumann pointed out already, for remoting by our xotcl remoting services, you can use policies quite similar to xowiki's (though with some extra privileges/ conditions) on service implementations (in the sense of acs-service-contract). In this context, we call them "invocation access policies".
Concerning authentification, it seems that HTTP basic authentification is approach is at least a start and provide accounts for the remote sites.
These policies refer more or less to the enforcing part of such an access scheme, the way how you can transfer identity information in a remoting setting is quite manifold:
  • One might use basic http authentication mechanisms to transfer credentials.
  • Cookies can also be used!
  • You can pack the credentials as header information into SOAP messages etc.
Trust-related issues are a bit more complex to handle, but there are ideas around (WS-Security, WS-Trust) to tackle these. The above, however, should be sufficient to start with.
Collapse
Posted by Malte Sussdorff on
Thanks a lot, that helps, though I am not 100% sure I understood it correctly 😊. Therefore my use case (I should remember to start with a real use case first and then talk about my thinking instead of starting in the middle of it.):

A user logs into the decentralized system (4 different frameworks, running on Windows and Linux) using CAS single signon (which works like a charm in OpenACS by the way). The user goes to system A and says "I want to prepare a product to be produced", he does all the necessary steps of the preparation and once finished he says "Start Project". This is the moment that system A sends over information to OpenACS to create the project, fill in the workflow, add the users to the project and start the workflow with the first task. This is done by calling a webservice provided by OpenACS (TWiST or xosoap).

What do I have at this stage:

a) A single signon cookie, but maybe not an OpenACS cookie yet, because it is not guaranteed that the user signed on to OpenACS before that operation (and the OpenACS cookie is only set once he tries to access an OpenACS webpage).

b) A username / e-mail

As you can see I do not have the password, as the password is only stored in the CAS system. This pretty much rules out HTTP based authentication, am I right?

Even if the user had logged into OpenACS first, I cannot use the cookie as the call comes from the remote server (system A), not from the users browser. Or did I miss something?

I could use HTTP authentication to authenticate System A and provide the username in the SOAP headers, effectively allowing me to check for the permissions for that user. But then I would have to trust System A that noone could login to that system and "fake" the username to be used in the remoting service.

Therefore, is the last one the way to go or did I miss something on the way.

I am not entirely sure how we could use the cookies to do the authentication (as I am not sure that System A is allowed to read the cookie), but if we could send the CAS cookie then I could do the authentication checking (see if the session is still valid) and find out about the username that way (I assume).

Again, thanks a lot for your advise it is really appreciated.

Collapse
Posted by Tom Jackson on
I've done something like this before. User logs into a non OpenACS system. The system gets the creds and then does a backdoor login to the OpenACS system to get the cookie.

Then the user can be redirected with the cookie as a form var, and as long as it is a valid session, log them in without email/password. (Also, the user doesn't even need to be aware of the email/password or their account on OpenACS, these could also be established by the external system.)

But a webservice isn't accessed via a browser, so it is easy to get the cookie(s) and paste them in.

For instance, TWiST does this with the browser interface. If you visit an operation with a GET, it provides a form and shows you what a request looks like, and it includes the cookies you just sent. Fill in the form and send. The cookies are copied and passed on to the webservice call. In response, you get a copy of the sent request and the received response. Essentially it translates HTTP/GET into a SOAP request.

So you could locate the webservice in an admin directory as a very simple way of checking access. User access is more difficult, as the webservice would then be responsible for doing a permission check.

Collapse
Posted by Dave Bauer on
If you have control and trust the other systems, just a unique ID that identifies the user should be sufficient.

That is, assume the single-signon has a way to identify each user, let's call it user_id. The remote system passed the user_id as a parameter of the remote call to OpenACS. Since OpenACS trusts this service (based on whatever you determine) it can peform those actions on behalf of the user_id passed in.