How to avoid collisions with GAE Google user IDs? - google-app-engine

Google App Engine provides user IDs from the Users service which are only promised to be:
an opaque string that uniquely identifies the user represented by this User object.
as per: https://developers.google.com/appengine/docs/java/javadoc/com/google/appengine/api/users/User#getUserId()
These strings always seem to be numeric with a length of 21 characters. Is there any guarantee from Google that they will always be numeric or any other promise more specific than just a String?
I ask because we'd like to store them alongside user IDs from other login providers such as Facebook and want to be sure that there will not be a collision if only the Facebook IDs have a prefix and the Google User IDs remain as is.

If you consistently add "g_" prefix to Google ids and "f_" prefix to Facebook ids, all ids will always be unique, even if you encounter a Google id that starts with "f_".
Note, however, that we decided against the approach that you are taking, because (a) users may change their accounts linked to our app (and we don't want to change their datastore id and update all references in such cases, even though it's a rare usecase), and (b) we allow users to connect more than one external account to an account in our app.

If you want to guarantee no collisions between IDs from multiple different providers/APIs, you should add prefixes to both types to ensure that. When an API says it's an opaque string, it is explicitly not making guarantees about what the content of the string may be. Just because it is consistently a number now doesn't mean it will continue to be a number in the future.

Related

What is the right way to maintain user audit in a system designed to use external authentication?

I am using AWS cognito for user authentication in the application that I designed. And where ever there is a need for user audit in the application, I have used the id from cognito as if it is a foreign key from another table(I am using a relational DB).
Even though this works, this approach somehow feels improper. Is there any other proper way to design this?
In my application, the user logs in with his email address (common scenario). Hence, by construction the email address is a unique identifier both in cognito and in my database.
My database creates a user id for each new user, and that is the main identifier I use in my app (note that this identifier has nothing to do with cognito).
Cognito also assigns an id to each user (which it calls "username"), but I never reference that id (nor have I ever felt the need to reference it). I have been in production for several years, and I have never regretted this decision.
Upside of not linking user ids:
full flexibility (e.g. I can decide that I want to create a new user Object in my database for a particular cognito user. I can keep the previous user e.g. as a backup, even though it is not linked to the cognito user).
less work: i don't need to make sure the ids in my system are in line with those in cognito.
Downside of not linking user ids:
maybe it's faster to query cognito using the username field than the email field? maybe that could be an advantage for some use cases?

Google Places API: store Places in DB

I am building a web app where all the users belong to some type of places, lets say "bank". Each user belongs to only 1 bank but 1 bank can have more then one user.
I need to display their bank name and location in user profile and to be able to search by bank names inside specific city. So I need to connect users and banks somehow.
Is it safe to use the Place ID for that for each bank in terms of app scalability and life-cycle?
The manual says:
Place IDs are exempt from the caching restrictions stated in Section
10.5.d of the Google Maps APIs Terms of Service. You can therefore store place ID values indefinitely.
So Google says I can but is it the best practise? Do I need to store a full address additionally to be safe in case Google will deprecate these IDs in future?
Let's say I can get the bank Place ID with the help of Place Autocomplete during the user registration. Then I need to save it to DB to be able to display it later and search by bank.
The DB Structure could be:
Or Just
But I think the 1st way it better with unique place_id column?
As Google says, you may store PlaceID, but they also tell you that it is a good practice to "refresh" these stored PlaceIDs each 100 days, they do not assure you that your stored PlaceID will be for the same place that you stored.
https://developers.google.com/places/place-id

Is it safe to publish keys from App Engine's NDB?

I have a RESTfull service to store and retrieve JSON. Payloads are stored in NDB, so in order to access an entity the user has to provide the key. Is it safe and secure to return ndb.Model.key().urlsafe() upon entity creation or should I develop my own unique ID?
As usual, this depends. If you're returning this key to the user, they can find the entity name and identifier of that object. If you're also accepting these keys from the user in a future request, they could construct one to point to any object in your datastore, so you must do any required permission/type checking before loading an object for a key they pass to you.
There's also the issue that if you later decide you want to change, say, how you store those models, you are a bit stuck by the fact that you've exposed an implementation detail by sending down the NDB key to the user. Generating your own unique ID might be better if you're worried about your users holding on to those identifiers for a long time.

Evernote users in the application database

What's the best practice or the common way of keeping (or not keeping) Evernote users in your application's database?
Should I create my own membership system and create a connection to Evernote accounts?
Should I store Evernote user data (or only part of it) in my own app and let the user log in only with Evernote?
Summary: you must protect their data but how you protect it is up to you. Use the integer edam_userId to identify data.
I think the API License agreement covers protection in the terms:
you agree that when using the API you will not, directly or indirectly, take or enable another to take any of the following actions:...
1.8.4 circumvent or modify any Keys or other security mechanism employed by Evernote or the API;
If you cache people's data and your server-based app lacks security to prevent people looking at other's data, then I think you're pretty clearly violating that clause. I think it's quite elegantly written!
Couple that with the responsibility clause 1.2
You are fully responsible for all activities that occur using your Keys, regardless of whether such activities are undertaken by you or a third party.
So if you don't protect someone's cached data and another user is able to get at it, you're explicitly liable.
Having cleared up the question of your obligations to (as you'd expect) protect people's data, the question is how do you store it?
Clause 4.3 covers identifiers pretty directly although it's a bit out of date now that we are all forced to use oAuth - there are no passwords ever entered into anything other a web view. However, mobile or desktop client apps must provide a mechanism for the user to log out, which must completely remove the username and password from your application and its persistent storage.
For a web app, you can't even save the username: If your Application runs as an Internet service on a multi-user server, you must not ask for, view, store or cache the sign-in name or password of Evernote user accounts.
The good news is that you can rely on the edam_userId value which comes back to you in the oAuth token credentials response, as discussed here.
When you look at the Data Model, you can see the unique id under the User and going into the User struct, see the reassuring definition The unique numeric identifier for the account, which will not change for the lifetime of the account.
Thinking about the consequences, as you can't get the user id until you have logged into the service, if you want to provide a local login for people you will have to link your local credentials to the user id. That may irk some people if they have to enter a username twice but can't be helped.
You can allow users to log-in via OAuth. Here's a guide on how that process works.
But you'll probably also want to store a minimal amount of user data, at least a unique identifier, in your database so you can do things like create relationships between the user and their notebooks and tags. Refer to the Evernote data model for those relationships. If you're using rails, this will also help you take advantage of rails conventions.

What should i store as UserName from DotNetOpenAuth

Im using DotNetOpenAuth to integrate Google,Yahoo,Twitter and Facebook Logins into my application.
Now everything works as expected.
Twitter returns -> User-name and Claim-identifier(Just Id)
Google returns -> Email-Address, First and last Name and ID(URL+ID)
Yahoo returns -> Email-Address, Alias and ID (Url + ID)
Also im also allowing my users to register internally so my database User table is like this:
ID,UserName,Name,OpenID,LoginType,DisplayName
im wondering what i should be storing as User-Name, i was thinking of the ID, but i have this questions:
Shall i store the whole ID as User-Name ?!
Would it affect performance to store the whole ID(URL) as username?
If i extracted the ID from the Claim-Identifier would it still be unique between all 3 providers?
For OpenID, you must use the ClaimedIdentifier as the ID. Not anything else, and certainly not only a substring from the claimed identifier. Anything else seriously compromises the security of your application.
As far as where you store it, I would recommend you keep a dedicated column for storing your claimed identifier rather than just storing it in your UserName column. Consider this scenario:
A user creates an account with your web site using an OpenID http://SomeOpenIDUrl
An attacker logs in via the username/password form. He leaves the password blank but enters http://SomeOpenIDUrl as the username
The attacker successfully logs in as his victim.
A situation like the above can be mitigated in various ways of course, but the best way IMO is to keep the OpenID out of the username column so that it's completely impossible.

Resources