Security rules of realtime database doesn't work - firebase-realtime-database

I have a firebase realtime database as below:
The key for each user is the uid of the authenticated user.
Following the security rules tutorial, I created a simple security rule for authenticated users who have the correct User UID to access the users information.
Part of the Javascript code to access the realtime database is:
fireusers = firebase.database().ref('/users');
this.fireusers.orderByChild('identifier').equalTo(this.email).once("value").then((snapshot) => {
var temp = snapshot.val();
for (var tempkey in temp) {
this.globalvar.userName = temp[tempkey].name
this.globalvar.userCompany = temp[tempkey].company
}
})
But the access is denied, and the error log is:
ERROR Error: Uncaught (in promise): Error: permission_denied at /users: Client doesn't have permission to access the desired data.
Error: permission_denied at /users: Client doesn't have permission to access the desired data.
Can you please help for solving this problem?

Your code (that you didn't share) is trying to read the /users node. Your rules don't grant anyone access to that node, so the read gets rejected.
It is important to realize that Firebase security rules don't filter data, but instead merely check whether the code is trying to access any more data than it is allowed. And in your case it does, so it gets rejected.
To read the data, try to only read the path for the current user's UID: /users/$uid.
Also see: Restricting child/field access with security rules

Related

Microsoft Graph returning Resource Not Found

I've registered an app in Azure AD and given it API permissions(both Application and delegated) to read all AD groups (Group.Read.All, also Directory.Read.All etc). Using this app I am using Graph Service Client to make a call to get user's AD groups.
public async Task<IEnumerable<GroupInfo>> GetAllGroupsOfUser(string mail)
{
IList<GroupInfo> result = new List<GroupInfo>();
IUserMemberOfCollectionWithReferencesPage memberOfGroups = await _graphServiceClient.Users[mail].MemberOf.Request().GetAsync();
.......... More code ........
}
It works fine for most of the users email but for few emails, which are present in the active directory, I'm getting the following exception
Code: Request_ResourceNotFound Message: Resource 'someuser#somedomain.co' does not exist or one of its queried reference-property objects are not present.
Your error is not that you lack certain permissions, and it has nothing to do with which api testing tool you are using. Your error is very simple. As your error message says, it is that you entered the wrong user email.
Your error message has clearly stated that there is no'someuser#somedomain.co' email, because this is not a correct email, it should be .com instead of .co.
So you must make sure that you enter the correct email without special characters or spaces.
This is my test result:
1.
2.

How to validate fields server side during user creation with Firebase Auth?

I'm trying to use Firebase Auth to create a new user, but I want to validate some fields (pattern matching) using Firestore Security Rules before creating a new account. How can I do that?
In the completion handler for the createUser(withEmail: , password:) function, I am performing some writes to Firestore on successful account creation.
I am facing a problem where sometimes the writes to Firestore may not be successful due to Firestore Secuity Rules (Pattern matching). In this case the write fails but the new user account is still created (since writes are being attempted in completion handler).
// Create User Method - Firebase Auth & Swift
Auth.auth().createUser(withEmail: self.emailTextField.text!, password: self.passwordTextField.text!) { (result, error) in
if error != nil {
print(error?.localizedDescription)
} else {
let userName = [
userName:self.userNameTextField.text!
]
// Writing field Data to Firestore
Firestore.firestore().collection("users").document(self.userNameTextField.text!).setData(userName) {(err) in
if err != nil {
// Rather than throwing a fatalError, how can I ensure new account creation is cancelled so that feedback can be given on the issue with entered field data?
fatalError()
}
I want to ensure a user account is not created in case writes to Firestore are unsuccessful due to a conflict with Firestore Security Rules.
Firebase Authentication doesn't have any security rules. There's currently no way to check if incoming account properties are valid before a user gets created. Security rules only apply to data read and written directly to Cloud Firestore (or Realtime Database, or Cloud Storage) from a mobile or web client.
The only thing you could do is use a Cloud Functions auth trigger to check the account properties after it was created, then delete or deactivate the account if something is wrong.

iOS - AWS Cognito - Check if user already exists

I want to allow a user to enter their email address/password in a field. Upon continuing, I want to run a check to see if that user already exists. If they do, log them in and continue with app, if they do not, move to account creation flow where they will be instructed to add name, phone number, etc.
I cannot for the life of me find documentation on how to log a user in using AWS Cognito. I should be able to pass email/pass in a call and get a response back that says User Exists/User does not exist or whatever! Am I missing something here?
Any help would be greatly appreciated. I've scoured the documentation..this is my last resort.
In the current SDK, calling getUser on your AWSCognitoIdentityUserPool just constructs the in-memory user object. To make the call over the network, you need to call the getSession method on the constructed user. Here's a Swift 3 method I wrote to check whether an email is available:
/// Check whether an email address is available.
///
/// - Parameters:
/// - email: Check whether this email is available.
/// - completion: Called on completion with parameter true if email is available, and false otherwise.
func checkEmail(_ email: String, completion: #escaping (Bool) -> Void) {
let proposedUser = CognitoIdentityUserPoolManager.shared.pool.getUser(email)
UIApplication.shared.isNetworkActivityIndicatorVisible = true
proposedUser.getSession(email, password: "deadbeef", validationData: nil).continueWith(executor: AWSExecutor.mainThread(), block: { (awsTask) in
UIApplication.shared.isNetworkActivityIndicatorVisible = false
if let error = awsTask.error as? NSError {
// Error implies login failed. Check reason for failure
let exceptionString = error.userInfo["__type"] as! String
if let exception = AWSConstants.ExceptionString(rawValue: exceptionString) {
switch exception {
case .notAuthorizedException, .resourceConflictException:
// Account with this email does exist.
completion(false)
default:
// Some other exception (e.g., UserNotFoundException). Allow user to proceed.
completion(true)
}
} else {
// Some error we did not recognize. Optimistically allow user to proceed.
completion(true)
}
} else {
// No error implies login worked (edge case where proposed email
// is linked with an account which has password 'deadbeef').
completion(false)
}
return nil
})
}
For reference, my ExceptionString enum looks like this:
public enum ExceptionString: String {
/// Thrown during sign-up when email is already taken.
case aliasExistsException = "AliasExistsException"
/// Thrown when a user is not authorized to access the requested resource.
case notAuthorizedException = "NotAuthorizedException"
/// Thrown when the requested resource (for example, a dataset or record) does not exist.
case resourceNotFoundException = "ResourceNotFoundException"
/// Thrown when a user tries to use a login which is already linked to another account.
case resourceConflictException = "ResourceConflictException"
/// Thrown for missing or bad input parameter(s).
case invalidParameterException = "InvalidParameterException"
/// Thrown during sign-up when username is taken.
case usernameExistsException = "UsernameExistsException"
/// Thrown when user has not confirmed his email address.
case userNotConfirmedException = "UserNotConfirmedException"
/// Thrown when specified user does not exist.
case userNotFoundException = "UserNotFoundException"
}
Some clarification is in order. Cognito has several parts. The part that does "Authentication" (which is what you are talking about) is called "Cognito User Pools". Not to be confused with Cognito Federated Identity Pools.
With User Pools you can create usernames and password combinations with attributes, and these can be used to authenticate and deliver a persistent, cross device, Cognito Federated identity identityId to a user (across multiple devices).
Once logged in, the Federated Identity Pool is hooked to roles which can get your "Authorized" to use AWS services (like Dynamo DB etc).
It can be tricky to get all these parts working together and AWS has an online site called "Mobile Hub" that will build code for you and download an xcode project. This process configures the Federated Identity Pool and the User Pool correctly, and connects them all up to a set of example code.
Connecting the credentials provider to the user pool to the identity pool is a bit counterintuitive, but the AWSIdentityManager in the aws-mobilehub-helper-ios on github manages all that for you. So I would recommend starting with mobile hub on the console.
Cognito is a somewhat confusing system, here is a link to a brief powerpoint that hits the highlights of how it works (for people that can't understand the AWS docs (like me)).
With that said, "how to check if a user already exists?"
The most reasonable approach is to create the user (via signup), and get a reject if the name is in use, and suggest that your user try a different username. With respect to the email being in use, you will get that reject upon confirmation (signup sends confirmation id's by email and/or via text). This can be overridden to reclaim the email address, or you can do a test beforehand to see if the email is in use by attempting to log in and looking at the failure code.
you can fetch the user as the other answer suggests, however if you have established in user pools an alias for login (like email) you will find this problematic, because this just tells you if someone has the user name, not if someone is already using the email address, and you will get a reject later at confirmation time.
ListUsers is now a nice way to check for existing usernames.
https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListUsers.html
You can also look for existing emails, phone numbers, and other default attributes.
Here is a simple .NET example:
Dim userRequest = New ListUsersRequest With {
.UserPoolId = "poolId",
.Filter = "username = bob#email.com"
}
Dim response = amazonCognitoIdentityProviderClient.ListUsers(userRequest)
Debug.WriteLine(response.Users.Count)

Bigcommerce - How to request Authorization Code/Access Token

In my application, the user when installs the app, needs to fill a registration form. I need to save the access_token along with the user instance.
So, if the user is unregistered, I redirect to the signup form ie. I dont save the access_token, but at this time, the app is registered. Which means, suppose when the store admin logs back in to the app, he does not get the auth code again, but gets signed_payload.
Since, I dont want to store, unregistered users on my database, I prefer calling a api, that would grant me auth code and/or access_token.
Is there any such call I can make?
To answer your question, the access token can only be obtained at the point of the initial app install, when the user installs the app for the very first time. This is the only time that BigCommerce will send the information required to obtain the access token.
Therefore your app should always save the access_token at the point of install. Your registration page should be prompted after obtaining and saving the access token. If for some reason the user installs the app and does not complete the registration, then you should simply just check on your end if the registration was finished or not, and if it wasn't then you should display it during the app load phase as a requirement before displaying your main app dashboard.
Since you didn't specify a programming language, I'm going to illustrate one in Python.
There are two parts you mentioned, registration/access token and signed payload.
The initial callback flow would look something like this:
#app.route('/bigcommerce/callback')
def auth_callback():
# Put together params for token request
code = flask.request.args['code']
context = flask.request.args['context']
scope = flask.request.args['scope']
store_hash = context.split('/')[1]
redirect = app.config['APP_URL'] + flask.url_for('auth_callback')
# Fetch a permanent oauth token. This will throw an exception on error,
# which will get caught by our error handler above.
client = BigcommerceApi(client_id=client_id(), store_hash=store_hash)
token = client.oauth_fetch_token(client_secret(), code, context, scope, redirect)
bc_user_id = token['user']['id']
email = token['user']['email']
access_token = token['access_token']
The flow using a signed payload would look something like:
#app.route('/bigcommerce/load')
def load():
# Decode and verify payload
payload = flask.request.args['signed_payload']
user_data = BigcommerceApi.oauth_verify_payload(payload, client_secret())
if user_data is False:
return "Payload verification failed!", 401
bc_user_id = user_data['user']['id']
email = user_data['user']['email']
store_hash = user_data['store_hash']
When initially creating a user in your database, you can also denote the sign up date through a function of your code and then do a periodic cron job to check if they have a registered account with you. There's not an endpoint where we store whether they completed registration with you since that is a function of your app.

Restore Access Token in hybridauth

I saved the Access Token (using this method: getAccessToken ()) in my database, but now I would like to restore this value to an object.
How can I do this?
This is explained in hybridauth user manual with below code :
// get the stored hybridauth data from your storage system
$hybridauth_session_data = get_sorted_hybridauth_session( $current_user_id );
Get_sorted_hybridauth_session is your internal function to get the stored data.
It doesnt matter whether you store the data in a table in a field named 'external_token' or something, get it through a normal sql query, and then just feed it to below function :
// then call Hybrid_Auth::restoreSessionData() to get stored data
$hybridauth->restoreSessionData( $hybridauth_session_data );
// call back an instance of Twitter adapter
$twitter = $hybridauth->getAdapter( "Twitter" );
// regrab te user profile
$user_profile = $twitter->getUserProfile();
$hybridauth->restoreSessionData( $hybridauth_session_data ); will restore the serialized session object, and then it will get an adapter for whichever provider it was saved for. Its best that you also save the provider name (Twitter in this case) in the same database table with something like external_provider , and then you can get it through a sql auery and feed it to getAdapter function. That should do what you need to do.
The manual example is below :
http://hybridauth.sourceforge.net/userguide/HybridAuth_Sessions.html
=============
As an added info - what i saw in my tests was, saving session in this way does not prevent hybridauth from logging the user in, even if the user has revoked access from the app in the meantime. Ie, if user is already logged in and authorized, but, went to the app separately and revoked the access (google for example), hybridauth will still log in the user to your system. Im currently trying to find a way to make sure the user is logged to the remote system too.
Late, but I thought this would help:
The following code verifies and removes those providers from HybridAuth that the user is not truly logged into:
$providers = $this->hybridauthlib->getConnectedProviders();
foreach( $providers as $connectedWith ){
$p = $this->hybridauthlib->getAdapter( $connectedWith );
try {
$p->getUserProfile();
} catch (Exception $e) {
$p->logout();
}
}

Resources