Using roles with Realtime Database (firebase) - firebase-realtime-database

I'm trying to write a project using Realtime Database (firebase) and Angular. Lately I've been trying to learn how to use roles in a project (user, manager, admin, etc.). Did I understand correctly - in the case of using Realtime Database, it is impossible to create roles. Instead, you need to use the rules in the database:
rules: {
"adminContent": {
".read": "auth.token.admin === true",
".write": "auth.token.admin === true",
}
Everything was very good until I read:
Firebase gives you complete control over authentication by allowing you to authenticate users or devices using secure JSON Web Tokens (JWTs). You generate these tokens on your server, pass them back to a client device, and then use them to authenticate via the signInWithCustomToken () method.
What does "your server" mean? I am using Realtime Database and firebase authentication and this is not enough and I need server?
Maybe there is an easier way to add roles to the Realtime Database, I just haven't found it?

Related

Datastore on Google Cloud Platform Oauth2 error and Data disappearing

I have recently lost all access to Google Cloud Platform Datastore for my app. I have records missing completely from my app and when I tried to check the data through the google cloud platform console I can no longer see any data or indexes.
I receive the following error when I try to view entities (no entities show up in the list anymore and this error appears if I try to manually enter a value in the kind field)
"Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project"
When I try to view indexes I receive a "Failed to load" error.
I have lost access to my database completely and I'm uncertain where to go from here. The app I'm using if for our CMS for our homeless charity which includes rental and tenancy information, sales information from our op shop and foodbank, and lots of client information regarding homelessness, mental health, counselling and addiction records.
Some of my clients have completely disapppeared from our system. I don't know how to save my data. Please help.
UPDATE : have been able to access datastore by updating google chrome, this has fixed the Oauth2 issue. While I can now see the data, this hasn't fixed the issue of the missing records. I'm currently migrating and updating my app from appengine ndb to cloud ndb and python 2 to python 3. I'm hoping this prevents future losses, but i've lost faith in the integrity of google datastore.

Firebase "admin user" in iOS?

Here's what I want to achieve:
I have an iOS frontend, a Vapor backend, and a Firebase storage bucket. I have an app where a small portion of the functionality is being able to add images to some Note objects. When the user attaches an image to a Note, I want to upload the image to the bucket, get the key/url where it's stored, and store that in the backend DB. All that is simple enough, except - I want the bucket to be accessible ONLY by my iOS code and my backend code, so not just publicly accessible by anyone.
The backend is covered via the service account stuff. but I'm not sure about how to cover the iOS side. Firebase generated this basic rule to prevent public access:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if request.auth != null;
}
}
}
I believe this rule allows only Firebase-authenticated users to use the bucket, but I do not plan to authenticate my users through Firebase. Is there a way I can set up rules such that the bucket is only accessible via my own iOS code? Should I essentially just create a single Firebase user, and have the app authenticate as that user on every app launch? Can I configure Firebase such that it uses some secret that allows it to perform storage operations that get past the rules?
**edited for clarity
As #jnpdx commented, have a look at Firebase's anonymous authentication, which allows you to sign in (and identify) users without asking for credentials. Based on that you'll then want to ensure that each user can only read the files they're authorized for.
While if request.auth != null may seem good for that initially, I find it's often better to start with the principle of least privilege - and for example have some form of content ownership based access rules.
Finally, also have a look at Firebase App Check which was introduced earlier this year, and works together with the attestation providers on your phone to reduce the risk of unauthorized code being used to call the Storage APIs.

Firebase Database 'Strong' rules

All,
I have been working on an Android App that uses firebase realtime database, cloud store and authentication. It's never going into production on the google play store - however I am worried that in a few days time, the access to the database will be denied because I don't have 'strong' rules - whatever 'strong' are.
Currently, the rules are set as follows:
"rules": {
".read": "auth.uid != null",
".write": "auth.uid != null"
}
}
The database and all functionality work great - what can i do to add to these rules to satisfy firebase that I now have 'Strong' rules - or at least prevent access from being denied in 30 days - as I need this app to show the functionality of the database etc.
Thanks
Automatically when you change your Firebase rules it will be propagated throughout all the database, there is no need for users to update your app, what you need to be sure is that the users have any login provider (google,facebook) because these rules are saying that only authenticated users can read and write into the database.
If you post this rules without an authentication provider from Firebase, your users will see a blank screen and they will not be able to read/write, if you have implemented a login system with any provider you would be fine

AWS web and mobile hub application

On AWS, I wish to create an application that allows a user to sign in via mobile, web or both.
I created a system using API Gateway, Lambdas and DynamoDB for the back end. I have sign in working for web using JavaScript but was having issues finding a Swift example for iOS of the same code (objective C only available). So I created a mobile hub application, imported my existing API and have a working iOS sign in.
The issue is that the iOS side uses the Mobile Hub so I now have 2 different User Pools so you can't sign up on web and log in on mobile (or vice versa).
I tried to change the settings in the iOS app to point to my web app Cognito User Pool settings and remove the secret but it errors as it can not be null or empty.
Why does the mobile hub require a client secret? The JavaScript documentation suggested was bad practice since code can be de-compiled and the secret extracted.
There doesn't seem to be any consistent documentation that explains, what I would guess, as the most common use case of a mobile and web app!
The other issue is that I can download my API client SDK for my API Gateway for use with web app and iOS app. But, the generated mobile hub app includes a REST based call? Am I going crazy here or does the official web approach not link to the official mobile approach?
So the key questions are:
Can or should I change the mobile apps to point at the original
Cognito?
if so should I remove the client secret?
can I effectively ignore the Mobile Hub after set up and use it purely for code generation? Assuming it was then working can I just use the generated client SDK for my API Gateway?
Is there a better way of setting up an iOS (later Android too) and web app?
I've spent considerable time and effort, and tried many approaches.
The "Mobile Hub" nicely sets up the user pool, identity pool, IAM roles etc.
The keys etc are mostly provided in the Info.plist file, although ( unwisely ) the developers of the user pool AWSSignInProvider made it have hardcoded keys in a configuration file.
SO:
If you don't intend to use the "Mobile Hub" console application for making changes to your mobile app configuration, then you won't need any more downloads. In that case, you don't have to worry about changes to Info.plist or the configuration file, and you can edit what you want.
It is unclear if you are going to use the mobile hub created identity pool and just want to insert your user pool, or if you want to change both pools. Obviously if you are using the same identity pool then some of the changes below will not be needed (they will be obvious because you will be changing them to be exactly the same).
So all you have to do is change the ID's to get everything hooked up correctly.
In general you need to fix all the downloaded keys and ID's in Info.plist and the configuration file, and then you need to update the server configuration. In more detail, here are the places you need to change it:
in the app:
update all the keys in Info.plist to be the keys you want. (specifically credentials provider and identity manager keys for google) But if you are using other mobile hub services, check the keys there too.
If you are using s3, and some of the other services the directory names/database names are also stored in the code... I leave it as an activity to find them.
in the file MySampleApp->AmazonAWS->AWSConfiguration.swift edit the keys provided by Mobile hub to match your user pool (do this while quietly swearing under your breath because they are not in Info.plist)
in the console:
put your app name in your user pool APP's list if it is not there, and record the user pool id, app id, and app secret.
click on federated identities and the identity pool created by mobile hub and update the authentication provider to use your cognito user pool id and app id.
if you are changing the identity pool too, then you will need to look at the IAM Roles for your auth and unauth users and specifically edit the policy that is named: .....yourapp....signin_MOBILEHUB_xxxxxxx, and change the identity pool id in that policy to be the one you want to use. Do this for both auth and unauth.
( you can change the id if you only use one pool, or add another to a list of id's like this if you will have multiple identity pools (for test...etc))
"Resource": [
"arn:aws:cognito-identity:*:*:identityPool/us-east-1:8s8df8f8-sd9fosd9f0sdf-999sd99fd",
"arn:aws:cognito-identity:*:*:identityPool/us-east-1:dfsf9099-sd9fosd9f0sdf-sd9f0sdf09f9s"
]
similarly, in the trust relationship associated with the roles, you need to fix the id's, (or handle multiple ID's if you want the role to serve multiple identity pools). Here is how to specify multiple id's there.
"Condition": {
"ForAllValues:StringLike": {
"cognito-identity.amazonaws.com:aud": [
"us-east-1:8s8df8f8-sd9fosd9f0sdf-999sd99fsdfdd",
"us-east-1:dfsf9099-sd9fosd9f0sdf-sd9f0sdf09f9s"
]
},
if you are using google too... you need to make sure that you have an identityProvider in the IAM configuration for google (mobile hub did that for you) and if you are using your own identity pool , in your federated identity pool authorization providers configuration you will need to select google open id provider (and put google in the authorized providers too (but I don't think this part is strictly needed))
facebook doesnt use OpenID Connect, it has a proprietary way of configuring into the authentication providers section, so enter those keys if needed in the identity pool authentication providers section.
And that should be enough to make it work.
And no you are not going crazy... the documentation does not match the current IOS SDK. Mobile hub uses the aws-mobilehub-helper-ios (github) which is built on TOP of the sdk, so the documentation does not apply to that either! Mobile Hub Helper has a nice design, so I recommend you use it, rather than the raw SDK.
(and lastly... and I am out of my depth here because I don't use API gateway, but my understanding was that the API Gateway is a way to get credentials to use AWS Services, and with the mobile hub app you will be using Cognito to get those credentials, so I am not sure you will need to bring the API Gateway into it...at all)
UPDATE
You may want to use no client secret for users of your javascript app, and use a IOS Mobile App on the same pool too. This can be done in two ways:
1) The better way is that you create two different client's in the user pool. For one you will generate a client secret, for the other you will UNCHECK the "generate client secret" box.
Then in your Federated Identity Pool you go to Authentication Providers, and click on Cognito, and specify TWO DIFFERENT PROVIDERS USING THE SAME USER POOL ID. (This is not really two different providers, but that is how the console makes you specify it). And you put the two different client ids in those providers.
Now both the IOS app and the Javascript app can access the pool and get authentication and credentials from the identityProvider and credentialsProvider.
2) A not so good way. The reason this way is worse is because I don't know the impact (if any) it has on the security of your mobile app. And at AWS there is nobody to ask the question to without buying a support contract. But the other way exists.
What you do is use the same client id in both apps, and you don't generate a client secret. To do this you put "nil" in the clientSecret. This works fine with some caveats.
First, the AWS Mobile Hub has a bug in it's AWSCognitoUserPoolsSignInProvider. That class requires that the clientSecret is non-null. But in the SDK, the only way to tell the SDK that you want no client secret is to pass nil! However there are workarounds.
(What I did was use the AWSCUPIdPSignInProvider.swift (that I wrote), which will work fine and I have a version that will take a nil for the secret. I did that because it was faster for me to test this out. you can find that signin provider on github if you want to use it)
But a better (more future proof) solution is probably to use the AWSCognitoUserPoolsSignInProvider that the mobile hub delivers, but change the code in AWSMobileClient to configure and register your own pool rather than letting AWSCognitoUserPoolsSignInProvider do it for you.
I haven't bothered to try this, (because we only have to do it because AWS has not gotten around to updating the github aws-mobilehub-helper-ios yet). But basically in AWSMobileClient instead of this code:
func setupUserPool() {
// register your user pool configuration
AWSCognitoUserPoolsSignInProvider.setupUserPoolWithId(AWSCognitoUserPoolId, cognitoIdentityUserPoolAppClientId: AWSCognitoUserPoolAppClientId, cognitoIdentityUserPoolAppClientSecret: AWSCognitoUserPoolClientSecret, region: AWSCognitoUserPoolRegion)
AWSSignInProviderFactory.sharedInstance().registerAWSSignInProvider(AWSCognitoUserPoolsSignInProvider.sharedInstance(), forKey:AWSCognitoUserPoolsSignInProviderKey)
}
you would have something like this code
func setupUserPool() {
// register your user pool configuration
// find the service configuration (we don't know if they set it as default)
let credentialProvider = AWSCognitoCredentialsProvider(regionType: .USEast1 (or your region), identityPoolId: "YourIdentityPoolId")
let configuration = AWSServiceConfiguration(region: .USWest2 (or your region), credentialsProvider: credentialProvider)
// configure and put your own user pool in the service configuration
let userPoolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: AWSCognitoUserPoolAppClientId, clientSecret: nil, poolId:AWSCognitoUserPoolId)
// now we register that pool with the service configuration using the key they use
AWSCognitoIdentityUserPool.register(with: configuration, userPoolConfiguration: userPoolConfiguration, forKey: AWSCognitoUserPoolsSignInProviderKey)
AWSSignInProviderFactory.sharedInstance().registerAWSSignInProvider(AWSCognitoUserPoolsSignInProvider.sharedInstance(), forKey:AWSCognitoUserPoolsSignInProviderKey)
}
But as I said above, solution 1, use two different clients and specify two different providers is preferred.

Limit Firebase Google OAuth Authentication to specific users

I'm using Firebase to handle my Google OAuth login for my website. Does anyone knew how to restrict the users who have access to the application? For example, I only want x#gmail.com, y#gmail.com, and z#gmail.com to successfully be able to log in via google to my application.
I wasn't sure if this was a Firebase or Google question, but any help would be much appreciated.
Firebase's authentication handles only that: the authentication of users through any of the mechanisms you enable. Whether those users have access to your data is called authorization and it is handled through the security rules of your Firebase.
So:
Authentication allows the user to identify him/herself with your application. See Firebase's documentation on authentication (for JavaScript/Web, but it exists for all supported platforms).
Authorization limits read/write access to your data to specific users, based on their authentication. See Firebase's documentation on its security rules.
Limiting access to your data to specific email addresses is certainly possible. I recommend that you read Firebase's documentation on its security rules and try to make it work based on that. If you have any problems, post what you've tried and we'll be able to help you better.
These rules will allow anybody to login, but only the listed email addresses to read or write data:
{
"rules": {
".read": "auth.email == 'x#gmail.com' ||
auth.email == 'y#gmail.com' ||
auth.email == 'z#gmail.com'",
".write": "auth.email == 'x#gmail.com' ||
auth.email == 'y#gmail.com' ||
auth.email == 'z#gmail.com'"
}
}

Resources