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.
Related
In my previous question I was looking for a way to access and store return value of the function in qaf step. I was provided with the following:
When create new user using "{'name':'user1','password':'user123'}"
And store into 'newUser'
Then system should have user '${newUser}'
Now, I'd like to know how to get value from object/collection stored.
If it is a simple object named newUser which has field Id. How would I pass Id on next step?
And, if return is List, how to get by index from stored list?
Resolved issue on my own. If anyone faces same unknowns, here is how I solved it.
For requirements to work around response data, parsing same stored objects in properties by specific fields or collecting data from other structures such as Maps or Lists, create common functions with #QAFTestStep annotation to get data for class member name, map by key or list by index and so on... Add those in common steps and then write stepname text in gherkin format with parameters specified. Let me know if someone needs help, always ready to help out...
I am in the process of trying to copy the properties of one domain object to another similar domain object (Basically moving retired data from an archive collection to an active one). However, when I try to save with a manually inputed id the save will not actually put anything into the collection.
def item = new Item(style: "631459")
item.id = new ObjectId("537da62d770359c2fb4668e2")
item.save(flush: true, validate: false, failOnError:true)
The failOnError does not throw an exception and it seems like the save works correctly. Also if I println on the item.save it will return the correct id. Am I wrong in thinking that you can put a specific id on a domain object?
You can set the id generator as 'assigned' so then you can put the value that you want and is going to be saved with that value.
class Item {
...
static mapping = {
id generator:'assigned'
}
}
The identifier id is a somewhat sensitive name to use. If you check your dbconsole, you will find that GORM has provided one for you even without asking. When you use that name for yourself, confusion happens. Grails will respect you with the println stuff, but GORM has the last word on how id gets initialized and stored, and it is not listening to you then.
You can rename the id to something else like you see in this post and maybe then you can use the name id for yourself. Otherwise, I suggest leaving id to GORM, and have your own identifier for your old keys. You won't have problems retrieving data anyway and there won't be performance issues.
Using a custom EFContextProvider, I want to check which properties have been modified on an entity before it saves, so that I can implement:
Security: The client has permission to change only certain properties of an entity.
Auditing: Whenever certain properties are changed, the change needs to be logged.
There are suggestions on SO to use OriginalValuesMap to determine the modified properties, see here and here. If the original value differs from the new value, the property has been modified. However, these original values are supplied by the client, and thus can be forged to match the new values, bypassing this check.
The first SO question I linked suggests this is not an issue, because if the original values are forged in such a way, those properties won't be saved anyway:
For any other "unchanged" property, which we are not using in any way, we don't need to worry if it has been tampered with because, even if it has, the tampered value will not be persisted to the database
This is untrue however, as long as all modified properties on the entity have their original values forged. For example, the following code will bypass server-side security checks based on OriginalValuesMap and still save to the database:
manager.fetchEntityByKey('Employee', 42).then(function (result) {
var employee = result.entity;
employee.Salary(1000000); // do you think HR will notice?
delete employee.entityAspect.originalValues.Salary;
return manager.saveChanges();
});
When Breeze .NET receives the entity, it adds the entity to an Entity Framework context in Modified state, and with no properties marked as modified, Entity Framework's behaviour is to save all the supplied property values to the database.
IMO this is a security bug in EFContextProvider.HandleModified, where it overrides the EF entity state to Modified (there is even a comment in that method warning not to do so). In any case, what is the correct way to determine which properties have changed and are about to be saved?
In your Context intercept Save and check if it is legal save or not. For the sake of explanation, let's say you want to save entity of type RestrictedClass and you defined table RestrictedClasses which imitates table in your database.
public override int SaveChanges()
{
foreach (
var entry in
this.ChangeTracker.Entries()
.Where((e => (e.State == (EntityState) Breeze.WebApi.EntityState.Modified))))
{
if (entry.Entity.GetType() == typeof(RestrictedClass))
{
var entity = entry.Entity as RestrictedClass;
var originalEntities = RestrictedClasses.Where(e => e.Id = entity.Id).toList();
if (originalEntities.Count == 0) continue; // user is trying to add, illegal since it says it's modified, you do different check for EntityState.Added
var originalEntity = originalEntities[0]; // there should be only one, unique ID
//.... now you check differences between entity and originalEntity and decide whether it's legal or not based on user role.
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".
This is mostly theoretical question, since I actually can implement it in any way, but it confuses me a bit. So, suppose I present a user with a page to select an Excel file, which is then uploaded to the server. Server code parses the file, and presents the user with another page with many options. The user can select and deselect some of them, edit names, and then click OK - after which the server has to process only the selected options.
The question may be:
is it better to store parsed file in Session?
is it better to push parsed data to client's page and then receive it back?
Here's example:
public class Data
{
public string Name { get; set; } // shown to user, can be changed
public bool Selected { get; set; } // this is in ViewModel but anyway
public string[] InternalData { get; set; } // not shown to user
}
// 1st option is to receive data via POST
public ActionResult ImportConfirmed(IList<Data> postitems)
{
// 2nd option is to receive only user changes via POST
var items = Session["items"] as IList<Data>;
items = items.Where(postitems of same name selected);
items.ForEach(set name to postitems name);
}
Obviously option #2 has less side effects, since it does not have global state. But in option #1 we don't push loads of useless-to-user data to the client. And this can be a lot.
Of course this problem is not new, and as always, the answer is: it depends.
I have to admit, I don't have any exact question in mind. I can't even tell why I don't like the Session solution which takes only couple of additional lines of code. The reason I ask is that I've read about Weblocks concept and was very impressed. So, I tried to invent something similar in ASP.NET MVC and failed to. Thus, I wonder, is there any elegant way to deal with such situations? By elegant I mean something that doesn't show it uses Session, easy to use, handles expirations (cleans up the Session if user does not press the final "Save" button), etc. Something like:
var data = parse(filestream);
var confirmationPostData = ShowView("Confirm", data);
items = items.Where(confirmationPostData of same name selected);
items.ForEach(set name to confirmationPostData name);
Here ShowView actually sends GET, wait for user's POST, and returns. Kind of. I do not insist, I just show the way that impressed me (in Weblocks - if I actually did understand it correctly).
Does everyone just use Session in such cases? Or is there a better way (except learning LISP which I already started to investigate if I can cope with)? Maybe, async actions in MVC v2 do it?
UPDATE: storing in DB/temp files, it works. I do sometimes store in DB. However this needs a way to expire the data since user may just abandon it (as simple as closing the browser). What I'm asking for: is there a proven and elegant way to solve it - not about how to do it. An abstraction built on top of serialization not tied to particular DB/file implementation, something like this.
I'm not sure what the purpose of uploading the Excel file is, but I like to make all actions that affect the long term state of the application, for the user, persisted. For example, what if the user uploads the file, changes a couple of options, then goes to lunch. If you store the info in session, it may be gone when they get back, ditto for storing it in the page with hidden variables. What about storing it in a DB?
I would store the file at the temp folder and only associate the name of the file with the user session so that later it can be processed:
// Create a temp file in the Temp folder and return its name:
var tempFile = Path.GetTempFileName();
// write to the temp file and put the filename into the session
// so that the next request can fetch the file and process it
There's a flaw with the GetTempFileName that I once fell into because I didn't read the documentation carefully. It says that the method will start throwing exceptions if you have more than 65535 files in the temp folder. So remember to always delete the temp file once you've finished processing it.
Another alternative to the temp folder would be to store the file into a database, but I am a little skeptic about storing files inside a relational database.