Meteor: REST collection API and auth - rest

In the need to expose part of my Meteor collections through REST, I stumbled across a the Collection API Meteorite package.
Whereas this indeed makes it possible to expose a Meteor Collection through REST, it does not take any security into account. Is there any way I can integrate the Collection API with the Meteor auth system introduced in 0.5.2?

Yes, kinda. Using the REST meteorite package, you can declare your collection and then use the allow rules on the collection, but with a couple caveats (NOTE: this is pseudo-code that requires more work!):
Players = new Meteor.Collection("players");
//a collection of associated userids and auth token headers
APIUsers = new Meteor.Collection("apiusers");
Players.allow({
insert: function (userId, doc) {
//invoking this from a RESTful context means the userId is NOT
//available, so you'll need to do three things things:
// (1) a way to get the current http request's X-Auth-Token header
// (2) a collection to look up the user(s) associated with
// that token
// (3) and an owner field on the Players collection to join back
// to the found userids.
return (_.indexOf(APIUsers.findOne(
{XAuthToken: __CURRENT_X_AUTH_TOKEN__}).users
, doc.owner) > -1;
},
update: function (userId, docs, fields, modifier) {
/* similar logic */
},
remove: function (userId, docs) {
/* similar logic */
},
fetch: ['owner']
});
BUT while I think the RESTful approach will prove useful in integrating legacy applications into a Meteor context, I would highly recommend looking into the DDP protocol for integration of new projects.
As you can see above, the allow rules do not expose a GET callback, presumably because the expectation is the GET is defined in the publication the server exposes. A DDP client is wired at a lower level to subscribe to these publications, so GETs in this context will be much more granular than a RESTful approach.

For anyone stumbling across this now, Restivus allows you to generate REST endpoints on collections, and configure user authentication and role permissions on those endpoints. The default authentication uses Meteor's built-in login token mechanism to authenticate a Meteor.user and provide access to this.user and this.userId in authenticated endpoints. You can also provide a custom authentication method if the default is too much, or not enough, for you. Here's a quick example (hope you can read CoffeeScript):
# Generates: GET, POST on /api/users and GET, DELETE on /api/users/:id for
# Meteor.users collection
Restivus.addCollection Meteor.users
excludedEndpoints: ['deleteAll', 'put']
routeOptions:
authRequired: true
endpoints:
post:
authRequired: false
delete:
roleRequired: 'admin'

Related

PUT list to a mapping collection. Only id array in request body?

I'm designing a REST interface for my service. My service will be Role and Permission based. Therefor a Role will contain Permissions.
Meaning a Role will have a collection of Permissions -> roles/1/permissions
Now I would like to change the set of Permissions for a Role. As I understand, a correct request for this would be:
PUT roles/1/permissions
[
{
id: 1,
permissionName: "read"
}, {
id: 2,
permissionName: "write"
}, {
id: 3,
permissionName: "delete"
}
]
As this basically only maps existing permissions (/permissions) to a role, there is a lot of unnecessary information sent. Especially if this example would contain a resource which is much more detailed as a Permission.
Would it be okay to only send an array of ids in the body?
PUT roles/1/permissions
{
ids:[1,2,3]
}
I would reach the same, with only the information I actually need. Is there a problem with this approach? I'm afraid that this might hurting the stateless principle of REST.
Sending the permission identifiers is just fine to create a link between the a given role and a set of permissions.
On server side, you should validate the permission identifiers and return a 422 if they are invalid. See this answer for further details.
The stateless constraint determines that each request must contain all of the information necessary to be understood by the server, rather than be dependent on the server remembering prior requests. And session state should be handled entirely by the client:
5.1.3 Stateless
[...] each request
from client to server must contain all of the information necessary to
understand the request, and cannot take advantage of any stored
context on the server. Session state is therefore kept entirely on the
client. [...]
Sending only the permission identifiers won't break the stateless constraint.
For more details on the stateless constraint, refer to this answer.
Your REST API is completely fine and it does not violate the stateless principle in any way. Your REST API will be using a different resource model for GET and PUT methods, which is also fine.

Upsert (update or insert) of resources with generated URIs in REST?

My data access layer supports the upsert operations (Spring Data's CrudRepository.save()), when the id field is not set a new record is inserted and when the id field is set it is updated.
I am wondering how to justify the additional effort required to create two separate REST methods (both on the backend and the frontend side):
POST /users, for creating a new user (and generating the URI of the newly created resource)
PUT /users/{id}, for updating the existing users
over creating just one REST method:
POST /users
Are there any benefits of having two seperate methods other than being more RESTful?
It's more clearer to using different resources for different actions.
By REST ideology - PUT Idempotent method and POST not Idempotent. So each POST request should return new item in response, but PUT should return the same item in response.
I think it's a good when behavior is expected.
But if you write documentation for your api, you can using one resource for both actions (but I would choose the first option).
The data access layer supporting upsert does not mean that the REST API should support it, too. I would not overload POST /users with two meanings. Stick to two different resources.
Edit:
POST /users has the general meaning of 'add a new instance to the resource collection'. I see no way to extend this to '... or update existing instance if an ID is given'. /users is the collection resource, not a single resource you want to manipulate. Doing a POST to a collection resource should manipulate the collection, not a single existing resource.

How to ensure that all WebAPI/OData requests pertain to a specific user?

I found this process simpler when consuming a WCF service (SOAP), but here goes...
Where Users 1..* Categories:
In exposing an OData RESTful service (MVC4, WebAPI, OData), client-side code could be issued like:
/odata/Categories?$filter=startswith(CategoryName,'paid')
Or even
/odata/Categories
Would return all categories for all users. Not very secure.
I want to ensure that all requests issued when a user is logged in (I'm using forms authentication with my own custom role provider) only return data related to that user (where userID=x). Is there a custom filter that needs to be created, whereby even if a logged in user saw the outgoing WebAPI/OData request paths (often defined in JavaScript), they can't try to get other user's information?
Each navigation property or related table in the db has a UserID field where the "AND UserID=x" could be used.
Would this involve creating some sort of FilterQueryValidator (actually query addition) similar to what's found at the bottom of this page?
I'm just not sure on how this works, and would like some pointers.
FYI: This may be related to this other question, but more specific on user-based requests.
You can use a filter attribute or you can override GET / POST etc in your ODataContoller to add the UserID == X to the Linq expression.
e.g.
public override IQueryable<Product> Get()
{
return _context.Products.Where(x => x.UserID == user_id);
}

Meteor: difference between names for collections, variables, publications, and subscriptions?

In the Discover Meteor examples, what's the diff between "posts" and "Posts"? Why is it that when we do an insert from the server we use "posts" but when querying from the browser we use "Posts"? Wouldn't the system be confused by the case differences?
I see the variable assignment for client Posts to the server posts in posts.js. Is it a conventional notation to capitalize client and use small caps for server?
Posts = new Meteor.Collection('posts')
Why does server/fixtures.js use "Posts"? I was under the assumption that we query "Posts" in the browser (client), and use "posts" in the server, like we did in meteor mongo. So why are we now using Posts in the server?
Let's distinguish between the different names you might have to deal with when programming Meteor:
Variable names, such as Posts = new Meteor.Collection(...). These are used only so your code knows how to access this variable. Meteor doesn't know or care what it is, although the convention is to capitalize.
Collection names, such as new Meteor.Collection("posts"). This maps to the name of a MongoDB collection (on the server) or a minimongo collection (on the client).
Publication and subscription names, used in Meteor.publish("foo", ...) or Meteor.subscribe("foo"). These have to match up for the client to subscribe to some data on the server.
There are two things you need to match up in the Meteor data model:
Names of publications and their corresponding subscriptions
(usually) Names of collections on the client and server, if using the default collection model
A subscription name needs to always match up with the name of a publication. However, the collections that are sent for a given subscription needn't have anything to do with the subscription name. In fact, one can send over multiple cursors in one publication or one collection over different publications or even multiple subscriptions per publication, which appear merged as one in the client. You can also have different collection names in the server and client; read on...
Let's review the different cases:
Simple subscription model. This is the one you usually see in straightforward Meteor demos.
On client and server,
Posts = new Meteor.Collection("posts");
On server only:
Meteor.publish("postsPub", function() {
return Posts.find()
});
On client only:
Meteor.subscribe("postsPub")
This synchronizes the Posts collection (which is named posts in the database) using the publication called postsPub.
Multiple collections in one publication. You can send multiple cursors over for a single publication, using an array.
On client and server:
Posts = new Meteor.Collection("posts");
Comments = new Meteor.Collection("comments");
On server only:
Meteor.publish("postsAndComments", function() {
return [
Posts.find(),
Comments.find()
];
});
On client only:
Meteor.subscribe("postsAndComments");
This synchronizes the Posts collection as well as the Comments collection using a single publication called postsAndComments. This type of publication is well-suited for relational data; for example, where you might want to publish only certain posts and the comments associated only with those posts. See a package that can build these cursors automatically.
Multiple publications for a single collection. You can use multiple publications to send different slices of data for a single collection which are merged by Meteor automatically.
On server and client:
Posts = new Meteor.Collection("posts");
On server only:
Meteor.publish("top10Posts", function() {
return Posts.find({}, {
sort: {comments: -1},
limit: 10
});
});
Meteor.publish("newest10Posts", function() {
return Posts.find({}, {
sort: {timestamp: -1},
limit: 10
});
});
On client only:
Meteor.subscribe("top10Posts");
Meteor.subscribe("newest10Posts");
This pushes both the 10 posts with the most comments as well as the 10 newest posts on the site to the user, which sees both sets of data merged into a single Posts collection. If one of the newest posts is also a post with the most comments or vice versa, the Posts collection will contain less than 20 items. This is an example of how the data model in Meteor allows you to do powerful data merging operations without implementing the details yourself.
Multiple subscriptions per publication. You can get multiple sets of data from the same publication using different arguments.
On server and client:
Posts = new Meteor.Collection("posts");
On server only:
Meteor.publish("postsByUser", function(user) {
return Posts.find({
userId: user
});
});
On client only:
Meteor.subscribe("postsByUser", "fooUser");
Meteor.subscribe("postsByUser", "barUser");
This causes the posts by fooUser and barUser to both show up in the posts collection. This model is convenient when you have several different computations that are looking at different slices of your data and may be updated dynamically. Note that when you subscribe inside a Deps.autorun(...), Meteor calls stop() on any previous subscription handle with the same name automatically, but if you are using these subscriptions outside of an autorun you will need to stop them yourself. As of right now, you can't do two subscriptions with the same name inside an autorun computation, because Meteor can't tell them apart.
Pushing arbitrary data over a publication. You can completely customize publications to not require the same collection names on the server and client. In fact, the server can publish data that isn't backed by a collection at all. To do this, you can use the API for the publish functions.
On server only:
Posts = new Meteor.Collection("posts");
Meteor.publish("newPostsPub", function() {
var sub = this;
var subHandle = null;
subHandle = Posts.find({}, {
sort: {timestamp: -1},
limit: 10
})
.observeChanges({
added: function(id, fields) {
sub.added("newposts", id, fields);
},
changed: function(id, fields) {
sub.changed("newposts", id, fields);
},
removed: function(id) {
sub.removed("newposts", id);
}
});
sub.ready();
sub.onStop(function() {
subHandle.stop();
})
});
On client only:
NewPosts = new Meteor.Collection("newposts");
Meteor.subscribe("newPostsPub");
This synchronizes the newest 10 posts from the Posts collection on the server (called posts in the database) to the NewPosts collection on the client (called newposts in minimongo) using the publication/subscription called newPostsPub. Note that observeChanges differs from observe, which can do a bunch of other things.
The code seems complicated, but when you return a cursor inside a publish function, this is basically the code that Meteor is generating behind the scenes. Writing publications this way gives you a lot more control over what is and isn't sent to the client. Be careful though, as you must manually turn off observe handles and mark when the subscription is ready. For more information, see Matt Debergalis' description of this process (however, that post is out of date). Of course, you can combine this with the other pieces above to potentially get very nuanced and complicated publications.
Sorry for the essay :-) but many people get confused about this and I though it would be useful to describe all the cases.
You decide the naming conventions, and meteor doesn't care.
Posts becomes a collection of documents from the mongo server. You find posts by calling Posts.find({author: 'jim}). In the example you wrote, meteor is being told to internally call that collection 'posts'. Hopefully this is easy to remember if the names are similar...
There needs to be a way to express and track what info is available to clients. Sometimes there may be multiple sets of information, of varying detail. Example: a summary for a title listing, but detail for a particular document. These are often also named 'posts' so it can be initially confusing:
Meteor.publish "posts", -> # on server
Posts.find()
and then
dbs.subscriptions.posts = Meteor.subscribe 'posts' # on client
publication and subscription names must match, but it could all be named like this:
PostsDB = new Meteor.Collection('postdocumentsonserver')
so in mongo you'd need to type
db.postdocumentsonserver.find()
but otherwise you never need to care about 'postdocumentsonserver'. Then
Meteor.publish "post_titles", ->
PostsDB.find({},{fields:{name:1}})
matching
dbs.subscriptions.post_titles = Meteor.subscribe 'post_titles'

Enrich Mongo documents in Meteor server-side when inserted from client-side?

I can't find anything in the docs, but in case I'm missing something, is there any way in Meteor to enrich documents inserted from the client on the server before they're sent to Mongo.
The use-case for this is to handle things like setting up timestamps and other (for server-side use only) fields, without having to set them as part of the document on the client.
The obvious method would be to use Meteor.call('addMyNewRecord', publicFields) then insert solely from the server-side, but I quite like having the minimongo api on the client-side and I'm hoping to avoid the call requirement. I know in CouchDB you can do some basic modifications in their on-update handler but can't seem to find anything similar for Meteor/Mongo.
I finally found a nice approach to doing this whilst still using the minimongo interface on the client-side.
It seems you can intercept the insert and enrich the documents as part of the Deny policy, like this:
myCollection.deny({
insert: function(userId, doc) {
doc.created = new Date().valueOf();
doc.creator = userId;
//other default fields
return false;
}
});
I've tried to do similar with the update Deny policy to add a modified field but that doesn't seem to work the same way. As noted in the post linked above, this won't work for the Allow policy.