Limit user in Fauna DB to read only his own data - faunadb

We are using FaunaDB for storing users and users movie collection. For accessing data in Fauna Functions we use secret key which is binded to Roles.
Users document looks like this:
{
username:"John Doe",
email: "john#doe.com",
userID: "124"
}
Movie Collection document looks like this:
{
userID: "124",
movies:['Titanic','Forrest Gump']
}
To query user movie collection we call fauna function with role user and specific secret key generated for that role
Call(Function("Get_users_moive"), '124')
I would like to know is to possible to limit user, to query only his own data? In the function above if I give another userID it will retrun another user collection.
Thanks

You can certainly do this in Fauna. You can create "identity" documents in a Fauna database, and give those documents credentials that can be used to authenticate the user. Once a user authenticates, the secret for a token is created. From that point, the user can directly query Fauna using that secret, if you choose to allow them to do so.
In addition, Fauna has attributed-based access controls (ABAC). You define a role, which has two primary features: a privileges definition that lets you control which collections, indexes, documents, etc. that a user with the role has, and a membership definition which lets you specify which identities belong to the role.
A role's privileges and membership definitions can use predicates: functions that can make a dynamic determination of whether a privilege, or the membership should apply to the current query.
You can find out more in the documentation:
Tokens
ABAC
To ensure that a user can only access movie records that they created, you'll need to store a reference to the identity document within each movie document.
When a user uses the secret for the token that they acquired via the Login function, a role predicate can use the CurrentIdentity function to retrieve a reference to the associated identity document, and then compare that to the reference stored in the movie document. If those match, you grant read access, otherwise you don't.
For details, see:
Login
CurrentIdentity

Related

Keycloak: should UserName be used as logical key or NameIdentifier, or email address, or something else?

In an ASP.net core application I'd like to store some information linked to each user.
Users are managed by Keycloak.
What is the best field to be chosen as "logical key" (that is: the foreign key used in my information table to link the user)? Should it be Keycloak's NameIdentifier (something like a GUID: "90666d8e-5efa-49d0-ba07-86cff816f1f3"), or the username (the one used by the user when logging in), or the email address or something else?
What is the best field to be chosen as "logical key" (that is: the
foreign key used in my information table to link the user)?
The best one will be the one that can 1) uniquely identify the user and 2) cannot be changed.
Username at first looks like a good candidate; but the username can be changed (Realm Settings > Login > Edit username set to ON), albeit by default it is readonly. The same applies to email address and many of the other user attributes.
The best key will be the user ID, represented in your case by the NameIdentifier. This Key uniquely identifies the user and its value cannot be changed. This Key will be injected into the tokens (e.g., access token) under the claim sub.

Adding ASP.NET Identity to an existing project with already managed users table

I have an existing web api project with a users table. In general User is involved in some key business queries in the system (as other tables keep its 'UserId' foreign key).
These days I'm interested in adding Asp.net (core) identity. Basically I've already performed the required steps adding a separate Identity table, managing an additional db context (implementing IdentityDbContext), and also added a JWT token service. It looks that everything works fine. However I am now wondering how should I "link" between the authenticated user (which has logged in through the Identity module) and the user which is found on the other original "business related db".
What I was thinking of is that upon login, having the userId retrieved from the original Users table, based on the email which is used as the username and is found on both the original Users table and the new Identity table, and than have it kept as a Claim on the authenticated user. This way, each time the user is calling the API (for an Authorize marked action on the API relevant controller), assuming is authenticated I will have the relevant userId on hand and be able to address and query what ever is needed from the existing business table.
I guess this can work, however I'm not sure regarding this approach and I was wondering if there are any other options?
Regarding the option I've mentioned above, the main drawback I see is that upon the creation of a new user, this should be performed against 2 different tables, on 2 different DBs. In this case, in order to keep this in one unit of work, is it possible to create transaction scope consists of 2 different db contexts?
You're on the right track.
I faced similar problem
Imagine two different microservices.
Identity-Microservice(Stores identity information (Username, Password Etc...))
Employees-Microservice (Stores employee information (Name, Surname Etc...))
So how to establish a relationship between these two services?
Use queues(RabbitMq, Kafka etc...)
An event is created after User Registration(UserCreatedEvent {Id, Name etc..})
The workers microservice listens for this activity and records it in the corresponding table
This is the final state
Identity
Id = 1, UserName = ExampleUserName, Email = Example#Email Etc...
Employee
Id = 1, Name = ExampleName, Surname = ExampleSurname Etc...
Now both services are associated with each other.
Example
If i want to get the information of an employee who is logged in now.
var currentEmployeeId = User.Identity.GetById()
var employee = _db.Employee.GetById(currentEmployeeId)

Database design for individual and group sign up

I need to create a system that allows both individual users and groups (e.g., a company) to sign up for a subscription service.
The procedure for signing up for a group membership will involve a user paying for as many users as they require (e.g., 5) at sign up. Once they have paid they will be able to create these other users (i.e., have admin functions) that will be associated with this group (e.g., other members of their company). (They will be able to pay for more users for their group at a later date if they wish.) A user cannot be in more than one group. The original person that signed up on behalf of a group can assign admin roles to these newly created members.
For login purposes, I would like to have both individual users and group users in the same table of the database. For example, it could be called and have columns (to keep things simple):
user table:
user_id
username
I then thought that there must be a second table that shows the links between users (i.e., which belong to which group). Let's say that this is:
groups table:
group_id
user_id
I am guessing that this is a one-to-many relationship as many users can be in one group, but each user can be in only one group.
In order to assign the proper roles to the user that signed up on behalf of a group there would be another table called:
roles table:
role_id
user_id
This would allow some users to have permissions of admin rather than just user. I would then just have to lookup the user_id's of the admin role (a specific admin user_id) when they logged in and this would give them access to the correct people in their group.
Before I go ahead designing this database I was wondering if this is an appropriate database design to go about creating these individual and group users or if there is a better setup?
FURTHER INFO: There are two sign up forms: an individual sign up form and a groups sign up form.
For an individual, we will record their "username", their user_type (individual) and assign them a role of "user". They do not need to be assigned a group id and we will not need to convert their membership to a group membership later on.
For the user who signed up as a group using the group sign up form, we will record their "username", their user_type (group), no. of memberships purchased (e.g., 5), a group id (e.g., a unique integer) and assign them a role of "admin". Because they have purchased multiple memberships, they will be able to create/add new users to their group upto the number purchased. They can assign each new user a role of either "user" or "admin". A role of "user" in both individal and group membership has the same permissions, so there are only two types of role.
As such, I had planned a createUser() function that creates:
For an individual: username, user_type(individual), role(user)
For a group: username, user_type(group), group_id, no_purchased, role(admin)
For a new member of a group (created by admin): username, user_type(group), group_id(the same as the admin), role(admin or user)
I had then planned to create a checkUser() function that:
Gets their id, username, etc...
Checks if they are an admin or user.
If admin, then gets the users/admins that are in the same group as them.
Most calls to the database will be to login (i.e., username/password). I was looking to see what the simplest database structure would be for this situation.
I feel like you might make your life simpler if you consider individual users as groups users with only one member. This will also give you flexibility in the future if an individual user would like to expand into a group?
On the other hand you can keep it as you have it but I wouldn't bother specifying the user type. That can be derived based on if they belong to a group or not.
Many ways to tackle this problem...

Permissions design pattern that allows date-based access

I am looking at ways to implement an authorization (not authentication) scheme in my app.
There are currently two roles in the system: A and B, but there may be more. User's only have one role.
Basically, the I have it set up now is with two database tables. One is for role-based permissions on a model, and the other is for specific user-based permissions. I am thinking that this way, users can have a set of default permissions based on their role-based permissions, but then they can also have specific permissions granted/revoked.
So for example:
table: user_permissions
columns:
user_id: [int]
action: [string]
allowed: [boolean]
model_id: [int]
model_type: [string]
table: role_permissions
columns:
role: [int]
action: [string]
model_type: [string]
In the user_permissions table, the allowed field specifies whether the action is allowed or not, so that permissions can be revoked if this value is 0.
In another table, I have the definitions for each action:
table: model_actions
columns:
action: [string]
bitvalue: [int]
model_type: [string]
I do this so that when I check permissions on a model, for example ['create', 'delete'], I can use a bitwise and operation to compare the user's permissions to the permissions I am checking. For example, a model X could have the following model_actions:
action: 'create'
bitvalue: 4
model_type: X
action: 'delete'
bitvalue: 2
model_type: X
action: 'view'
bitvalue: 1
model_type: X
If my user/role permissions specify that the create, view, and delete actions for the model X are 1, 0, and 1, respectively, then this is represented as 110 based on the model_actions table. When I check if I can create model X, I use the fact that create is 4 to construct the bitarray 100. If the bitwise AND operation of 110 and 100 is 100, then the permission is valid.
ANYWAY, I think I have a granular permissions design pattern figured out. If not PLEASE feel free to educate me on the subject.
The actual focus of my question concerns the following:
Some of my models have actions that are time-dependent. For example, you can only delete a model Y no more than 24 hours after its created_at date.
What I am thinking is to automatically create a cron job when the model is created that will update the permissions on the date that this occurs. In the case of model Y, I would want to insert a record into the user_permissions that revokes the 'delete' action of this model.
My question is: is this advisable?
Edit
What if I include another row in the SQL tables, that specifies a date for the permission to 'flip' (flipDate)? If a flipDate is defined, and if the current date is after the flip date, the permission is reversed. This seems much easier to manage than a series of cron jobs, especially when models may be updated.
Your models seems fine, but... you are reinventing the wheel a bit and, as you realized yourself, your model is not flexible enough to cater for additional parameters e.g. time.
In the history of authorization, there is a traditional, well-accepted model, called role-based access control (RBAC). That model works extremely well when you have a clearly defined set of roles and a hierarchy between these roles.
However, when the hierarchy isn't as clear or when there are relationships (e.g. a doctor-patient relationship) or when there are dynamic attributes (such as time, location, IP...), RBAC doesn't work well. A new model emerged a few years back called attribute-based access control (ABAC). In a way, it's an evolution or generalization of RBAC. With ABAC, you can define authorization logic in terms of attributes. Attributes are a set of key-value pairs that describe the user, the action, the resource, and the context. With attributes, you can describe any number of authorization situations such as:
a doctor can view a patient's medical record between 9am and 5pm if and only if the patient is assigned to that doctor
a nurse can edit a patient's medical record if and only if the patient belongs to the same clinic as the nurse.
ABAC enables what one could call PBAC or policy-based access control since now the authorization logic moves away from proprietary code and database schemes into a set of centrally managed policies. The de-facto standard for these policies is XACML, the eXtensible Access Control Markup Language.
In a nutshell, XACML lets you do what you are looking for in a technology-neutral way, in a decoupled, externalized way. It means, you get to define authorization once and enforce it everywhere it matters.
I recommend you check out these great resources on the topic:
NIST's website on RBAC (the older model)
NIST's website on ABAC (the model you need)
the OASIS XACML Technical Committee website (the standard that implements ABAC)
Gartner's Externalized Authorization Management
Kuppinger Cole's Dynamic Authorization Management
The ALFA plugin for Eclipse, a tool to write attribute-based policies.

Multiple Login Feature

I am implementing a multiple login system, using Facebook, Twitter, Email.
If the user login with Facebook, he is able to merge his account with Twitter account or Email account, so next time login, he can press on "Login with Twitter" or key in email+password to login.
Now the problem is the merging.
If user created account A using Facebook login, modify some data, then create account B using Twitter login, and modify some data, this would be hard to merge, because both accounts will have different data.
What do app/site who use multiple login handle this kind of situation? Or is it me who makes it complicated?
I guess the main point is not storing any detailed account information with the login method. This is probably what your user account DB looks like now:
- account_id: …
facebook_auth_info: …
username: …
birth_date: …
- account_id: …
twitter_auth_info: …
username: …
birth_date: …
Now this schema should make it a no-op to “merge accounts”:
- account_id: …
facebook_auth_info: …
twitter_auth_info: …
username: …
birth_date: …
In other words, treat Facebook, Twitter and other as a “identity providers” and allow for multiple identity providers per your own account.
The way I would do this is to keep separated third party login details and use tables like email and third party login details interchangeable to authenticate a user. This way you can have a customer that get authorized either by using email or using a third party login. This does not mean that the same user can login either with email&password or third party provider. This I find it helpful to avoid having all the time fields for third party providers in the User table and if you want to add more login providers you don't have to alter any table, just add another entry in Types table.
For example I would use a Users table where you you keep all details for a customer but login details. No email, password or any other login details. These details are held in separate tables and are linked by the PK from this table. This table will map 1:1 to the Emails table. For example a schema might be:
- Id (PK)
- FirstName
- SecondName
- etc.
Then I'll have an Emails table where I would keep the email and password for a user. You can also have extra details like Id and Verified (to know if email is verified). Please be aware of keeping plain text passwords or keeping pairs email - password in your db. This is an important security concern and I would not discuss it here. I would also use a UserId column to map emails to users. This will map 1:1 to Users table. A schema might be:
- Id (PK)
- Email
- Password
- UserId (FK)
- Verified
To handle the third party login details I'll use a table called ThirdPartyUsers. In this table I will store a UserId to map one record from this table to one record from User tables. Basically this table can replace Email table and you can move away from holding email - password in your db. In this table I would keep a ProviderCode that is a code from types table and a ProviderId that is an Id provided by third party logins. This Ids are unique per third party providers and don't change per user. You can pair a ProviderCode with a ProviderId to make a composite key. This will map 1:1 to Users table. A schema might be:
- Id (PK)
- UserId (FK)
- ProviderCode
- ProviderId
To have a unified User account I would have a MasterUsers table where you define a User as a Master user and you define into a link table its children. Through its children I understand any account that has the same email address. This means a classic account and any third party login providers. Using this you can a unique Master and multiple children. This would map 1:1 to Users table and 1:* to MasterLinkToChildren table. A schema might be :
- Id (PK)
- UserId
To link multiple customers to one MasterUser I would use a link table called MasterLinkToChildren (or any naming you prefer). In this I would have two columns for storing UserIds for childrens and MasterId for their parent. An important thing I would do is to make any MasterUser also be a children of himself in the Link table so when you update the MasterUser you would keep consistency between your records. This will map *:1 to MasterUsers and 1:1 to Users table. A schema might be:
- MasterId (FK)
- UserId (FK)
Finally I would have a Codes table where I would store unique code for each third party login provider. This would map 1:* to ThirdPartyUsers. A schema like:
- Id (PK)
- Code (Unique)
It might look like a lot of code and many tables but in this way you can preserve unique user login or you can unify everything under one Master account. I wouldn't merge them automatically but I will offer the user the option to do that. Another thing you need to consider is not to allow users to login or merge accounts before they verified their account. I didn't use a Verified column on ThirdPartyUsers table as I don't want to verify this type of users but you can do this as well.
By using a Codes table you can extend your third party login providers without altering other tables.