RESTful API hiding hibernate id and version - java

Let's say I have a User entity with an id and a version managed by hibernate, plus a firstname and a lastname.
I want to have CRUD operations on User instances with a RESTful API but I don't want the client to get the user's id and version stored in the database.
A simplistic solution I can think of is to send a representation of the user with modified id and version and to map the "public" values with the database values in a HashMap that lives in the server's memory. I also though of cookies, but I don't think it's a secure solution as they can be hacked by the client. AFAIK, a pure RESTful API must not handle session state on the server.
Is there a secure, scalable and RESTful way to publish resources without exposing their real ids and versions ?

Difficult one. You need the id or some representation of it somewhere in the URI to make GET requests.
Why are you worried about your users obtaining the real id?
One thing you could do is encrypt the user's id before it is sent to the front end and decrypt id in the back end using a symmetric encryption algorithm like AES.
See Symmetric-key algorithm

The best solution is to separate your UserEntity and UserData:
#Embeddable
class UserData {
String firstName;
String lastName;
... // getters and setters
}
// your mapped class
class UserEntity {
int id;
int version;
UserData data;
// getters and setters
}

If you're set on 'true' REST then you need to provide the client with the entire state of the object that they'll need to perform an action on it at a later time. Have you considered just applying a salt and some symmetric encryption to fields that you don't want users to be able to modify? Passing the hashes around will increase your payload size obviously, but everything comes with a cost, especially security!

Related

how to detect the user in OpenID Connect provider token endpoint

talking about the authorization_code grant type. In authorization end point of the OpenID Connect provider we gave an authorization code to the relying party and then they makes a back channel request(no browser involved) to the token end point with this code.
so the question is , How to distinguish this user at the token end point?I guess no session exist for this call since its a back channel request.
What methods can be used to identify the user. could a stored HashMap in memory with key as authorization_code be the ideal solution
Storing it in a HashMap is a solution that does not scale, as internal memory is not shared accross server nodes.
You'll have to store it in some form of persistent store
a SQL database
a NoSQL database
a key value database
Note that you'll not only need to be able to determine the user, for which it was made, but also the client, as clients don't need to authenticate themselves to get a code. Also know that you'll need to be able to determine which scopes are covered by a given code, and to detect double usage of a code, and in case of double usage, to revoke associated access tokens.
On the other hand, you need to be able to easily forget the codes again. They're short term use, and it's no use keeping them around after their ttl.
You'll have similar requirements for storing the access tokens, refresh and id tokens you produce, so it'll make sense to build something which can also be used for those.

What can I use instead of an entity bean?

I would like to write a Java EE app for online learning. I'm thinking of this data representation:
#Entity
public class Course {
private String name;
private String[] instructors;
private String[] teachingAssistants;
private GradeBook gradeBook;
// plenty of methods
}
#Entity
public class GradeBook {
private GradeBookColumn[];
// some methods
}
#Entity
public abstract class GradeBookColumn {
private String name;
private GradeBookColumnType type;
// more methods
}
I would have quite a lot more than just that, but you get the point.
Now, in the EJB 3.2 spec, entity beans were removed and replaced with JPA entities. My question is how to cope with this tragic loss. There are three reasons why serialized JPA entities won't work for me:
Performance. I will need to push the whole entity and all of its data through the net. There is quite a lot of that data, and it could take an unacceptably long time to get it all through.
Security. If all the data in the entity is transferred over the net, then all of the data is accessible to the program that downloaded it. However, I want certain data to only be accessible if the user has sufficient permissions.
Write Access. Once the copy of the data has been downloaded, the client should be able to make changes to it. However, if the changes are made, they won't be persisted to the server. Of course, I could always send the entity back to the server for persisting, but I would have to send all the data through an even slower upstream connection.
So, how do I design this system to meet these requirements without entity beans?
I'm not sure that the loss of entity beans is really tragic, but that's a matter of opinion :)
You seem that have a rich client on the desktop that connects to a remote server. You have two options:
A. You exchange "detached" object graphs between the client and server. The client receives some data, modifies it, then sends it back. The server then "merges" the data it receives. There is one transaction on the server when you load the data, and one when you merge back. To ensure you don't have conflict, you can version the data.
B. You use an "extended persistence context". In that case, the client receives entites that are still "attached" to a session. Modification to the entities on the client side are cached, and will be synchronized when you call a method on the server.
So, regarding the three design issue you face, here is my take on it:
Performance. JPA and other modern ORM rely on laziness to avoid unnecessary data transfer: data is loaded on demand. You can choose which part of the graph can be loaded eagerly or lazily. With option A, you need to make sure that you load all the necessary data before you send them to the client; if the client attempts to access data that aren't loaded, it gets an exception since it's outside of a transaction. With option B, I guess the client can lazy load data anytime (it would be worth double checking that).
Security. The JPA entities should be business objects, not data object. They can encapsulate business methods that do the necessary checks and preserve the desired invariants. In other words: security is not handled at the data level but at the business logic level. This applies for both options A and B.
Write Access. With option A, you need to send back the whole graph and merge it. With option B, the framework should merge the changes that have been cached in a more optimized way.
Conclusions:
Extended persistence contexts have been designed for GUI applications with long units of work. They should in theory solve your problems. In practice, extended persistence contexts have their share of complexitiy though (e.g. needs to use stateful session beans).
The approach to detach and merge the graph is simpler, but raises the issues that you mention in terms of performance.
The third options is to go back to traditional data transfer object (DTO) to optimize performance. In that case the JPA entites stay exclusively on the server side. Instead of transferring JPA entites, you transfer only the subset of the data really needed into DTOs. The drawback is that DTOs will proliferate, and you will have boilerplate code to create DTOs from JPA entites, and update the JPA enties from DTOs.

Providing entities to the client using JAX-WS

I am trying to create a web service using JAX-WS (SOAP) allowing CRUD operations on some entities. I am also writing a desktop client with an UI which provides easy means of doing CRUD on those entities via the web service.
However, I am running into some design issues. I would like the client to only be able to view and manipulate certain fields of an entity, and I'm not sure what's the best way to impose this restriction.
For instance, given:
#Entity
public class Customer {
#Id
#GeneratedValue
public Long id;
public String name;
// neither read nor write from the web service
public String password;
// read-only from the web service
#Temporal(TemporalType.DATE)
public Date joinedAt;
#ManyToOne
#LazyCollection(LazyCollectionOption.FALSE)
private List<Order> orders;
// .. boilerplate getters and setters
}
#Entity
public class Order {
#Id
#GeneratedValue
public Long id;
public String name;
}
I would like to provide the client with these basic operations:
get the list of all customers with their orders
he can see all the fields EXCEPT for password
create a new customer with some orders
allow control to all fields EXCEPT FOR joinedAt and password
modify a customer
same as above, you're not allowed to modify joinedAt or password
.
My current solution for (1) is to add #XmlTransient to the password field. This is problematic if you want to send the password to certain clients but not to others. Another solution would be to do customer.setPassword(null); before marshalling that entity via
the webservice. But is this really the way to do it? A third solution would be to create a base class BaseCustomer which contains all the fields except for password and then Customer would be a BaseCustomer with the added password field. The user would receive a BaseCustomer object instead of a Customer one. But this has problems with create/update as well.
Same as for (1), one solution is to do customer.setJoinedAt(my_value); customer.setPassword(my_value); customer.setId(null); when the client wants to create a new customer. Is manually nulling the id really best practice? I find that hard to believe. Should the id be XmlTransient as well? But then how would the user of the web service be able to modify/delete entities?
When the client wants to change a Customer, he retrieves the list of customers, makes changes to one of the Customer objects, then marshals that object and passes it back to the web service.
There are a few problems with this: if the id field is XmlTransient, then the EntityManager's persist won't know which row to modify and would likely create a new one. A similar issue raises if the user is evil and simply refuses to pass an id, so I have to manually check that the id is non-null. Moreover, the user has not received the password field, so now the server has received an object with a null password field which it will attempt to persist. I believe this will cause the EntityManager to completely remove the password of that existing Customer. Having the user specify exactly which fields he wants modified and to which values seems impractical.
Note that this is just a proof-of-concept of what I need to do in a nutshell, I have far more entities, relations and operations to provide.
I am new to using these technologies and I was hoping that being so high level and having so many abstractions would make my life easier, but so far it has been mostly headaches. It appears very difficult to achieve this common, basic task. Am I doing something wrong? Please don't suggest creating a web application instead :)

Is there any security concern with displaying the Key value to users in a URL?

I am using the Key value of entities in my datastore as the unique identifier in the URL for pulling up a record:
http://mysite.appspot.com/myaction/1x7s3fgdlbnRlcklkcicLAbcXc2VyQWNjb3VudCIFYW9uZ
This is not a very attractive solution, nor is it SEO friendly, but it's the easiest way I've found to identify an entity uniquely in App Engine/Java.
My main concern, though, is whether there is any security concern related to displaying the unique Key value for the entity?
The encoded key contains your app ID, namespace (if any), entity kind name, and key name or ID. There's two possible issues here: the disclosure of that information (probably not problematic), and the fact that you're accepting an encoded key. If you don't check that the entity specified by the key being passed in is of the correct kind, and that the user should have access to it, then they could pass in their own key to cause you to disclose information you shouldn't.
Almost universally, however, you already know the kind name of the entity you're fetching, so a much better idea is to use just the key name or ID of the key, and construct the full key on demand. This also makes for much cleaner URLs.
The security concern is that a potential hacker knows something, however small, about your database.
If parts of your database are ever compromised the entity id could prove useful for the hacker.
Like you I don't really like displaying database IDs but IF you secure your application properly it isn't worth worrying about as knowing the entity id isn't going to be useful.
Are you sure that's an actual key? It doesn't look like one (the un-base64'd data generally includes your app identifier, for one).
The documentation covers it, though:
Note: A string-encoded key can be converted back to the raw key data. This makes it easy to guess other keys when one is known. While string-encoded key values are safe to include in URLs, an application should only do so if key guessability is not an issue.
It's a lot cleaner to do something like this:
foo = FooModel.get_by_id(int(foo_id))
That doesn't stop attackers from guessing IDs, but at least it doesn't fool you into thinking that IDs are "opaque" (and you can trivially change the ID to test access control, instead of needing to mess around with base64-protobuf-encoded data).
This is not a security concern in my opinion. Lots of sites use id as identifier within the site. A key is just a key to a row in a database table, you do want to refrain from showing much detail about your database in terms of table and user accounts etc.
In this regard, you want to prohibit your site from dumping out database errors when they occur, catch them and handle nicely.

Custom ID in session handling by Java Servlet API

Is it possible to assign a custom ID to a HTTP session through Servlet API?
I know that session handling from any application server, Tomcat for example, it's enough good to generate unique IDs. But I have custom unique session IDs based on information per user and time, so it won't be repeated.
And I looked at every documentation about session handling but nowhere I find what I need.
It's a requirement for a project, so if it's not possible, I need to know the reasons (or it's only not available through API?).
If you are using Tomcat, you may be able to create a custom session manager (see this discussion). You would then have access to the Tomcat Session object and could call setId.
The servlet API does not support creating your own cookie value. In fact, it does not guarantee that sessions are maintained via cookies... it specifically states that they can be maintained via a mechanism such as "URL Rewriting". It DOES guarantee that the session is maintained in some fashion, and that pretty much requires some sort of unique ID which is passed to the browser and returned, but no mechanism is provided in the Servlet API for servlet code to control what value is used. Nor do common servlet containers that I know of (such as Tomcat) provide a means for controlling this value.
However, none of this should be a problem for you if I understand your requirements properly. Just because Tomcat (or whatever servlet container you use) is creating a unique ID based on its own algorithms (that contain things like cryptographically secure random number generators to prevent "guessing" of session IDs), doesn't mean that you cannot create a SEPARATE ID which meets your requirements (based on user and time, unique across all sessions... whatever you need). This ID can be stored in the session (if that's all you need), or can be stored on the browser in a separate cookie (if you need it maintained across sessions). The only effect would be that the browser was storing TWO cookies -- and most websites store many more cookies than that!
Um...if you have the code to generate a unique ID, you can just do this:
/**
* The String key of the user id attribute.
*/
public static final String USER_ID_KEY = "userIdKey";
// Set the user attribute (createUniqueUserId's parameters and return type are up to you)
httpSession.setAttribute(USER_ID_KEY, createUniqueUserId());
// Retrieve the user attribute later
httpSession.getAttribute(USER_ID_KEY);
The HttpSession interface also provides a getId() method, which is documented here (copying the documentation for reference):
public java.lang.String getId()
Returns a string containing the unique
identifier assigned to this session.
The identifier is assigned by the
servlet container and is
implementation dependent.
Returns: a
string specifying the identifier
assigned to this session

Categories