GCS delete bucket ACL always returns 404 - google-cloud-storage

I can't seem to delete a GCS bucket ACL that I inserted.
I did a POST to insert an ACL for my service account:
https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/acl
with this request JSON:
{
"entity" : "user-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s#developer.gserviceaccount.com",
"role" : "WRITER"
}
When I list the ACLs, the ACL I inserted looks like this:
{
bucket = "arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s";
entity = "user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
entityId = 00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f;
etag = "CA0=";
id = "arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
kind = "storage#bucketAccessControl";
role = WRITER;
selfLink = "https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s/acl/user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f";
}
So apparently my "user-<emailaddress>" gets converted some other kind of ID.
When I try to delete the ACL:
DELETE https://www.googleapis.com/storage/v1/b/arqclient-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0sfkjhfkjhf/acl/user-1026650596885-sfd2omc18k3qs6lgphlch37jb5fucg0s%40developer.gserviceaccount.com
I always get a 404 error.
What's wrong with my DELETE command? The doc says I can use user-emailAddress, but that doesn't work.
If I use the entity ID from the listing, "user-00b4903a970addfce72044c71917166bd27bc8b9ab94a391dc841b526cd9466f", that works through the Google APIs Explorer.
If I'm supposed to use the entity ID, how do I get the entity ID given a service-account email address?

The access control page of the Google API docs says "You can find a user's Google Storage ID by retrieving the ACL of an object that the user uploaded." https://cloud.google.com/storage/docs/access-control?hl=en#google-storage-ids
So I guess the best answer is to create an object with my service account, retrieve its ACL, and find the entity ID in the ACL.

Related

In OpenAPI 3.0, how do I create a link from a list of entities to a single entity?

In most OpenAPI 3.0 documentation (like the official one), links are introduced with a combination of a POST endpoint to create an entity returning an ID linking to a GET endpoint to fetch that entity by that same returned ID:
POST /users -> UserID
GET /users/{UserID} -> User
In Schemathesis context, this would assume an empty data storage and simulate a create+fetch scenario. I would like to test my GET endpoints on a pre-warmed data storage and implement a "fetch a list, then fetch each entity from the list by ID" scenario:
GET /users -> List[User] -> List[UserID]
GET /users/{UserID} -> User for each entry in the list
For this to work, I need an OpenAPI link from the list GET endpoint to the entity GET endpoint, however I can't seem to find either an example or a confirmation that this is indeed possible.
Can I and if so how can I create such a link in OpenAPI 3.0?
OpenAPI links are defined using JSON Pointers. JSON Pointers are quite limited - they can only point to a specific field within a JSON Structure (such as "the first element of this array", or the entire array) and don't support wildcard expressions (such as "any/each element of this array").
This means, for example, that if you have the GET /users endpoint that returns
[
{
"id": "29d590d1-02b2-4aa1-9ce5-98202cc9a619",
"username": "nikolai",
...
},
{
"id": "58091b14-eb06-47ee-b896-50cebdda20ef",
"username": "helen",
...
},
...
]
you can define a link like $response.body#/0/id to indicate that the id of the first user in the list can be used as a parameter to another endpoint. But there's no way for a link to reference an arbitrary/each user from the list.
You can check these discussions in the OpenAPI Specification repository for more details:
Link for array element
Variables/Parameters in Links

Spring-rest sub resource request on missing parent

I have a User entity and a Post entity with a One User to Many Posts relationship. To get a user resource I make a GET request to this endpoint in the UserController:
http://localhost:8080/users/{userId}
If the requested userId does not correspond to a user in MySQL I throw an exception with a 404 User not found error through the UserService class (code below).
public User getUser(Integer id) throws ResourceNotFoundException{
return userRepository.findById(id).map(user -> {
return user;
}).orElseThrow(() -> new ResourceNotFoundException("User with the ID " + id + " is not available"));
}
Now in order to get a Post resource I use this endpoint on the PostController:
http://localhost:8080/users/{userId}/posts/{postId}
My question: What if I request a Post (whatever this is) on a non existing User? Is the best logic to throw a 404 User not found error again, or Post not found? If so, how can I combine the UserService getUser(id) and the PostService getPost(id) to throw the error?
Actually it depends how do you map the relationship between user and post.
If it is bidirectional relationship and cascade type is ALL then while deleting the user all the posts created by the user also will get deleted.
So if above is the case then you just check for user in DB if not found then show user not found.
Also you should perform the recommended approach to delete a user using soft delete

Loopback Update User Field

I am trying to update a field in a model that extends the user model. In the API explorer, I set the where field to {"id": 59}, and have the access token one that corresponds with id 59. In the data field I have {"age": 55} where I am just trying to update the age to 55.
The request URL ends up being: http://IP:3000/api/MODEL/update?where=%7B%22id%22%3A%2059%7D&access_token=LONG ACCESS TOKEN VALUE
Which gives an error:
{
"error": {
"statusCode": 401,
"name": "Error",
"message": "Authorization Required",
"code": "AUTHORIZATION_REQUIRED",
}
}
I don't understand why authorization is required when I have a correct access token and the email has been verified. What am I doing wrong?
Loopback by default provides ACL to user model. So by default the update operation can only be changed by the $OWNER, ie. the person himself.
So first login with the username and password, you get the accesstoken. Copy and set the accesstoken in Api Explorer.
Now use the PUT method, which will say Users/{$id}
Open it and you will see 2 fields, data and id. Provide your model's id and provide the data object (the data that needs to be changed)
Hope this helps.

Authenticate a user based on a token and not through mysql table

round 2: trying to make this clearer:
I have two totally and completely separate services (both laravel 5.3).
One is an authentication service that has access to a user mysql database, permissions and role.
The other is a resource service. It couldn't care less about the user table and does not have access to any user table.
That means that any type of Auth::loginById()... would never work in this service because there is no user table.
I want to use JWT to have users access the resource service API, and have the user Auth to act as if a user is authenticated - but again - all I have are the claims inside the JWT - no user table. The claims include some information about the user - id, name, etc. I want to do something like this:
$userObj = JWTAuth::parseToken()->getPayload()->claims; // { id:4, name: Birdman, email: birdy414141#gmail.com}
Auth::login($userObj)
and then have access to the user object like usual
echo Auth::user()->name // Birdman
Has anyone tried anything like this?
I have found that doing this more or less works:
$u = new User();
$u->user_id = (JWTAuth::parseToken()->getPayload()->get('sub'));
$u->name = (JWTAuth::parseToken()->getPayload()->get('name'));
Obviously I can't $u->save() here because again - there is no user database.
I can do this though:
Auth::login($u);
and then I can later call Auth::user()->name properly...
I'm asking if I'm doing something exotic here or is this good stuff. Where will this fail?

Resource level authorization in RESTful service

Let /users/{id} be a resource url in RESTful service.
Basic authentication is enabled and only authenticated users are allowed to access the url.
Example Scenario:
User_1 & User_2 are authenticated users with userId 1 & 2.
Since both are authenticated, both of them are having access to,
/users/1
/users/2
But the expectation is User_1 should have access to /users/1 and not to /users/2 or other userId.
Question:
How to do resource level authorization in RESTful services?
Note: I am implementing RESTful using Jax-RS (with Apache CXF implementation), helpful if you could explain with Jax-RS.
-Barath
Edit:
As Donal mentioned, I am not looking for role based authorization rather resource level authorization.
To give an example, lets say /users/{id}/photos/{photoId} be another resource url. User_1 should be given access to the photos belong to him only. If photoId of 2 belonging to user_2, then we should give http_404 error code for user_1 when a request /users/1/photos/2 is requested.[Since User_1 is also authenticated user he can invoke /users/2/photos/2, so we must identify the user id based on authentication parameters than via resource url]
Only solution I can think of is, include the unique id which determines the authorization in each query like,
Instead of SELECT * FROM PHOTO_TBL WHERE PHOTO_ID=2;
use SELECT * FROM PHOTO_TBL, USER_TBL WHERE PHOTO_ID=2 AND USER_ID=1 AND USER_ID=PHOTO_ID;
with this resources are delivering data that belongs to specific user. [There should be a mechanism to prevent the modification of the unique id in client side which is used to decide on authorization(userId in this case), since all requests are STATELESS request]
Caveat: Each and every query should be intelligent enough to understand the security concerns and include extra join. This is a bad design to tie up security logic to every business function.
I am yet to look into Spring security and how it can be used in this use case.
I would recommend not having the user id in the url (as if it's being 'limited' by a Basic Auth header then you may as well just have it 'specified' by the Basic auth header). This will reduce the risk of introducing a Direct Object Reference Vulnerability - https://www.owasp.org/index.php/Top_10_2010-A4-Insecure_Direct_Object_References)
In this case you could have one of the following urls:
/users/CURRENT
/me
As photos is a sub resource then you could just create the photos with a "sequence number" within the user. In a sql database this would mean having a "compound key" across both user and photo columns.
/users/CURRENT/photo/{user_photo_seq}
/me/photo/{user_photo_seq}
Your SQL would then look something like:
SELECT * FROM PHOTO_TBL WHERE USER_ID=<BasicAuthUsername> AND PHOTO_ID=<path param value>;
A good explanation of "Basic Auth Headers":
http://en.wikipedia.org/wiki/Basic_access_authentication
JAX-RS specifies sub-resource where instead of handling request in a method, processing is delegated to other object - sub-resource.
Using sub-resources it's enought to take care of the root resource and nested ones will be secured as well.
In the example you can see UserResource and all it's sub-resources available only to authorized user.
#Path("/user/{userId}")
public class UserResource {
private final String userId;
public UserResource(#PathParam("userId") String userId, #Context SecurityContext securityContext) {
this.userId = userId;
boolean authorized = /* authorization code */;
if (!authorized) { throw new WebApplicationException(Status.UNAUTHORIZED); }
}
#Path("photo")
public PhotoResource getPhotoResource() {
return new PhotoResource(userId);
}
}
public class PhotoResource {
private final String userId;
public PhotoResource(String userId) {
this.userId = userId;
}
#GET
public Response listAll() { /* ... */ }
#GET
#Path("{photoId}")
public Response present() { /* ... */ }
}