i have a class User which holds an email address and password for authentication users in my web application. This user is mapped to the database via JPA / Eclipselink.
My question is, how can i prevent JPA from loading the password field back from the database? Since i will access the user object in my web app, i'm uncomfortable regarding security with sending the password to the browser.
Is there any way i can prevent loading the field in JPA / EclipseLink? Declaring the field transient is not an option, since i want to store it on the database when i call persist() on the user object.
Thanks,
fredddmadison
JB Nizet has a valid point. Retrieving it and serializing it in the Http response are two separate concerns.
I'm not sure what you're using to serialize your data. If it this is a REST API, consider Jackson's #JsonIgnore annotation or Eclipselink MOXy's #XmlTransient equivalent. If this uses Java EL (facelets, jsps), you should be able to select only the bean properties of interest.
If you really must do this during retrieval, consider JPQL's/Criteria API's constructor functionality. Ensure that the object has a constructor that accepts the specified parameters, and keep in mind that it won't be managed in the persistence context if it's retrieved in this manner.
SELECT NEW my.package.User(u.id, u.name, u.etc) FROM User u
Alternatively, consider the #PostLoad lifecycle callback.
#PostLoad
private void postLoad() {
this.password = null;
}
Finally, this might not be the case, but I would like to reinforce the notion that passwords shouldn't be stored in plaintext. I mention this because returning a hashed salted password that used a secure algorithm (bCrypt, multiple iteration SHA-512, etc) wouldn't be that big a deal (but still isn't ideal).
I have the similar problem. But in my case I have many #OneToMany relationships inside of Entity class and some of them are EAGER. When I query against this Entity it loads all of them, although for web service I need only some of them.
I tried TupleQuery. But it's not the solution because to get needed OneToMany relationships I have to join and get many duplicate rows of the main query. It makes the result more heawy, than economic.
Related
In a JHipster based project, we need to selectively filter out certain columns based on role/user logged in. All users will be able to view/modify most of the columns, but only some privileged users will be able to view/modify certain secure fields/columns.
It looks like the only option to get this done is using EntityListeners. I can use an EntityListener and mask a certain column during PostLoad event. Say for example, I mask the column my_secure_column with XXX and display to the user.
User then changes some other fields/columns (that he has access to) and submits the form. Do I have to again trap the partially filled in entity in PreUpdate event, get the original value for my_secure_column from database and set it before persisting?
All this seems inefficient. Scoured several hours but couldn't find a specific implementation that best suits this use case.
Edit 1: This looks like a first step to achieving this in a slightly better way. Updating Entities with Update Query in Spring Data JPA
I could use specific partial updates like updateAsUserRole, updateAsManagerRole, etc., instead of persisting the whole entity all the time.
#Repository
public interface CompanyRepository extends JpaRepository<Company, Integer> {
#Modifying(clearAutomatically = true)
#Query("UPDATE Company c SET c.address = :address WHERE c.id = :companyId")
int updateAddress(#Param("companyId") int companyId, #Param("address") String address);
}
Column based security is not an easy problem to solve, and especially in combination with JPA.
Ideally you like to avoid even loading the columns, but since you are selecting entities this is not possible by default, so you have to remove the restricted content by overriding the value after load.
As an alternative you can create a view bean (POJO) and then use JPQL Constructor Expression. Personally I would use CriteriaBuilder. construct() instead of concatenating a JPQL query, but same principle.
With regards to updating the data, the UI should of cause not allow the editing of restricted fields. However you still have to validate on the backend, and I would recommend that you check if the column was modify before calling JPA. Typically you have the modifications in a DTO and would need to load the Entity anyway, if a restricted column was modified, you would send an error back. This way you only call JPA after the security has been checked.
When generating a new entity with JHipster, I'm adding fields which are required, but I'm not displaying them in the front-end application's input forms. These are fields which the back-end should fill out. To illustrate, think of a hypothetical blog application. I have a Post entity and it has a field createdDate which is annotated with #NotNull. The service layer takes care of setting the current date when the entity is being saved.
When the user creates a new post, its fields are validated. Although the user has no option to enter a createdDate, the server responds with a validation error saying that createdDate cannot be null. That's because of the #Valid annotation in the Resource class. At the same time I don't want to remove the #NotNull annotation from the entity class since this field is required in the database.
Then I decided to regenerate the same entity but this time I selected the DTO option. Now I can remove the #NotNull from the createdDate field in the DTO class. I don't get any validation errors from the REST layer anymore, the DTO is mapped to an entity object and when saving takes place, I'm adding the the current date.
Am I overengineering this problem by introducing a DTO and Mapper classes or is this a reasonable solution?
DTOs are a good approach for your use case, whether you use mappers generated by MapStruct or hand written depends on how complex is your mapping.
Other reasons for using DTOs in JHipster are:
hiding some data based on user's role
being able to evolve your entities without impacting your REST API
formatting some fields
aggregating data from several entities into one DTO to avoid too many requests (especially for a mobile client)
we have a huge database application, which must get refactored (there are so many reasons for this. biggest one: security).
What we already have:
MySQL Database
JPA2 (Eclipselink) classes for over 100 tables
Client application that accesses the database directly
What needs to be there:
REST interface
Login/Logout with roles via database
What I've done so far:
Set up Spring MVC 3.2.1 with Spring Security 3.1.1
Using a custom UserDetailsService (contains just static data for testing atm)
Created a few Controllers for testing (simply receiving/providing data)
Design Problems:
We have maaaaany #OneToMany and #ManyToMany relations in our database
1.: (important)
If I'd send the whole object tree with all child objects as a response, I could probably send the whole database at once.
So I need a way to request for example 'all Articles'. But it should omit all the child objects. I've tried this yesterday and the objects I received were tons of megabytes:
#PersistenceContext
private EntityManager em;
#RequestMapping(method=RequestMethod.GET)
public #ResponseBody List<Article> index() {
List<Article> a = em.createQuery("SELECT a FROM Article a", Article.class).getResultList();
return a;
}
2.: (important)
If the client receives an Article, at the moment we can simply call article.getAuthor() and JPA will do a SELECT a FROM Author a JOIN Article ar WHERE ar.author_id = ?.
With REST we could make a request to /authors/{id}. But: This way we can't use our old JPA models on the client side, because the model contains Author author and not Long author_id.
Do we have to rewrite every model or is there a simpler approach?
3.: (less important)
Authentication: Make it stateless or not? I've never worked with stateless auth so far, but Spring seems to have some kind of support for it. When I look at some sample implementations on the web I have security concerns: With every request they send username and password. This can't be the right way.
If someone knows a nice solution for that, please tell me. Else I'd just go with standard HTTP Sessions.
4.:
What's the best way to design the client side model?
public class Book {
int id;
List<Author> authors; //option1
List<Integer> authorIds; //option2
Map<Integer, Author> idAuthorMap; //option3
}
(This is a Book which has multiple authors). All three options have different pros and cons:
I could directly access the corresponding Author model, but if I request a Book model via REST, I maybe don't want the model now, but later. So option 2 would be better:
I could request a Book model directly via REST. And use the authorIds to afterwards fetch the corresponding author(s). But now I can't simply use myBook.getAuthors().
This is a mixture of 1. and 2.: If I just request the Books with only the Author ids included, I could do something like: idAuthorMap.put(authorId, null).
But maybe there's a Java library that handles all the stuff for me?!
That's it for now. Thank you guys :)
The maybe solution(s):
Problem: Select only the data I need. This means more or less to ignore every #ManyToMany, #OneToMany, #ManyToOne relations.
Solution: Use #JsonIgnore and/or #JsonIgnoreProperties.
Problem: Every ignored relation should get fetched easily without modifying the data model.
Solution: Example models:
class Book {
int bId;
Author author; // has #ManyToOne
}
class Author {
int aId;
List<Book> books; // has #OneToMany
}
Now I can fetch a book via REST: GET /books/4 and the result will look like that ('cause I ignore all relations via #JsonIgnore): {"bId":4}
Then I have to create another route to receive the related author: GET /books/4/author. Will return: {"aId":6}.
Backwards: GET /authors/6/books -> [{"bId":4},{"bId":42}].
There will be a route for every #ManyToMany, #OneToMany, #ManyToOne, but nothing more. So this will not exist: GET /authors/6/books/42. The client should use GET /books/42.
First, you will want to control how the JPA layer handles your relationships. What I mean is using Lazy Loading vs. Eager loading. This can easily be controller via the "fetch" option on the annotation like thus:
#OneToMany(fetch=FetchType.Lazy)
What this tells JPA is that, for this related object, only load it when some code requests it. Behind the scenes, what is happening is that a dynamic "proxy" object is being made/created. When you try to access this proxy, it's smart enough to go out and do another SQL to gather that needed bit. In the case of Collection, its even smart enough to grab the underlying objects in batches are you iterate over the items in the Collection. But, be warned: access to these proxies has to happen all within the same general Session. The underlying ORM framework (don't know how Eclipselink works...I am a Hybernate user) will not know how to associate the sub-requests with the proper domain object. This has a bigger effect when you use transportation frameworks like Flex BlazeDS, which tries to marshal objects using bytecode instead of the interface, and usually gets tripped up when it sees these proxy objects.
You may also want to set your cascade policy, which can be done via the "cascade" option like
#OneToMany(cascade=CascadeType.ALL)
Or you can give it a list like:
#OneToMany(cascade={CascadeType.MERGE, CascadeType.REMOVE})
Once you control what is getting pulled from your database, then you need to look at how you are marshalling your domain objects. Are you sending this via JSON, XML, a mixture depending on the request? What frameworks are you using (Jackson, FlexJSON, XStream, something else)? The problem is, even if you set the fetch type to Lazy, these frameworks will still go after the related objects, thus negating all the work you did telling it to lazily load. This is where things get more specific to the mashalling/serializing scheme: you will need to figure out how to tell your framework what to marshal and what not to marshal. Again, this will be highly dependent on whatever framework is in use.
i have a User entity with a password property. I want to store bcrypt hashed passwords in the database.
How can i handle the hashing as transparent as possible with jpa/eclipselink.
I want the hashing to take plase as late as possible and for the code that accesses the user to know as few as possible about the underlying hash mechanism (or its existence).
Currently i only access the password in jpql queries and the user doesn't even have a getPassword() method.
Greetings,
Laures
You can have different access methods; one set for the user and another for the JPA provider that handle the data underneath as required. The access methods required by the provider must deal with the data as it is needed to persist in the database. When using property access, just mark the get/set methods you want the provider to use with the mapping annotations, and either use different naming for user methods or mark them as transient. You are then free to store the data in the User entity how ever is needed.
I'm using DataNucleus as a JPA implementation to store my classes in my web application. I use a set of converters which all have toDTO() and fromDTO().
My issue is, that I want to avoid the whole DB being sent over the wire:
If I lazy load, the converter will try to access ALL the fields, and load then (resulting in very eager loading).
If I don't lazy load, I'll get a huge part of the DB, since user contains groups, and groups contains users, and so on.
Is there a way to explicitly load some fields and leave the others as NULL in my loaded class?
I've tried the DataNucleus docs with no luck.
Your DTOs are probably too fine-grained. i.e. dont plan to have a DTO per JPA entity. If you have to use DTOs then make them more coarse grained and construct them manually.
Recently we have had the whole "to DTO or not to DTO, that is the question" discussion AGAIN. The requirement for them (especially in the context of a JPA app) is often no longer there, but one of the arguments FOR DTOs tends to be that the view has coarser data requirements.
To only load the data you really require, you would need to use a custom select clause containing only these elements that you are about to use for your DTOs. I know how painful this is, especially when it involves joins, which is why I created Blaze-Persistence Entity Views which will take care of making the query efficient.
You define your DTO as an interface with mappings to the entity, using the attribute name as default mapping, this looks very simple and a lot like a subset of an entity, though it doesn't have to. You can use any JPQL expression as mapping for your DTO attributes.