Child pages
  • Set permissions
Skip to end of metadata
Go to start of metadata

Setting authorizations and protecting your content

Apstrata allows you to define fine grained permissions on the content of your documents (no SQL key/value pairs data structures), by specifying who (users, roles or groups) is authorized to read/write a given set of fields in a given document type. Apstrata also allows you to specify who (users, roles or groups) is authorized to execute a given server-side script. Authorizations are created using Access Control Lists (ACLs) and applying those on your documents and scripts provides you the ability to define flexible and powerful authorization policies.

Authorizations on documents can be specified using document schemas ACLs, whereas authorization on server-side scripts are specified using the ACL that is embedded in a script. Document schemas allow you to create types of documents, with predefined authorizations and content validation rules.

Back to the map       Next stations: control access, Log in with Facebook

Example 1 - Only authenticated users can subscribe to the newsletter

You need to diffuse a newsletter to keep your users informed of the latest updates and events that relate to your mobile game. Subscribing to the newsletter is done by invoking one of your server-side scripts from the client side of your game. However, you want to restrict the subscription to that latter to your authenticated users only, i.e. users who are known to your Apstrata user directory. Let us see how to do this using a server-side script:

 

<script>
<scriptACL>
	<!-- 
		execute is used to specify the list of roles, users and groups who are authorized to execute this script
		authenticated-users is a predefined Apstrata role that includes any user known to your Apstrata user directory. 
		The script will check the signature of the call and make sure it matches one of your user's credentials 
	-->
	<execute>authenticated-users</execute> 
	<read>nobody</read>
	<write>nobody</write>
</scriptACL>
<code>
	<![CDATA[
		
		// Extract the user who initiated the call from the native request object
		var user = request.user;
		var login = user.login.substring(0, user.login.indexOf("@")); // The value of the login field is such as : username@applicationKey
		
		// retrieve the name and email of the user from the user object and store them in 
		// a newsletter_subscription document
		var subscriptionParams = {
			"apsdb.store": "DefaultStore", // DefaultStore is the name of the store by default
			"name": user.name,
			"email": user.email,
			"apsdb.schema": "newsletter_subscription", // a schema allows you to define types of documents and specify authorization and validation rules
			"apsdb.runAs":  login // Create the document using the current user privileges
		};
		
		var response = apsdb.callApi("SaveDocument", subscriptionParams, null);
		if (response.metadata.status == "failure") {
			return response.metadata;
		}
		
		return {
				"Message" : user.name + "( " + user.email + ") subscribed to news letter",
				"subscriptionId":  response.result.document.key // we return the key of the subscription document as a subscription identifier
		}
	]]>
</code>
</script>

Example 2 - An authenticated user can only cancel his own subscription to the newsletter

OK. You now can control who can subscribe to the newsletter. Let us assume next that we need to allow any player to cancel his subscription to the newsletter. We can write a server-side script for that and make sure that only authenticated users are authorized to execute it. However, how do we make sure that the caller can only remove his own subscription?

To make this possible, we need to combine two authorizations levels: the one that applies to scripts (script ACL) and the one that applies to content (schema ACL). 

Let us start with the latter and see how to specify this in the "newsletter_subscription" schema that we used in example 1 above:

<schema>
	<aclGroups> <!-- ACL groups allow you to specify authorizations on groups of fields -->
		<aclGroup name='all_the_document'> <!-- In this schema we create a single ACL group that applies to all the fields of the document -->
			<!-- creator is an Apstrata pre-defined role that refers to the user who created the document -->
			<read>creator</read><!-- the creator is the only one entitled to read/query this subscription document -->
			<write>creator</write><!-- the creator is the only one entitled to update/delete this subscription document -->
			<fields>
				<field>name</field>
				<field>email</field>
			</fields>
		</aclGroup>
		<schemaAcl>
			<read>nobody</read>
			<write>nobody</write>
			<delete>nobody</delete>
		</schemaAcl>
	</aclGroups>
	<fields>
		<field name='name' type='string'>
			<validation>
				<cardinality min='1' max='1'/>
			</validation>
		</field>
		<field name='email' type='string'>
			<validation>
				<cardinality min='1' max='1'/>
			</validation>
		</field>
	</fields>
</schema>

Now let us see how to leverage this in the cancelSubscription script that we create to allow authenticated users to cancel their own subscription:

<script>
	<scriptACL>
	    <!-- Only authenticated users, i.e users known to your Apstrata user directory can execute this script -->
		<execute>authenticated</execute>
		<read>nobody</read>
		<write>nobody</write>
	</scriptACL>
	<code>
		<![CDATA[
			
			var user = request.user;
			var login = user.login.substring(0, user.login.indexOf("@")); // The value of the login field is such as : username@applicationKey
			var subscriptionId = request.parameters["subscriptionId"];
			
			// Prepare the parameters to send to the DeleteDocument API in order
			// to delete the subscription
			// The DeleteDocument API is called with the current user's privileges (apsdb.runAs field)
			// which guarantees that he can only delete a document that he owns
			var deleteSubscriptionParams = {
			    "apsdb.store": "DefaultStore",
			    "apsdb.documentKey": subscriptionId,
			    "apsdb.runAs": login 
			}
			
			var response = apsdb.callApi("DeleteDocument", deleteSubscriptionParams, null);
			if (response.metadata.status == "failure") {
			    return response.metadata;
			}
			
			return "success";
		]]>
	</code>
</script>

Try it!

You can directly try these examples using the Apstrata workbench

Step 1. Create two users (players)

First, create two users for your application that we will use in our test: click on "Manage App > Users > Save User". Fill in the form fields to create a first user (let's set his login to "user1") then save. Repeat these steps to create a second user (let's set his login to "user2").

Step 2. Create the newsletter_subscription  schema

If not already done, click on "Manage App > Schemas >  New" to create a new schema. Copy/paste the above example and save it (in the example below, we chose "newsletter_subscription" for the schema name).

Step 3 - create the "subscribeToNewsLetter" and "cancelSubscription" scripts

Manage App >  Scripts > My Script >  New" to create a new script. Copy/paste the "subscribeToNewsLetter" script above then click on "Save". Repeat the operation for the "cancelSubscription script".

Step 4 - create a subscription for an authenticated user (e.g. user1) and for an unknown user

4.a. In the list of your available scripts, click on "subscribeToNewsLetter" then on the "Run" button. In the parameter form, enter "apsdb.runAs" as a parameter field and set "user1" as the value, then click on "Go".

The call should be successful.

4.b. Now repeat the same operation by passing a dummy value for the "apsdb.runAs" parameter then click on "Go". You can observe that Apstrata returned an "INVALID_IDENTIFIER" error message:

Step 5 - Let user2 try to cancel the subscription created by user1

Write down the value of the subscriptionId field returned in the response returned at step 4.a. Select the "cancelSubscription" script from your list of scripts, click on "Run". In the parameters form, add "apsdb.runAs" as a fieldName and set its value to "user2". Also add the "subscriptionId' fieldName and set its value to the value of subscriptionId (as returned in 4.a), then click on "Go". As you would expect, Apstrata applied the authorization policy defined on the "newsletter_schema" and prevented "user2" from deleting a document owned by "user1".

Dig deeper

Related tutorials

 

 

  • No labels