How to give fine grained method permission to a DSP service accessing a remote REST web service


#1

Hello everybody,

I managed to set up a new DSP service that in turn accesses a remote REST web service.

The DSP service is comprised of the following entities

  • /users - Representing all users in the system
  • /users/{user_id} - Representing a specific user in the system
  • /users/{user_id}/reservations - Representing all reservations of a specific user in the system
  • /users/{user_id}/reservations/{reservation_id) - Representing a specific reservations of a specific user in the system

Now I was wondering if it is possible to define the allowed methods for that DSP service on a per-entity level. Example:

  • /users - READ
  • /users/{user_id} - READ
  • /users/{user_id}/reservations - READ
  • /users/{user_id}/reservations/{reservation_id) - READ, PUT and DELETE

Right now as far as I was able to manage it, the definition of allowed methods is only possible on a per-service level which would result in the same set of allowed methods for all entities.

Regards, Matthias


Access to database rows
#2

Assuming all users require the same access to the remote web service, you could write a custom script to allow or deny access based on the HTTP method and resource (url) provided to the script. There would be no service on the DSP for the remote web service. You would be calling the remote web service directly from the custom script.

To invoke a custom script, the calls from the client would look like this:

POST /system/script/myservice?is_user_script=true&svcMethod=GET&svcResource=/users

The custom script would have logic something like this:

var result = null;
// get method and resource from query params
var method = event.svcMethod;
var res = event.svcResource;
// get data POSTed to script if any, it's wrapped with record []
var data = event.record[0];
var baseUrl = http://www.myservice.com;

if (res like /users or res like /users/{user_id} or res like /users/{user_id}/reservations)
	if (method === "GET") {
		result = platform.api.get(baseUrl + res);
	} else {
		throw("method " + method + " is not allowed for resource " + res);
	}
} else if (res like /users/{user_id}/reservations/{reservation_id})
	switch (method) {
	case "GET":
		result = platform.api.get(baseUrl + res);
	case "PUT":
		result = platform.api.put(baseUrl + res, data);
	case "DELETE":
		result = platform.api.delete(baseUrl + res);
	default:
		throw("method " + method + " is not allowed for resource " + res);
	}
}

// return null for invalid resource
return result;

Think about this and let us know if it’ll work you.


#3

Hi Todd,

thank you very much for your answer.

Reading your answer I was wondering if it is a design flaw of the final web service when I need to restict/define the user access on a per-entity basis rather than for the whole webservice alone.

Or in other words: would the necessity of defining fine-grained entity level access ever arise with a perfectly designed web service?

Regards, Matthias


#4

Hey Matthias,

If you haven’t already, you should take a look at the blog posts below on server-side filters. This feature provides a pretty comprehensive way to manage entity-level access control.


In short, server-side filters provide a way to control access to an arbitrary set of records within a given table that a REST service can access. For example, say you set up an API in DreamFactory which returns data from a remote MySQL database that has twenty tables. Server-side filters enable you to specify conditional logic that governs which records are available to users to create, read, update, and delete within each of those twenty tables (i.e., record-level access control).

So in that example you have one service that accesses many tables. And you can set up multiple roles that use that service (often you only have one role, but you can have many). And each role can have completely different HTTP access to different sets of records within each of those tables. The most common example is allowing users to read, update, and delete records that they’ve created in a given table.

If you’re connecting to a remote web service, you have to look at how that remote web service is defined. If it consists of structured data like SQL tables or NoSQL collections, then we’d suggest structuring the web service the same way as DreamFactory’s REST APIs for SQL and NoSQL…in which case it’s easier just to connect to the SQL or NoSQL database with DreamFactory so the API is auto-generated and you can use server-side filters for record-level access control on those remote databases.

However, for special cases where you think you need a different API definition, you can use DreamFactory to connect to the remote web service, and use server-side scripting to manage record-level access control on that remote web service.

Hope that helps.