Grails - Retrieve an object from another tenant - grails

I have a system in grails, already running on a server, and we use tenant solutions to distinguish the branches of the corporation, but now I need to recover information from one branch to another.
The point is when I make the following query in my model:
def expedition = Expedition.findByCode(row.code)
If my expedition was issued by a branch this find does not return anything to me, after all it was thus the initial architecture for the branch offices not to fill information of each other.
Does anyone know how I can do this? it may just be to return that object at that point, or some annotation in the model, but I would not like to remove my multi-tenant structure because I still need to block some information.

You can use the methods on the grails.gorm.multitenancy.Tenants class to achieve this:
Allow to find across any tenant:
def expedition = Tenants.withoutId { Expedition.findByCode(row.code) }
Specify a tenant
Long otherTenantsId = 2L
def expedition = Tenants.withId(otherTenantsId) { Expedition.findByCode(row.code) }
Of course be careful when doing so or trusting user input for a tenant id as it will give access to other users data.
Note there are also #WithoutTenant if you'd like to add it to a class/method level.

Related

Designing safe and efficient API for item state updates via events

Recently I've been working on a simple state-tracking system, its main purpose is to persist updates, sent periodically from a mobile client in relational database for further analysis/presentation.
The mobile client uses JWTs issued by AAD to authenticate against our APIs. I need to find a way to verify if user has permissions to send an update for a certain Item (at this moment only its creator should be able to do that).
We assume that those updates could be sent by a lot of clients, in small intervals (15-30 seconds). We will only have one Item in active state per user.
The backend application is based on Spring-Boot, uses Spring Security with MS AAD starter and Spring Data JPA.
Obviously we could just do the following:
User_1 creates Item_1
User_1 sends an Update for Item_1
Item has an owner_ID field, before inserting Update we simply check if Item_1.owner_ID=User_1.ID - this means we need to fetch the original Item before every insert.
I was wondering if there was a more elegant approach to solving these kind of problems. Should we just use some kind of caching solution to keep allowed ID pairs, eg. {User_1, Item_1}?
WHERE clause
You can include it as a condition in your WHERE clause. For example, if you are updating record X you might have started with:
UPDATE table_name SET column1 = value1 WHERE id = X
However, you can instead do:
UPDATE table_name SET column1 = value1 WHERE id = X AND owner_id = Y
If the owner isn't Y, then the value won't get updated. You can introduce a method in your Spring Data repository that looks up the Spring Security value:
#Query("UPDATE table_name SET column1 = ?value1 WHERE id = ?id AND owner_id = ?#{principal.ownerId}")
public int updateValueById(String value1, String id);
where principal is whatever is returned from Authentication#getPrincipal.
Cache
You are correct that technically a cache would prevent the first database call, but it would introduce other complexities. Keeping a cache fresh is enough of a challenge that I would try it only when it's obvious that introducing the complexity of a cache brings the required, observed performance gains.
#PostAuthorize
Alternatively, you can make the extra call and use the framework to simplify the boilerplate. For example, you can use the #PostAuthorize annotation, like so, in your controller:
#PutMapping("/updatevalue")
#Transactional
#PostAuthorize("returnObject?.ownerId == authentication.principal.ownerId")
public MyWidget update(String value1, String id) {
MyWidget widget = this.repository.findById(id);
widget.setColumn1(value1);
return widget;
}
With this arrangement, Spring Security will check the return value's ownerId against the logged-in user. If it fails, then the transaction will be rolled back, and the changes won't make it into the database.
For this to work, ensure that Spring's transaction interceptor is placed before Spring Security's post authorize interceptor like so:
#EnableMethodSecurity
#EnableTransactionManagement(order=-1)
The downside to this solution is that there are still the same two DB calls. I like it because it's allowing the framework to enforce the authorization rule. To learn more, take a look at this sample application that follows this pattern.

What is available for limiting the use of extend when using Breezejs, such users cant get access to sensitive data

Basically this comes up as one of the related posts:
Isn't it dangerous to have query information in javascript using breezejs?
It was someone what my first question was about, but accepting the asnwers there, i really would appreciate if someone had examples or tutorials on how to limit the scope of whats visible to the client.
I started out with the Knockout/Breeze template and changed it for what i am doing. Sitting with a almost finished project with one concern. Security.
I have authentication fixed and is working on authorization and trying to figure out how make sure people cant get something that was not intended for them to see.
I got the first layer fixed on the root model that a member can only see stuff he created or that is public. But a user may hax together a query using extend to fetch Object.Member.Identities. Meaning he get all the identities for public objects.
Are there any tutorials out there that could help me out limiting what the user may query.?
Should i wrap the returned objects with a ObjectDto and when creating that i can verify that it do not include sensitive information?
Its nice that its up to me how i do it, but some tutorials would be nice with some pointers.
Code
controller
public IQueryable<Project> Projects()
{
//var q = Request.GetQueryNameValuePairs().FirstOrDefault(k=>k.Key.ToLower()=="$expand").Value;
// if (!ClaimsAuthorization.CheckAccess("Projects", q))
// throw new WebException("HET");// UnauthorizedAccessException("You requested something you do not have permission too");// HttpResponseException(HttpStatusCode.MethodNotAllowed);
return _repository.Projects;
}
_repository
public DbQuery<Project> Projects
{
get
{
var memberid = User.FindFirst("MemberId");
if (memberid == null)
return (DbQuery<Project>)(Context.Projects.Where(p=>p.IsPublic));
var id = int.Parse(memberid.Value);
return ((DbQuery<Project>)Context.Projects.Where(p => p.CreatedByMemberId == id || p.IsPublic));
}
}
Look at applying the Web API's [Queryable(AllowedQueryOptions=...)] attribute to the method or doing some equivalent restrictive operation. If you do this a lot, you can subclass QueryableAttribute to suit your needs. See the Web API documentation covering these scenarios.
It's pretty easy to close down the options available on one or all of your controller's query methods.
Remember also that you have access to the request query string from inside your action method. You can check quickly for "$expand" and "$select" and throw your own exception. It's not that much more difficult to block an expand for known navigation paths (you can create white and black lists). Finally, as a last line of defense, you can filter for types, properties, and values with a Web API action filter or by customizing the JSON formatter.
The larger question of using authorization in data hiding/filtering is something we'll be talking about soon. The short of it is: "Where you're really worried, use DTOs".

How to check if lists have the same value in grails?

I am currently working on a grails project right now where I needed to combine the result of my query in a list. The problem is, there are instances that the result of my query returns equal values, which causes an error message: A different object with the same identifier value was already associated with the session
Here's my code:
List permissions = []
cmd?.role.each{ role ->
permissions.add(RolePermission.executeQuery("select distinct rp.permission from RolePermission rp where rp.role = ?",[Role.get(role.toLong())]))
}
The object role here may contain two different role names that in some instances the permissions present in these role names are the same.
How will I modify my query in such a way that I can only get the unique values from the result ? I've tried using distinct, but it didn't work.
Please help!
Thanks!
I'm not sure if this is what you're trying to do, but from your description I think this is it. What the below line does is iterate over your passed in roles (I assume these are role id's from the syntax) and for each role id it finds a RolePermission for the Role. Each permission found is added as a list to permissions. So, at the end you should have a list of RolePermissions.
Now, what I'm not understanding is the distinctness your looking for. Are you saying that a Role can return more than one RolePermission and your trying to make sure that the returned RolePermissions are unique in the final list? If so you could return the list as a set (i.e. return permissions as Set). Please let me know where my understanding falls short.
def permissions = cmd?.role.collect{RolePermission.findByRole(Role.get(it.toLong()))}
return permissions as Set
Alternatively, you could use a criteria:
def c = RolePermission.createCriteria()
def results = c.listdistinct () {
roles {
'in'("id", cmd?.role as List)
}
}
I didn't run this through the compiler, but it should work.

grails removeFrom removes only one at a time

I have a grails application where I have contacts which belongs to another domain contactGroup. It all seems to be working fine except for removeFromContacts method. I am using following code. The code works correctly but removes only one contact from the group at a time. I even did some debugging and the foreach loop runs as many times as the contacts provided. There is no error message. Any idea what could be going wrong -
ContactGroup group = ContactGroup.findByIdAndOwner(params.groupId, user)
def contactIds = request.JSON.data.contact
contactIds.each {
Contact contact = Contact.findByContactIdAndOwner(it.contactId, user)
if(contact) {
group.removeFromContacts(contact)
}
}
I've read a few things about the findAll methods loading proxies if the associations are lazy-loaded rather than the "real" instance.
Try this:
group.removeFromContacts(Contact.get(contact.id))
The 'get' should bypass the proxies and use the "real" instance. There is a JIRA that talks about this (Grails-5804). An overall fix according to the JIRA (from Burt Beckwith) is to implement the equals and hashCode method in your Contact class.
Thanks for all your support. I realized that I have not defined the relationship at the domain level correctly and that was messing up with the whole thing. When I corrected that it was working correctly.
saurabh

Hydrate related objects

I am looking for a simple way to hydrate a related object. A Note belongs to a Document and only owners of a Document can add Notes so when a user tries to edit a Note, I need to hydrate the related Document in order to find out if the user has access to it. In my Service layer I have the following:
public void editNote(Note note)
{
// Get the associated Document object (required for validation) and validate.
int docID = noteRepository.Find(note.NoteID).DocumentID;
note.Document = documentRepository.Find(docID);
IDictionary<string, string> errors = note.validate();
if (errors.Count > 0)
{
throw new ValidationException(errors);
}
// Update Repository and save.
noteRepository.InsertOrUpdate(note);
noteRepository.Save();
}
Trouble is, noteRepository.InsertOrUpdate(note) throws an exception with "An object with the same key already exists in the ObjectStateManager." when the repository sets EntityState.Modified. So a number of questions arise:
Am I approaching this correctly and if so, how do I get around the exception?
Currently, the controller edit action takes in a NoteCreateEditViewModel. Now this does have a DocumentID field as this is required when creating a new Note as we need to know which Document to attach it to. But for edit, I cannot use it as a malicious user could provide a DocumentID to which they do have access and thus edit a Note they don't own. So should there be seperate viewmodels for create and edit or can I just exclude the DocumentID somehow on edit? Or is there a better way to go about viewmodels such that an ID is not required?
Is there a better way to approach this? I have read that I should just have a Document repository as an aggregate and lose the Note repository but am not sure if/how this helps.
I asked a similar question related to this but it wasn't very clear so hoping this version will allow someone to understand and thus point me in the right direction.
EDIT
Based on the information provided by Ladislav Mrnka and the answer detailed here: An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key, it seems that my repository method need to be like the following:
public void InsertOrUpdate(Note note)
{
if (note.NoteID == default(int)) {
// New entity
context.Notes.Add(note);
} else {
// Existing entity
//context.Entry(note).State = EntityState.Modified;
context.Entry(oldNote).CurrentValues.SetValues(note);
}
}
But how do I get the oldNote from the context? I could call context.Entry(Find(note.NoteID)).CurrentValues.SetValues(note) but am I introducing potential problems here?
Am I approaching this correctly and if so, how do I get around the exception?
I guess this part of your code loads the whole Node from the database to find DocumentID:
int docID = noteRepository.Find(note.NoteID).DocumentID;
In such case your InsertOrUpdate cannot take your node and attach it to context with Modified state because you already have note with the same key in the context. Common solution is to use this:
objectContext.NoteSet.ApplyCurrentValues(note);
objectContext.SaveChanges();
But for edit, I cannot use it as a malicious user could provide a DocumentID to which they do have access and thus edit a Note they don't own.
In such case you must add some security. You can add any data into hidden fields in your page but those data which mustn't be changed by the client must contain some additional security. For example second hidden field with either signature computed on server or hash of salted value computed on server. When the data return in the next request to the server, it must recompute and compare signature / hash with same salt and validate that the passed value and computed value are same. Sure the client mustn't know the secret you are using to compute signature or salt used in hash.
I have read that I should just have a Document repository as an aggregate and lose the Note repository but am not sure if/how this helps.
This is cleaner way to use repositories but it will not help you with your particular error because you will still need Note and DocumentId.

Resources