Before I go into the issue I am having I'd like to provide you with some context. Currently I have users and sessions. Users are the what you would normally think of when you think of users, however sessions can be thought of as meetings. These meetings can be marked as private, in which case I have Firebase Database security rules in place which prevent users from reading and writing to the meeting unless they are a part of it. In app invites are the only way to get invited (originating from the organizer)
Until Now, here's the problem: I would like to use Dynamic links to invite users to sessions by linking straight to the session, however I don't know how I would model this in database security rules.
Does anyone have any idea how I would say: "Anyone that was invited here from a dynamic link has access to invite themselves to a session"? In this case I guess the issue is that I don't know who the user will invite.
Looks like I solved my own problem using my previous comment. I decided to generate a new push key and distribute the key using dynamic links.
What does this look like in the DB?
I created a path in firebase to hold the session's random key:
dynamicInvites/sessions/{sessionId}
"somerandomkey"
and a path to hold the key distributed to users
dynamicInvites/users/{userId}
{
"somerandomkey": {timestamp}
}
In addition there are security rules that say that session X and random key for session X cannot be read unless user A has the random push key for session X or they are a member of the session.
How did you distribute the key?
Since users of the session have access to the random key they can generate a dynamic link with the random key and sessionId as querystrings.
When the user clicks the link they are redirected to the app which pulls the random key and session id from the link and puts the random key under their dynamicinvites user path along with the current time and then opens the session using the session id. The current time is used in the event that I want to perform some type of periodic cleanup of these keys.
Why use a separate push key and not the one from the session?
The push key for the session is in multiple places in the DB and is not considered private as it may be loaded to the client.
Performing a DB update at app startup is not user friendly though
I masked this time using a splash screen when the user clicks the link. Since I have a splash screen at normal startup time this is the normal behavior that users will expect.
Related
I am developing an app for my college and there are different types of users called students ,teachers , hod's
etc. When they login, how do I know a teacher logged in, or a student logged in? Is there any function in firestore for role based signups and signins?
I was thinking that when a teacher signs up, I will add a tag end of her uid.username that if username is 'DANIEL' while signup, I will add a tea for teachers and stu for students at the end of the name what they provided.
So when they login i will get the uid and do the string manupulations and get the last three letters so that i can know who logged in so that i can show different UI to Different types of users
Is there any best way to do like this ?
while singning up user enters his username example:"daniel"
i will update that username in uid.username like this "daniel-stu"(if student signed up),"daniel-tea" if techer signsup.
Storing this information in the user's display name can work. You can read it back from there next time, and take action in your application's client-side code. But note that this means that any user can change their role, since they can also call the same code to update their profile. If that is not a concern for your app, then this approach sounds like it would work.
If malicious users should not be able to change their role, then you shouldn't set that role from the client-side application code. In that case, you can set the role from a server (or your development machine, or Cloud Functions) using the Admin SDK. Since the Admin SDK runs in a trusted environment, it has expanded privileges and can update the profile of any user. So the Admin SDK could update the display name of the user in the same way you have in mind.
But this still isn't secure, since you're still setting a property that anyone can modify for their own profile. Again... if that is no problem for your app that is fine, but if the use-case requires that you can rely on the property to be correct, we have to keep looking elsewhere.
The Admin SDK can set additional so-called claims on a user profile that client-side code can't modify. Such claims are for things that affect the permissions of the user, such if the user is an admin, or what role/group your users belong to. This sounds quite close to what you are describing, so can also be used. And this time, only your code that runs in a trusted environment will be able to do so.
Finally, you could store the additional information about a user in the database. It's quite common to have a collection (Users or Profiles) in the database, where you store a document for each user (with the document name being User.uid). You create the document when the user first signs in, and update whenever you need to. You can do this from the client-side code (if there is no need to control what gets written), or from code that runs in a trusted environment (such as your development machine, a server you control, or Cloud Functions) if you do need to keep control. A big advantage of this approach is that all users can potentially see the information in this collection, where the client-side Authentication SDK only allows a user to read their own user profile.
For more on this, see:
Adding new data to firebase users (in which I essentially list the same options with fewer words)
Add extra User Information with firebase (store the information in the realtime database)
Associate Firebase Users to Database Records (also using the realtime database for the additional information)
Cloud Firestore saving additional user data
this video explaining custom claims
and many more previous questions on this topic
i've read all the tutorials and questions asked about the subject but they contradict one another
claims(userclaims and roleclaims) are serialised into a cookie (along with custom identity user properties you specify by overriding the principle factory) but they don't get queried, they're stored in a cookie, which mean that the more claims a user have, the more data will have to round trip between the server and browser
a custom identity user property by default don't get serialised but get queried from the database, so every time you need that data it query it from the database which is more work to do on the database on each request if you frequently query for it
so which is more efficient and which is safer
for instance
IsAdmin should be a role/claim? but then if someone stole the cookie, nah nah, the cookie already contains userid/username/securitystamp, so even if it's a property, the userid on the stolen cookie would query on the custom identity user property, or is there something that will prevent this cookie from working when stolen ?
another instance
if i've 20 property for the user (first name, last name, address 1, address 2, postal code, whatever the case may be), should i simply have the user wait a bit for a bigger slower cookie to be send back and forth or should i do all the work from the db using custom identity user
but then, if i remove or add a claim to the user, would it be updated on the next request if it doesn't get queried or is the security stamp validate that this cookie is still valid ?
cause at the Task AddClaimsAsync of the userstore of efcore it only add the claim to the dbset
i apologize i know this is many questions to ask but the resources on the matter are not that good and one can easily get lost reading the identity source
Rule of thumb - put frequently added items as a claim, everything else can live in DB and be queried on demand. I.e. address 1, address 2 can't be required on every request, so keep them in the DB.
On the other hand IsAdmin (should be a role anyway) I can imagine will be checked on every request, so it should be in the cookie without having to query the db.
If you afraid of your cookies getting stolen, don't show them to anyone! set up SecurityStampValidator to do frequent checks - like every 5 minutes. This basically updates the cookie with the fresh information from your database and changes the cookie. So even if the cookie is stolen, it will only work for 5 minutes.
I don't think the two statements contradict, it depends on your configuration. The second statement mentions "by default".
You do not need to store all information in claims nor do you need all the information all the time. If you want profile information, call the server once and store the information on the client, or get it when needed only.
The same counts for authorization, in case you want to show / hide elements based on permissions. This may include a tag called "IsAdmin". Authorization should be kept close to the resource.
If your client wants to refresh the information, just call the server. Claims are not updated during each request. In general, the user has to log out and log in again. So Claims are not flexible and therefor not really suitable for properties that can change (frequently).
As for safety, it doesn't really matter that the client can alter the information, it is for display only. It doesn't change the permission in the backend.
You can consider to add something like a display name to the properties, if you are showing that in every page. You can also consider to implement caching to limit database calls. In the end it really depends on your requirements.
As for stolen cookie, you'll need to implement additional security to your server to detect suspicious behaviour. You may want to include the ip address as claim. As for the admin, add security, e.g. filter by ip address and / or use an additional code which was send by email.
When I create a firebase reference and take a snapshot of that reference while authenticated through firebase authentication then I log out, that data remains.
Requirements:
Page cannot be reloaded or force reloaded after logout
Cannot Clear Firebase Session or all data will need to be reloaded
Must clear only the data that was accessable to the user and not to the public
Must also reload data that is owned or is in the same group as the non-escalated or guest user after the other user has logged out.
I am considering creating objects that wrap my references that will supply a user group and other permissions property as is commonly seen on linux. This will allow me to use the current user object that provides group and user details as a base for deactivating or clearing local data.
Is there a standard way of doing this?
Am I making more work of this than is needed?
I will be hardcoding the knowledge of what groups have permission on the clientside to be replaced later with metadata provided by firebase. I plan to eventually keep track of all references available to a specific user under the user id as well as keep track of the references available publicly and as well again keep track of references available to specific groups where the highest permissions takes priority.
Step one I am taking is creating a way to manage the references clientside and build in checks for authentication change and then utilizing the user details provided in the current auth apply needed changes with authenitication change kicks off. Is it easier to just initiate another call to the server for that snapshot, will that snapshot change if it is no longer authorized?
You control your own app and the prefs based snapshot (or wherever else you save the data) is under your app control as well. Assuming that whatever local storage is protected to your app only (whether natively by Android OS such as private prefs or otherwise), you can simply save the local cache under the user id of the currently authenticated user. So your app can check if the authenticated user matches that user id of the cache and if it does not, then access is denied. In fact, the local cache should be keyed minimally by the logged-in user so you get that kind of check for free (basically the snapshot data won't be found).
I've a pretty basic question related to user profile storage along a session.
Let's say that I've an Account table that stores user profiles and that I've linked this table to ASP.NET SimpleMembership. Once a user is logged in, controllers may need to retrieve information in or based from her Account. What I'm doing right now is querying the database each time I need data, with something similar to this: _dbContext.Accounts.Where(a => a.EmailAddress == User.Identity.Name).Single().
But I'm afraid that this may cause unnecessary load on the DB and think that a better idea (perhaps it's what everybody does!) is to store the Account object in a Session variable once a user logs in, enabling direct access without re-querying the DB.
Is this the usual way to do it? Isn't there a risk of "de-sync" between the Session variable and the authentication?
Thanks
Our website uses this same type of method for a user-type object at login. Upon confirmed login we store the user object in a session variable. If something is changed or updated the object is updated and depending on the circumstance the change is updated in the database as well (timing meaning update immediately following the change or, after gathering a group of changes).
It just depends on how complex your system is. Ours is fairly complex, and this has proved to be a pretty solid way - without requiring constant maintenence and updates.
Here is my problem if i can call it that way.I have implemented authentification with custom memebership provider in asp.net mvc 2.0.Everything works well but i have one problem.When user log in he provides its username and password and i check this through databse in MSSQL then i validate user and pass and use FormsAuthentication to set only UserName as profile information.
But when that user wants to create new item(lets say for sale or something) that belongs only to him and can be listed with other items that user created i can use this username(in FormsAuthentication) check it in database and connect that item to appropriate user with foreign key but that works if username is unique so i need additional informations like ID column from database table "user" to store and use it later so what is the most secure and "best practice" way to store additional information of user and use it later because username as i mentioned must be unique in database and it is not enough information about logged user.
Couldn't you store the User object (or whatever additional info you have) in the Session? or using a cookie at the client side (if you need to persist the login state even after the user closes his browser etc)? Let me know if you need specific examples.
EDIT: After reading your comments, if you are looking for a "secure cookie" solution have a look at this: http://www.codeproject.com/Articles/13665/HttpSecureCookie-A-Way-to-Encrypt-Cookies-with-ASP
I use it to store the user's id (only his id). When I retrieve this cookie I load the user given his id. Some in-memory caching allows me to avoid loading the user on each request.
But just wanted to clarify that the session object seems great for what you are trying to do + you dont have to worry about security (for the average app that is).