How to authorize user to update only a document that matches his `_id` in CouchDB? - authentication

I'm trying to model a profiles database, where every profile is public for authenticated users, and where each user can only update his/her own profile.
Each profile document _id will be the email of the registered user, and I modeled the following validate_doc_update function:
function(newDoc, oldDoc, userCtx, secObj) {
var id = userCtx.roles[0].substring(5);
if (newDoc._id !== id) {
throw({forbidden: "One can only update one's self document."});
}
}
I tested the database and it worked perfectly as I expected. Am I getting this right? Is there any flaw or breach?
(I'm using SuperLogin for creating and login-in the users)

Yes, this is a viable solution. I'd check for the roles prefix to be "user:" just to be safe, and maybe you can also allow users with the role "_admin" to edit any document.
One possible problem with your solution might be that you are probably exposing the email addresses of all your users if you use the email as the id. But if you're ok with that in your particular use case, your solution is fine.

The key here is SuperLogin. It creates a document in the _users database to represent a session of a given user.
When the user logs in, SuperLogin creates a new session that inserts a document that looks like this:
{
"_id": "org.couchdb.user:iwn9IpwNR4i0wrxmYcGarg",
"_rev": "1-0f36c9e220c41fe54726cdd01adcdcf2",
"password_scheme": "pbkdf2",
"iterations": 10,
"type": "user",
"name": "iwn9IpwNR4i0wrxmYcGarg",
"user_id": "aasaaaaaaaaaaaaaaaaaaaandremiramor#gmail.com",
"expires": 1458027109739,
"roles": [
"user:aasaaaaaaaaaaaaaaaaaaaandremiramor#gmail.com",
"user"
],
"derived_key": "9a6cfaaac2249ef74fba599c3fbede65a48dcd32",
"salt": "1ef2689337699061b9460f6f68f63f28"
}
The roles array is also created by SuperLogin using the username. Since I had it configured to use the email as the username ({emailUsername: true}), the e-mail was could be matched as the corresponding document _id.

Related

How do I insert into a user column in a SharePoint list using Graph API?

I am trying to create an item in a SharePoint list using Microsoft Graph API and all the fields are inserting except when I add a user column I get the following error:
"code": "generalException",
"message": "General exception while processing".
Based on research, to insert into a user column the user's LookupId is required. My request body for the user column is as follows:
{
"fields": {
"[ColumnName]LookupId": "12"
}
}
If anybody could advise what I'm doing wrong or if I can insert using the user's email that would be better.
Cheers.
Everything is good with your request, but this body will work only for lookup/user columns where setting "Allow multiple selections" is false. I guess in your case it's true.
You can check it with the endpoint
GET https://graph.microsoft.com/v1.0/sites/{{SiteId}}/lists/{{ListName}}/contentTypes?expand=columns(select=name,type,personOrGroup)
where personOrGroup.allowMultipleSelection will show the flag.
For user or lookup type column where multiple selection is allowed, use the following body (and obviously you may pass multiple values in array):
{
"fields": {
"[columnName]LookupId#odata.type":"Collection(Edm.String)",
"[columnName]LookupId":["12"]
}
}
As for referring to user fields with email, I don't think it's possible with Graph API, but you may check Sharepoint REST API v1 if it supports that

How to allow firebase user to only access documents that they created

This, to me, is the most basic authentication scheme for user-generated content, given a collection called "posts":
Allow any authenticated user to insert into "posts" collection
Allow the user who inserted the document into collection "posts", to read, update, and destroy the document, and deny all others
Allow the user to list all documents in collection "posts" if they are the one who created the documents originally
All examples I've found so far seem to rely on the document ID being the same as the user's id, which would only work for user's "profile" data (again, all the examples seem to be for this single limited scenario).
It doesn't seem that there is any sort of metadata for who the authenticated user was when a document was created, so it seems i must store the ID on the doc myself, but I haven't been able to get past this point and create a working example. Also, this opens up the opportunity for user's to create documents as other users, since the user ID is set by the client.
I feel like I am missing something fundamental here since this has to be the most basic scenario but have not yet found any concise examples for doing this.
This answer is from this github gist. Basically, in the document collection posts there is a field called uid and it checks if it matches the users uid.
// Checks auth uid equals database node uid
// In other words, the User can only access their own data
{
"rules": {
"posts": {
"$uid": {
".read": "$uid === auth.uid",
".write": "$uid === auth.uid"
}
}
}
}
-- Edit --
DSL rules
match /Posts/{document=**}{
allow read : if uid == request.auth.uid;
allow write: if uid == request.auth.uid;
}

RavenDB Authorization Bundle proper user of SecureFor

I am attempting to use RavenDB's authorization bundle to limit the results of a query (on WorkItems) by the permissions that have been explicitly set on WorkItem documents.
For example:
I have a user bob#bob.com with a userId of /users/1 and a WorkItem that has the following permissions set in the Meta-Data:
"Raven-Document-Authorization": {
"Tags": [],
"Permissions": [
{
"Operation": "/Operations/WorkItem/Search",
"User": "users/1",
"Role": null,
"Allow": true,
"Priority": 1
}
]
}
I would then expect the following code to limit a query (from Bob's perspective) to this one WorkItem, because that is all he has permission to.
using (var session = documentStore.OpenSession())
{
session.SecureFor("raven/authorization/users/1", "/Operations/WorkItem/Search");
var workItemsQuery = from wi in session.Query<WorkItem>()
select wi;
var debts = workItemsQuery.ToList();
// do something with the work items
}
I based my code on the following example from RavenDB's documentation (Context & User section): http://ravendb.net/docs/2.5/server/extending/bundles/authorization-bundle-design
What I am getting instead is WorkItems that have no explicit permissions set. This is very puzzling to me because if I run the following code:
using (var session = mDocumentStore.OpenSession())
{
var answer = session.Advanced.IsOperationAllowedOnDocument(userId, operation, securableId);
var allowed = answer.IsAllowed;
}
allowed is true.
One additional item of note, I am attempting to ignore or simply not use the authorization bundle's concept of role and I wonder if this is having some unintended effect.
It is very possible that I am misunderstanding their example, could anyone shed any light on this subject for me? Thanks in advance.
Also, I wondered if the issue I am encountering was related to this StackOverflow question: RavenDB: Raven Query not returning correct count with document authorization, but their issue seems to be with the count and not necessarily the actual results.
Just to tiddy up this question, I will provide an answer to what was causing my problem. The issue was related to the use of "raven/authorization/users/1" syntax. When I changed the search command to simply use, "users/1" it worked correctly.

SimpleMembership updating the "isconfirmed" flag

My Users table (the one that I created) has the following columns:
UserId,UserName,FirstName,LastName,DOB
After I ran this command
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "Users", "UserId", "UserName", autoCreateTables: true);
it created the required simple membership tables for me.
How would I go about "UnConfirming" an user or setting the "IsConfirmed" flag to false in the webpages_Membership using the new SimpleMembership API?
(Earlier, before going to simplemembership using the "Membership" class I could update an user using the api call : Membership.UpdateUser( user );)
I can't answer your question directly since I couldn't figure out a way to 'unconfirm' an account either. What I ended up doing, however, may help whoever finds this question.
I basically use Roles as a gatekeeper. Whenever I create a new account I add that user to a "User" role:
Roles.AddUserToRole(newUser.Username, "User");
I use the Authorize attribute to restrict access to my controllers (and use [AllowAnonymous] for actions that I want to be public -- like RegisterUser, for example). Then, inside each action I add a method to restrict access to only users that are in the "User" role.
if (!Roles.IsUserInRole(role))
{
throw new HttpResponseException(
new HttpResponseMessage(HttpStatusCode.Unauthorized));
}
NOTE: I'm using Web API, but if you're using MVC you should have a much easier time. Instead of manually checking if a user is in a role in each action you can just use the authorize attribute:
[Authorize(Roles = "User")]
When I want to "UnConfirm" a user I just remove them from the "User" role.
Roles.RemoveUserFromRole(user.Username, "User");
This way if a user comes crawling back I can just reactivate their account by adding them back as a User.
What I ended up doing was updating that table directly via a SQL query. Not sure if thats the recommended way of doing it, but that seemed to work for me.
(Thanks for your suggestion too).
Look at this blog post on adding email confirmation to SimpleMembership registration process, which covers how the confirmation process works. The cliff notes are that when you create a new user you set the flag that you want to use confirmation like this.
string confirmationToken =
WebSecurity.CreateUserAndAccount(model.UserName, model.Password, new { Email = model.Email }, true);
When you do this the CreateUserAndAccount method returns a unique token that you can put in an email with a link so the user can confirm that they gave you a valid email address. When they click on the link it passes the token in the URL and the controller action can then confirm the token like this.
[AllowAnonymous]
public ActionResult RegisterConfirmation(string Id)
{
if (WebSecurity.ConfirmAccount(Id))
{
return RedirectToAction("ConfirmationSuccess");
}
return RedirectToAction("ConfirmationFailure");
}
The ConfirmAccount method checks if there is an uncomfirmed token that matches in the database and if there is it sets the isConfirmed flag to true. The user will not be able to logon until this is set to true.
set requireConfirmationToken to be true: (The 4th value shown below)
WebSecurity.CreateUserAndAccount(viewModel.UserName, viewModel.Password, null, true);
Source
http://www.w3schools.com/aspnet/met_websecurity_createuserandaccount.asp

Use a single POST request to update to create two objects Bad API design?

Consider the scenario, an unknown unauthenticated user is looking at the list of nerddinners and then goes to a particular dinner, enter his name and email and clicks "Attend". This should result in two things. Create the user and create the DinnerAttendRequest for that user.
The user also has a property called FavProgLanguage which is set to the prog language property of the dinner which he wants to attend.
Assuming it is a single page javascript app which talks to an API, there are two approaches which come to mind.
1) On the client, set the users FavProgLanguage and then POST to /user with name, email and favproglanguage to create the user. Use the created UserId and POST to /DinnerAttendRequest with DinnerId and UserId to create DinnerAttendRequest.
2) POST to /somename with Name, email and dinnerId and then use dinnerId at server to populate favproglanguage of user. create user and then use userid to create DinnerAttendRequest
The first approach seems more natural/RESTful, however if the logic of computing the favproglanguage is a bit complex, all the api consumers would have to implement that logic and with the second approach that code is written just once on the server.
Which is a better approach? Is the second approach RESTful?
Your 1st design would place the burden of logic, workflow and the fav lang decision, upon the client, this would make handling the user creation and reservation a single transaction difficult and something that a client app would need to orchestrate. Your fav lang logic sounds like an important business rule that again should ideally sit at the server for re-use...
Why don't you look at having some resources like so:
Dinner e.g. { "name", "date", etc. }
Booking e.g. { "user" { NESTED USER RESOURCE }, "bookingStatus", etc. }
User e.g. { "email", "name", "fav lang", etc.}
Some example urls
/dinners/{uid}
/dinners/{uid}/bookings
/users/{uid}
Basically I would POST a Booking resource containing a nested User resource to the dinner bookings url and run the logic for checking is a user exists, creating if needed and updating their fav lang in a transaction.
So to create a booking I would POST a Booking Resource:
{
"user": {
"email": "john#doe.com",
"name": "name"
},
"bookingStatus": "requested"
}
To /dinners/{uid}/bookings
And expect a 201 created response with a response like this:
{
"uid": "4564654",
"user": {
"uid": "1234564",
"email": "john#doe.com",
"name": "name",
"favLang": "C#"
},
"bookingStatus": "booked"
}
Obviously the properties are largely just for example but hopefully this demonstrates some of the concepts and shows that a single POST can be considered RESTful...