Matching Google Cloud Storage ID to a user email address - google-cloud-storage

I'm looking for a way to determine who uploaded a file to a Cloud Storage bucket. All of the users with access to write to the bucket are authenticated users in the same G Suite domain.
The object ACL in Cloud Storage shows an owner identifier string which looks like the following:
{
"entity": "user-84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46",
"entityId": "84fac329bceSAMPLE777d5d22b8SAMPLE77d85ac2SAMPLE2dfcf7c4adf34da46",
"role": "OWNER"
}
However, it does not appear that there is an easy way to map this ID back to a user's email address (or to determine the Cloud Storage ID for a user whose email I know, except by using that user account to upload a file and querying the object ACL).
Is this true? Or am I just not seeing the way to do this?
Thank you for the help!

Although I can't give you an specific timeline, we're actively working on deprecating canonical ids. This should no longer be a problem in the near future.
In the meanwhile, there are.. options.
First: A user can find their canonical ID on this page (Unfortunately it is going to make you pick a project, since the page also shows the canonical ids for the project roles).
https://console.cloud.google.com/storage/settings
However, if you really need to find out the email address for a random canonical id you should be able to do this somewhat ugly workaround.
1) Add the user to a bucket policy via the ACL API
gsutil acl ch -u <canonical_id>:READ gs://<bucket>
2) Fetch the bucket IAM policy
gsutil iam get gs://<bucket>
The entry should show up as an email address.
{
"bindings": [
{
"members": [
"projectOwner:<project-id>",
"projectEditor:<project-id>",
],
"role": "roles/storage.legacyBucketOwner"
},
{
"members": [
"projectViewer:<project-id>",
"user:<user email here>"
],
"role": "roles/storage.legacyBucketReader"
}
],
"etag": "CAI="
}

Try getting the ACLs again. I just tried today 07/05/2017 and the returned ACLs included email address. It would appear Google has updated the API, replacing the old Google Cloud Storage ID with the user's email address.
{
"email": "email#domain.com",
"entity": "user-email#domain.com",
"role": "OWNER"
}

Related

Create User / Batch Create Users in Asgardeo User Management API with Auto Generated Password

Just want to ask how we can create a user using Asgardeo User Management API without providing a password?
Basically we want to replicate this flow but instead of manually doing it on the console, we want to do it from the User Management API.
enter image description here
Here are some of the Endpoints that we tested
POST
https://api.asgardeo.io/t/asgardeo/scim2
/Users
POST
https://api.asgardeo.io/t/asgardeo/scim2
/Bulk
The password field seems to be a required field.
Setting the urn:scim:wso2:schema with "askPassword":"true" should allow you to create the users without providing the password.
Sample Payload of the scim https://api.asgardeo.io/t/tenantName/scim2/Users:
{
"emails":
[
{
"primary":true,
"value":"<User Email>"
}
],
"name":
{
"familyName":"",
"givenName":""
},
"urn:scim:wso2:schema":
{
"askPassword":"true"
},
"userName":
"DEFAULT/<User Email>"
}
The will receive the invite request similar to the UI function.
Same approach can be taken with the Bulk endpoint too as mentioned this medium blog

Get User Set Filters using Gmail API?

I have an application that rewards users for placing orders with certain merchants and we are planning on connecting to our user's inbox (with their consent of course!) to verify and confirm that an order was placed on certain merchant sites. The idea is that if the order is placed and then cancelled, we'd be able to detect the order cancellation email sent by the merchant and then revoke any rewards linked to that order.
One potential flaw with this approach is that it is possible for a user to set filters that automatically reject and delete incoming emails that match those filters. A user can then set filters on his account to automatically reject and delete any cancellation emails sent by the merchant.
Is it possible to obtain whether a user has any filters set (and what those filters are) using Gmail API?
How to get the logged in user's GMail filters:
Use the users.settings.filters list endpoint.
Here is an example response from that endpoint.
{
"filter": [
{
"id": "0000000",
"criteria": {
"from": "YOUREMAIL",
"to": "me",
"subject": "ORDER",
"query": "ORDER"
},
"action": {
"addLabelIds": [
"Label_94938493840"
],
"removeLabelIds": [
"INBOX",
"SPAM"
]
}
},
...
...
]
}
Experiment by going to the URL I posted and make a request with me as the userId to see your own filters.

How to get the user name/id of a google account linked with Dialog flow

I have integrated google assistant with my dialogflow agent. I need to get the user who is invoking the intent.
For eg, If an user account "ABC" have access to invoke my agent via Google assistant app, on the welcome intent I have to send a response like "Welcome ABC". How do I achieve this with google assistant app is my endpoint.
Thanks in Advance.
You have two questions here: How to get the user's name and how to get their id.
The first thing to realize is that this information is considered personally identifiable information (PII), so Google doesn't give it to you without the permission of the user. How you ask for that permission, and how it is delivered to you, depends on some of your exact needs.
User ID
Historically, you could get an anonymous user ID for the Assistant account. This would be different than the Google User ID that is available below and was meant to be a persistent identifier so you could keep track of returning users.
This has been deprecated, and if this is all you need, then you can create your own identifier and save it as part of the userStorage.
Requesting user information
The traditional way of getting their name is to request the user for permission to access their information. If you're using the actions-on-google library, you do this using the Permission object with something like this:
const options = {
// We just want permission to get their name
permissions: ['NAME'],
// Prompt them why we want the information
context: 'To address you by name'
};
conv.ask(new Permission(options));
If the user grants permission, the results will be available in conv.user.name. You should save this in the userStorage, since the permission is not persistent. So this might look something like:
var userStorageStr = conv.user.userStorage || '{}';
var userStorage = JSON.parse( userStorageStr );
var name = conv.user.name || userStorage.name;
userStorage.name = name;
// ...
conv.user.userStorage = JSON.stringify( userStorage );
With the multivocal library, you would indicate that the User/Name environment property is one of the Requirements for the action or intent you want. So this might be in your configuration as
Local: {
en: {
Requirements: {
"Action.multivocal.welcome": "User/Name"
}
}
}
The name will be available in the environment under User/Name.
If you're using JSON, then you need to use the user information helper. For Dialogflow, this would be under the payload.google.systemIntent property, while for the Actions SDK this would be in expectedInputs[0].possibleIntents[0]. You might specify something like this:
{
"intent": "actions.intent.PERMISSION",
"inputValueData": {
"#type": "type.googleapis.com/google.actions.v2.PermissionValueSpec",
"optContext": "To address you by name",
"permissions": [
"NAME"
]
}
}
The name will be under the originalDetectIntentRequest.payload.user.profile field if you are using Dialogflow and user.profile for the Action SDK.
All of this seems like a lot, just to get a name. And you can't get the email address if you want that in addition. But there are other options.
Requesting their Google Profile
Their Google Profile contains both their unique Google ID, their full name (in the "name" field, given_name, last_name, and typically some other information such as their email address (the email address isn't guaranteed since they can omit this from their profile, but is typically there). You would use Google Sign-In for the Assistant to request this information. There is some configuration required in the Action console, and then you would request permission to get it using the sign-in helper.
With the actions-on-google library, the line would be something like:
conv.ask(new SignIn());
Once the user granted it, you can get their profile in
conv.user.profile.payload
their name in
conv.user.profile.payload.name
and their email in, you guessed it,
conv.user.profile.payload.email
Note that unlike asking for the user information, the profile will be available in all future activity with you. You don't need to store it.
With multivocal, you would say that the User/IsAuthenticated environment setting is one of the Requirements for the action or intent you want. So this might be in your configuration as
Local: {
en: {
Requirements: {
"Action.multivocal.welcome": "User/IsAuthenticated"
}
}
}
The profile will be available in the environment under User/Profile, the name would be in User/Profile/name, and the email in User/Profile/email.
If you're using JSON, then you need to use the sign-in helper. For Dialogflow, this would be under the payload.google.systemIntent property, while for the Actions SDK this would be in expectedInputs[0].possibleIntents[0]. You might specify something like this:
{
"intent": "actions.intent.SIGN_IN",
"inputValueData": {}
}
You will get an identity token for the user in the originalDetectIntentRequest.payload.user.idToken field if you are using Dialogflow and user.idToken for the Action SDK. You will need to validate and decode this JWT. (The actions-on-google and multivocal libraries handle this step for you.)
The easiest would be to use Google Sign-In for the Assistant: https://developers.google.com/actions/identity/google-sign-in

Why does my Google Home send an empty location field in an Actions On Google webhook request?

I have been following the template on GitHub for integration with the locations API the Actions On Google offers.
It works fine in the simulator and even on the Google Assistant for Phones, i.e. I either get a lat/lon pair or a coarse location provided depending on whether the device has a screen or not.
However, on my physical Google Home device, the location field in the response is empty and I cannot figure out why.
In one step, I request the permission with
app.askForPermission(Responses.permissionReason(), app.SupportedPermissions.DEVICE_COARSE_LOCATION);
In my follow-up step I then check if the permission was granted and continue:
if (!app.isPermissionGranted()) {
return Promise.reject(new Error('Permission not granted'));
}
const location = app.getDeviceLocation();
If I start this conversation from my Google Home, however, getDeviceLocation is undefined.
Looking at the request, the permission is clearly granted but the location field is empty:
<snip>
"user": {
"userStorage": "{\"data\":{}}",
"lastSeen": "2018-01-20T10:50:01Z",
"permissions": [
"DEVICE_COARSE_LOCATION"
],
"locale": "en-GB",
"userId": "<redacted>"
},
"device": {
"location": {}
},
</snip>
Full request here.
I couldn't find any information in the documentation about why this would happen. Could someone fill me in?
Check to make sure that your Google Home has a location set for it in the configuration. If you have configured it for voice recognition, make sure it is your voice being recognized and not a generic account.

Retrieving pages for a newly created admin user of a page returns empty

My applicaton uses this endpoint to retrieve a list of pages to which a user has access.
For my personal account, which is the admin of a page, it works fine:
https://graph.facebook.com/me/accounts?access_token=[accesstoken_for_my_personal_profile]
Results:
{
"data": [
{
"access_token": "<the access token>",
"category": "Record Label",
"name": "Page Name",
"id": "Page ID",
"perms": [
"ADMINISTER",
"EDIT_PROFILE",
"CREATE_CONTENT",
"MODERATE_CONTENT",
"CREATE_ADS",
"BASIC_ADMIN"
]
}
]
}
But when we create a totally new facebook profile (regular user, as per my personal one) - and get it verified using mobile phone / SMS based verification, it only ever returns blank here, despite being given page admin access to the same page and having requested an access token exactly the same way:
https://graph.facebook.com/me/accounts?access_token=[accesstoken_for_newly_created_profile]
{
"data": [
]
}
UPDATE
The access token permissions are also different.
So when calling https://graph.facebook.com/me/permissions?access_token=xxx, the bad user only has public_profile and installed as 'granted' - but the good user has all the requested permissions including 'manage_pages'.
The URL used to request the tokens in the first place is here:
https://www.facebook.com/dialog/oauth?client_id=[my_app_id]&redirect_uri=https://www.facebook.com/connect/login_success.html&scope=manage_pages,read_mailbox,read_stream,publish_actions,user_likes&response_type=token
This directs to a login page which logs in as the user for which we want a token.
Courtesy of #CBroe above:
The issue here was that since API v2.0 came in, requesting access tokens for users who do not have a role in the requesting app will not assign certain permissions (in our case 'manage_pages') unless the app has been reviewed.