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
Related
I have these entities:
User
Role
Permission
A user has many roles and a role has many permissions.
What is the best way to retrieve a set of permission a user has?
I need a method to check if a User has a particular Permission.
This is what I have so far:
public boolean hasPermission(String permissionString) {
if (!authenticated) return false;
for (Role role : user.getRoles()) {
for (Permission permission : role.getPermissions()) {
if (permission.getName().equals(permissionString)) {
return true;
}
}
}
return false;
}
A second, but related question -- where should I put the code that checks if a user has a particular permission?
In the User entity?
In the UserBean EJB?
In the Authentication JSF Managed Bean?
It depends on your mappings, the number of objects in the list, if the lists have already been fetched, your database connections, the database tuning etc.
You would have to try with production data to determine what ways are best.
For instance, If your collections have been prefetched with a join query, then traversing them in Java is trivial. If they haven't, each access in the for loop would cause a query to populate the objects. If it is the last one all the time, it means your java code causes you to traverse your object graph in the worst way possible and it would have been better to fetch it upfront. So you would be losing any benefit of lazy access, and would be better of hitting the database once to query for the permission linked to this user with the permissionString name: "Select p from u User join u.roles r join r.permissions p where p.name = :permissionName".
Only testing on production data will give you the best answer for your situation, and numerous other decisions in the application and mappings change the outcome.
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.
I have a Mobile Service with Model classes and DTO classes. I mapped these using Fluent API and got it to work to perform CRUD operations, but I have a problem with the JSON responses returned in some instances.
Take for example a User entity with user name and password. To register a user I have my PostUserDTO method like this:
// POST tables/UserDTO
public async Task<IHttpActionResult> PostUserDTO(UserDTO item)
{
string hashString = PasswordHash.CreateHash(item.Password);
item.Password = hashString;
UserDTO current = await InsertAsync(item);
current.Password = "";
return CreatedAtRoute("Tables", new { id = current.Id }, current);
}
On the method I read the password property sent from the client and then proceed to hash it with a salt, replace the value in the object sent and save it to the database, then I proceed to empty the password so the hashed result isn't returned.
In this case the best practice would be to omit the password property from the response, this also should happen when retrieving all of the users in the table, I only want to return specific information, some information generated by my server should stay out from the response.
How can I select or alter the information from the responses? Do I have to create other DTOs for every kind of response I desire?
I have 2 Entity objects that i mapped in Entityframework
I have relationship between users and Messages
I want to get all messages of specific user so i load the data from users table to specific user object:
var user = (from u in context.Users
where u.u_username == username
select u).First();
Now, how can i get all messages of this user , i notice that i can do:
var messages = user.Messages;
But i got nothing.
Is it correct?
How can i used this syntax and to get all message of the specific user?
I used .net4
Is it possible to do
If you want to lazy load the Messages of the user you can make the Messages property virtual.
public class User
{
//other properties
public virtual ICollection<Message> Messages;
}
Or you can eager load Messages using Include function
var user = (from u in context.Users.Include("Messages")
where u.u_username == username
select u).First();
Finally it maybe the case that you have not configured the Messages property with EF.
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() { /* ... */ }
}