Ionic and Firebase Authentication Security with Domain Restrictions - security

I'm using Ionic with Firebase Authentication (Google sign-in method) to authenticate users. I've got the authentication working. The problem is I want to only allow access to my application (login --- rather than authentication) if the user is from my company's domain (jimmy #neutron.ca).
I only want my employees logging into the app and gaining access to the interface beyond the login page. I only want my employees to be able to submit their hours (that's the scope of the application after login).
My question is, what is a secure way of authenticating a user and logging them in?
Is it secure to calculate on the client-side ionic app wether or not the user is of a particular domain after we get the authentication object back from firebase google sign-in method?
login() {
this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider())
.then(res => {
// example email object = 'jimmy#neutron.com'
// get email object, split('#')[1] on it
// if result of split (#neutron.com) is eqaul to my domain (neutron.com), which it is, then log user in
this.navCtrl.setRoot(AuthenticatedPage);
// if not, unauthenticate and present unauthorized message to user.
})
}
If this isn't secure to do in ionic on client-side, then how can we calculate it? Can firebase calculate it?

If I understand this correctly. You need to pass hd custom OAuth parameter to Google provider:
const provider = new firebase.auth.GoogleAuthProvider();
provider.setCustomParameters({hd: 'neutron.ca'});
this.afAuth.auth.signInWithPopup(provider);
However, users could still bypass that as Google doesn't enforce it (check the email domain).
You need to also enforce that via your security rules (if you are using Firebase Rules) or when you parse the ID token and verify it via Firebase Admin SDK.

Related

Able to have interactive login for calls to API Management service?

We have a backend service that can return a json result (Elasticsearch result) or an interactive browser web page (Kibana) based on the route. This service is gated behind an API Management service. Our developers need to be able to access the web page (Kibana). We are currently using a client certificate and we have it set to require this in our API definition. When browsing to the path in the browser, the user is prompted for the cert and the connection is made.
I would like to get rid of having to manage the certificate and instead use AAD to allow only users in a specific group to be able to access. I understand how to do this when making an API call. Is it possible to also have an experience similar to the cert where if the user is not logged in, they are prompted to log in, and then if they are in the correct group, access would be allowed?
Thanks
I imagine you want to enforce authentication at APIM level and not in Kibana. For that you'll have to handle two flows:
Initial flow, when non authenticated user requests URL, you should of check for persistent auth, possible in Cookie header and if not found - redirect user to login.microsoft.com.
Returning flow, when Azure AD redirects user back to APIM with a token, you'll need to validate that token and add it to Set-Cookie header, better encrypted.
And finally when any call is made also check and validate the cookie to see if it has expired.

How can I specify a security rule for firestore based on device Platform?

I have a database in firestore which is connected to a Android App, iOS App and a Website. Now for all these we need to sign in to access data.
My question is How can we specify a rule
for Android and iOS app, so that users should sign in to access data.
And another rule for Website, so that users who access website can decide whether to sign in or not but they can still access data.
Can anyone help me out?
There is nothing built in to Firebase Authentication or Cloud Firestore security rules to indicate what platform a request is coming from. To be honest, it sounds quite insecure: if a user doesn't have to sign in on your web app, what keeps all users from using that web app?
But if you really want to implement this functionality, the easiest way to do this, is to use anonymous authentication in the web app. With anonymous authentication, the user gets signed in without having to enter any credentials:
firebase.auth().signInAnonymously()
Now in your security rules, you can simply check for any authenticated user:
allow read, write: if request.auth.uid != null
This allows any authenticated user access to the data: from the web app this will be anonymous users, while from the native apps it'll be whatever sign in method you implemented there.
Once you add other sign-in methods to the web app, you can upgrade the user's anonymous account by linking the providers to a single user account.
Fair warning though that nothing stops users from creating their own app and running it against your project configuration. So they can create an Android/iOS app that also uses anonymous authentication. If you want to prevent that, things get quite a bit more complex...
Here's one way to do it:
In the web app, sign the user in with anonymous authentication. This means that the user doesn't need to enter credentials
In the web app, send a request to a Cloud Function you create.
In the Cloud Function, verify that the request is coming from your web app. I have no guidance here, since it's unrelated to Firebase.
If the request is coming from the web client, add a custom claim to the user account identifying the user as a web user.
admin.auth().setCustomUserClaims(uid, { isWebUser: true })
Once the client refreshes its token (this may take up to an hour, unless you force it to refresh), the custom claim will be present in all requests it makes. So you can from that moment on, check the claim in your Firestore security rules:
allow read, write: if request.auth.token.isWebUser == true;

Clarify some things about OAuth2.0 and Node.JS REST API

I'm currently developping a REST API with NodeJS and Express for a mobile application written with the Ionic framework.
I have a mysql database in which are stored my users.
I want my API to be safe concerning the authentication of my users and their right to access certain routes and ressources of the API.
My user can either login/register with their own credentials or use Facebook to do it.
So, this is what i'm doing right now :
A user register using one of my API's routes
When he wants to access a protected route, i use passport-http's Basic Strategy for Basic Auth.
I use it like this:
router.route('/protected/route')
.put(auth.isAuthenticated, controller.someMethod);
The auth.isAuthenticated looks like this :
passport.use(new BasicStrategy(
function(username, password, callback) {
Account.findByEmailAndPassword(username, password, function(err, user) {
if (err) { callback(err) };
if (!user) { return callback(null, false); }
return callback(null, user);
});
}
));
exports.isAuthenticated = passport.authenticate('basic', { session : false });
Then, in controller.someMethod(), i get my user object in req.user. I have a field in my DB that is type, i can check what's the type of the user and continue my request or not.
Now, using Facebook:
The client uses Facebook's Login button, authorize my app to access it's data, and then gets an access_token. It is send to my API via an HTTP request.
The API gets the token, and then start calling the Facebook Graph API to ask information about the user such as his id, email, firstName and lastName.
I send theses informations back to the client. He's able to modify his firstName and lastName if he wants. Then send it back to the API.
The API register the User.
They both works like a charm, but i'm facing some problems:
When registering with facebook, if the user id is already in the database, i consider that the user has already subscribed to my service. But how can i identify him using basic auth afterwards ?
The first question brought me to the others. I've read everywhere that Basic Auth isn't secure enough. So i was thinking about, first of all, buy a SSL certificate, then change my authentification system to OAuth 2.0.
I was thinking that if i do that, i would be able to send a token back to my user that logged in with Facebook, which would answer my first question.
But is OAuth2.0 the solution here ?
Am i doing things right with my Facebook registration ?
How does that callback stuff works when i want to login using my own users on my Ionic app ?
There's so many things that seems unclear about OAuth2.0 that i don't want to start implementing it and then figure out than it wasn't the right solution for my problem. I've always thought that OAuth2.0 was the right system to choose if you want other services to use your service. I am wrong?
Okay. So first thing first. HTTP Basic is perfectly secure if you are doing it over SSL.
OAuth 2.0 is an authorisation method.
OAuth is used when you want to make API calls on behalf of a user registered on other service. The other service has to provide the OAuth functionality for it to be usable by you. Let's say, you don't want to have a Registration function in your app but want to register users via Facebook, etc, you'll give an option to sign in using Facebook. So what happens is you are asking the user to give you access to access some of their Facebook account's info (more or less). You can read about it here: https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2
On the other hand, you can be the provider so that other services can use your service.
Many services let you create a local account and also give you an option to signup with other services like Facebook, Google etc..... The handle the cases on their backend side.
Let's say you want to give option of Sign in with Facebook, you'll have to take care of a couple of cases:
Associating Facebook Login with an already logged-in account - This is the case where someone uses an app's custom login system to create an account. Later, while they are still logged in they want to associate their Facebook account with it. For example, people can sign up to Spotify with an email address and a password, but they can later choose to associate that account with their Facebook account using Facebook Login, such as when they want to publish their listening activity to their timeline.
For this, you want to add a Facebook log in flow, like Spotify does.
One thing you have to take care is the merging of your local account and the Facebook flow account info. It is advised that you create separate tables for this as this will ease the process when you want to add more providers like Google, etc.
Merging separately created accounts with Facebook Login - In this situation, a person logged in to your app with their own credentials such as an email and password for example. Later, when the person logs out they choose to sign in to your app using Facebook Login. Your app will now have two accounts for the same person, one created via the app login system, the other created via the Facebook Login flow. In order to provide the best experience for that person, your app should attempt to merge these accounts into one.
For this you have to request for email (assuming your app requires email for registration) from Facebook. If it's the same as the email registered in your app, you can merge these accounts. If it's not the same, then you should give an option to connect existing email/account.
You should go through the following for more info: https://developers.facebook.com/docs/facebook-login/multiple-providers

how to secure azure mobile service / html - javascript

When I call an oauth provider like gmail and I get the token back, how can I make sure that all future calls I make are from that same client that did the authentication? that is, is there some kind of security token I should pass pack? Do I pass that token back everytime?
For example, if I have a simple data table used for a guest book with first,last,birthdate,id. How can I make sure that the user who "owns" that record is the only one who can update it. Also, how can I make sure that the only person who can see their own birthday is the person who auth'd in.
sorry for the confusing question, I'm having trouble understanding how azure mobile services (form an html client) is going to be secure in any way.
I recently tried to figure this out as well, and here's how I understand it (with maybe a little too much detail), using the canonical ToDoList application with server authentication enabled for Google:
When you outsource authentication to Google in this case, you're doing a standard OAuth 2.0 authorization code grant flow. You register your app with Google, get a client ID and secret, which you then register with AMS for your app. Fast forwarding to when you click "log in" on your HTML ToDoList app: AMS requests an authorization code on your app's behalf by providing info about it (client ID and secret), which ultimately results in a account chooser/login screen for Google. After you select the account and log in successfully, Google redirects to your AMS app's URL with the authorization code appended as a query string parameter. AMS then redeems this authorization code for an access token from Google on your application's behalf, creates a new user object (shown below), and returns this to your app:
"userId":"Google:11223344556677889900"
"authenticationToken":"eyJhbGciOiJb ... GjNzw"
These properties are returned after the Login function is called, wrapped in a User object. The authenticationToken can be used to make authenticated calls to AMS by appending it in the X-ZUMO-AUTH header of the request, at least until it expires.
In terms of security, all of the above happens under HTTPS, the token applies only to the currently signed-in user, and the token expires at a predetermined time (I don't know how long).
Addressing your theoretical example, if your table's permissions has been configured to only allow authenticated users, you can further lock things down by writing logic to store and check the userId property when displaying a birthday. See the reference docs for the User object for more info.

Authorized Request Origins is not restricting domain access in Firebase?

I'm building an application using AngularFire + Firebase.
To prevent new users from being created, and authenticated, from domains other than my application's domain, I'm trying to use the Authorized Request Origins feature in Firebase.
Currently, it is only configured to allow authentication from localhost. However, when I create a new user using the createUser API from my application's domain, the user gets created in my Firebase.
This should not happen since I used "err" from createUser is null.
Is there anything else I need to configure?
[Engineer at Firebase] The authorized request origins is actually only applicable to the OAuth-based authentication providers (i.e. Facebook, Twitter, and GitHub) though your confusion is definitely warranted given our current interface. E-mail and password authentication is not subject to the same origin verification because it is not vulnerable to a malicious site taking advantage of an existing login on Facebook, Twitter, etc.
Keep it mind that email / password authentication only creates a mapping of an email address to a password hash, and generates a corresponding Firebase authentication token upon login. It does not read or write any data to / from your Firebase, and your Firebase is still subject to the same security rules that you've written for your application. Feel free to reach out to support#firebase.com if you have other concerns, or we can help out in any way.

Resources