Google Cloud Storage Bucket created with no ACL available so can't update - google-cloud-storage

I'm creating a Google Cloud Storage bucket via the JSON API.
I can create it fine, but when I query the meta data for it I can't see any ACL specified, despite asking for "full" access. Another bucket created via the UI I can see all ACL for.
I need to see the ACL as to update a bucket a required field is the buckets ACL, which I don't quite understand why is needed, but without the same bucket giving its ACL data it means I can't update buckets I create.
I assume that I have full write access to the bucket once I create it, and have tried creating it with and without a predefinedAcl.
Is there anything I am missing on why I can't see the ACL on new buckets?

The creator of the bucket is always an owner of that bucket, and owners of a bucket can always see the bucket's ACL. That said, the ACLs are not part of the default response to a storage.objects.get call. Try passing in the URL query parameter "projection=full", which will cause the ACLs to be included.
The "update" call always sets the absolute, full state of the bucket's metadata, including ACLs and everything else. If you're looking to simply modify some property of the bucket, the "patch" call is probably what you want to use.

The ACL isn't returned because its just not present for the bucket. But to do updates, you can simply pass an empty list to the PATCH method and it will work, even though the acl field is still required:
PUT https://www.googleapis.com/storage/v1/b/blahblahblxxxxlifecycle?key={YOUR_API_KEY}
{
"acl": [
],
"kind": "storage#bucket",
"id": "blahblahblxxxxlifecycle",
"selfLink": "https://www.googleapis.com/storage/v1/b/blahblahblahffflifecycle",
"projectNumber": "1080525199262",
"name": "blahblahblxxxxlifecycle",
"timeCreated": "2016-09-09T21:20:56.490Z",
"updated": "2016-09-09T21:20:56.490Z",
"metageneration": "1",
"location": "US",
"versioning": {
"enabled": true
},
"storageClass": "STANDARD",
"etag": "CAE="
}

Related

Restrict Storage Admins from specific GCS bucket

Can I restrict users/service accounts with roles/storageAdmin permission from a specific GCS Bucket?
I have a sensitive bucket that should be writeable only from a specific service account, and restrict write permissions from all other accounts, even from storage admins.
I've tried setting the permissions to unified instead of acl, with the following iam set on the bucket:
{
"bindings": [
{
"members": [
"serviceAccount:my-sa#my-account.iam.gserviceaccount.com"
],
"role": "roles/storage.objectAdmin"
},
{
"members": [
"group:my-dev-team#my-company.com"
],
"role": "roles/storage.objectViewer"
}
],
"etag": "abcd"
}
Some of my team members have the roles/storageAdmin role, and they can also write to the bucket - which I need to restrict.
At the bucket level, there is uniform bucket-level access, Identity and Access Management (IAM) and Access Control List (ACL). If you want to avoid creating GCP accounts for the users, then try Access Control List (ACL).
If you want to regulate the access each user has within the bucket, you should try Access Control List (ACL).
An access control list (ACL) is a mechanism you can use to define who has access to your buckets and objects, and what level of access they have. In Cloud Storage, you apply ACLs to individual buckets and objects. Each ACL consists of one or more entries. An entry gives a specific user (or group) the ability to perform specific actions. Each entry consists of two pieces of information:
A permission, which defines what actions can be performed (for example, read or write).
A scope (sometimes referred to as a grantee), which defines who can perform the specified actions (for example, a specific user or group of users).
Here is a list of the accesses that can be granted:

Multiple accounts in a single JWT token

I am building a solution, where a single user should be able to access resources from a API spaning multiple accounts using a JWT token.
The setup is quite simple: I have a API exposing resources related to an account, e.g:
[api]/account/{account_id}/orders
However a user should be able to access multiple accounts, but with different permissions for each account (like admin and guest). I however am unsure about how this should best be expressed in the access token, and I have not been able to find an example online addressing this issue.
My current idea would be to have a payload like:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"aud": "[api]",
"accounts": [
{
"account_id": 123,
"roles": ["admin"]
},
{
"account_id": 234,
"roles": ["guest"]
}
]
}
In theory the "roles" property could be replaced on scopes related to the specific account, mimicking then root level scopes. However, if there exist a standard way to achieve this, I would prefer going in that direction?

Negative logic for UMA Policy in Keycloak

I want to manage policies for my resources in Keycloak through a UMA compliant endpoint. So I created a resource profile with scopes view_users, invite_users, edit_users.
Then I moved on to creating Policies using the Policy API.
## POST
{
"name": "can_view_users",
"logic": "NEGATIVE",
"decisionStrategy": "AFFIRMATIVE",
"clients": ["uma_postman"],
"scopes": ["view_users"],
"roles": ["uma_postman/lg_admin", "uma_postman/sales", "uma_postman/customer_admin"],
"users": ["37ae8b1e-f1b0-4e72-b6ac-5ad1e49f89d7", "3627cb69-23ed-474d-abec-8f31b230b730"]
}
I can query this(GET http://localhost:8080/auth/realms/ng_whs/authz/protection/uma-policy) and it seems that the policy is created properly.
Now my understanding is that since the decision strategy is AFFIRMATIVE & the logic is NEGATIVE, for any of the above roles - lg_admin, sales, customer_admin or the user with the above ids, I should not be allowed access to the resource.
However, when I query as a user with the above role or id, I still don't get access denied.
Now when I change the logic to POSITIVE for the same policy, the response is still the same. Am I missing something here? Any help would be really appreciated. :)
I was following the instructions from here - keycloak.org/docs/latest/authorization_services/#_service_authorization_uma_policy_api

How to delete an element from a collection association in Spring Data REST?

Suppose you have a One-To-Many or Many-To-Many relationship in Spring Data REST. Let's say you have groups that has a One-to-Many relationship with users. If you get the list of associations from a group you will get back links like this:
{
"_embedded": {
"users": [
{
"username": "test25",
"enabled": false,
"firstName": "strifng",
"lastName": "sdfdffff",
"_links": {
"self": {
"href": "…/users/78"
}
}
},
{
"username": "test33",
"enabled": true,
"firstName": "sd",
"lastName": "asdfsa",
"_links": {
"self": {
"href": "…/users/77"
}
}
}
}
]
}
Which is useless if you are trying to remove a particular user from a group. You are either forced to use PUT with /groups/{id}/users but that is impossible if you have thousands of users. You can POST to /groups/{id}/users with a list of URI but you can't DELETE to /groups/{id}/users.
Why?
The only way DELETE works is by calling /groups/{id}/users/{id} but there's no way to construct this URI from the front end as it is not returned in the collection.
How do you get around this?
The pattern that you'd need to use here is to access the association resource asking it for the text/uri-list media type, get the URIs of all linked resources, modify the list as you see need and PUT it back to the association resource. I.e.:
GET /groups/4711/users
200 OK
…/users/3149
…/users/41
…/users/4711
Followed by a:
PUT /groups/4711/users
…/users/3149
…/users/4711
Basically removing the user with id 41 from the association.
The problem
The problem with this suggestion is it that it currently doesn't work 🙃. It's broken in the sense that the lookup of the list of URIs currently fails due to some bug. Looks like that functionality went off the radar at some point (as it's not even advertised in the reference docs anymore). Good news is that I filed and fixed a ticket for you. If you give the latest snapshots a try, the suggested protocol should be working.
Some general considerations
In general it's hard to provide an API to generically remove individual items from a collection of associations. The HTTP DELETE method unfortunately operates on the target URI only and does not take any request body. I.e. you'd have to expose some kind of identification mechanism for the individual collection elements within the URI. There's no spec that I am aware of that defines how to do that and we don't want to get into the business of defining one.
One could investigate the ability to use JSON Patch requests to collection like association resources but that's not without problems either. I've filed a ticket to keep track of that idea.
Besides that a potentially ever-growing list of references to other resources is pretty hard to manage in the first place. It might be a better choice to augment the resources space with a custom resource that handles the unassignment of the user from the group and advertise that through a custom link.

Exposing relationships in REST APIs (how does the user refer to objects?)

In my models I have Events and Users. Each Event has a leader attribute that points to a User, however there isn't always a host necessarily, in which case host is null.
In my API:
GET /users/ returns a list of all users
GET /users/3/ returns user 3 info, {"name": "John", "href": "/users/3/"}
GET /events/ returns a list of all events
GET /events/2/host/ should return the user who is a host for event 2. (say this is user 3)
Should I return {"href": "/users/3/"}, simply a link to the User? Or the representation of the user itself, {"name": "John", "href": "/users/3/"}?
Lets say I go with the first option. How do I change the user?
PUT /events/2/host/ json={"href": "/users/2/"} - does this make sense? My server would then have to parse the endpoint to figure out which user id is the new host, and then assign that in the database. Seems a bit inelegant, but Flask has a way to parse the endpoint into the arguments. But is this the right way to do it?
Finally, in the GET /events/2/ resource, I was thinking about having an attribute "host":{"href": "/events/2/host/"} in the representation. Does this make sense? And if there's no host, there would be no href attribute at all, just an empty dictionary assigned to host.
To be short, I think that you should return the representation when getting, for example, host for an event and use the link when updating it. But the design remains up to you ;-)
Here are the different cases:
GET /events/2/host/
{"name": "John", "href": "/users/3/"}
PUT /events/2/host/
{"href": "/users/3/"}
DELETE /events/2/host/ (to set the host field to null)
I think that the OData v4 specification could give you some good ideas for your design. This link gives good insights about the way to handle entity relations with OData : http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/entity-relations-in-odata-v4.
Moreover with its query parameter $expand, OData allows to configure if you load the entity dependency. If the field host is for example defined, you will have the content of the referenced entity, if not, only the reference.
OData also provides a way to get the reference for a dependency with the suffix $ref.
Another link could also give you some ideas: http://templth.wordpress.com/2014/12/15/designing-a-web-api/.
Hope it helps you.
Thierry