Archive for the ‘Articles in English’ Category

Spring managed Hibernate interceptor in JPA

Saturday, January 24th, 2009

I have been trying to teach Hibernate injecting dependencies into Entities (I know, there is magic @Configurable annotation, I wanted to try it without magic). It is quite easy to do it using Hibernate interceptor (for example like this). But there is one drawback. It is not straightforward to inject interceptor into Hibernate when JPA abstraction is in the way.

It is simple to define interceptor in persistence.xml using hibernate.ejb.interceptor property. But it is only possible to specify class name, you can not inject Spring bean. If you read documentation to Spring LocalContainerEntityManagerFactoryBean there is no possibility to specify the interceptor bean there neither. But there is a way how to achieve it. First of all, you have to redefine Hibernate PersistenceProvider.

public class ConfigurableHibernatePersistence extends HibernatePersistence {
	private Interceptor interceptor;
	public Interceptor getInterceptor() {
		return interceptor;
	}

	public void setInterceptor(Interceptor interceptor) {
		this.interceptor = interceptor;
	}

	@SuppressWarnings("unchecked")
	@Override
	public EntityManagerFactory createContainerEntityManagerFactory(PersistenceUnitInfo info, Map map) {
		Ejb3Configuration cfg = new Ejb3Configuration();
		Ejb3Configuration configured = cfg.configure( info, map );
		postprocessConfiguration(info, map, configured);
		return configured != null ? configured.buildEntityManagerFactory() : null;
	}

	@SuppressWarnings("unchecked")
	protected void postprocessConfiguration(PersistenceUnitInfo info, Map map, Ejb3Configuration configured) {
		if (this.interceptor != null)
		{
			if (configured.getInterceptor()==null || EmptyInterceptor.class.equals(configured.getInterceptor().getClass()))
			{
				configured.setInterceptor(this.interceptor);
			}
			else
			{
				throw new IllegalStateException("Hibernate interceptor already set in persistence.xml ("+configured.getInterceptor()+")");
			}
		}
	}
}

(source)

Here we override method createContainerEntityManagerFactory in order to add postprocessConfiguration method call. In this method, it is possible to change Hibernate configuration as needed. Now the only thing to be done is configuring Spring to use our new PersistenceProvider. It is quite simple.

	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
		<property name="persistenceUnitName" value="testPU" />
		<property name="dataSource" ref="dataSource" />
		<property name="persistenceProvider">
			<bean class="net.krecan.javacrumbs.jpa.interceptor.ConfigurableHibernatePersistence">
				<property name="interceptor">
					<bean class="net.krecan.javacrumbs.jpa.interceptor.SpringInjectingInterceptor"/>
				</property>
			</bean>
		</property>
	</bean>

And that all folks, we have Spring configured interceptor even when using JPA abstraction. It would be better if similar classes were in Spring or Hibernate, but it's just few lines of code so feel free to copy them if you need to. If you know easier way how to do it, please mention it in the comments below.

JavaFX security

Tuesday, December 16th, 2008

I had some concerns regarding JavaFX security. You know, if you go to JavaFX samples page, most of them are self-signed and you have to give them all permissions to be able to run them. I didn't like it at all. On Devoxx I asked few guys from Sun about it and their responses were not clear. So I have decided to do few experiments to find out how it works. It's nothing new, it's similar to the way applets have worked all the time. But who remembers how applet security works?

I took InterestingPhotos sample application from JavaFX pages and added following code to onNext function (behold, my very first JavaFX code).

try {
	var writer = new FileWriter(new File(System.getProperty("user.home"),"javafx_infection.txt"));
	writer.append("I have escaped the browser. {new Date()}");
	writer.close();
} catch (e:Exception) {
	e.printStackTrace();
}

Now every time user clicks on the “next” button, the applet attempts to write to a file in user home directory. It can be both a malicious code or a legitimate action. There is no way to tell them apart. That's the reason why we need some security mechanism.

Unsigned application
Example
You can choose not to sign the application at all. Usually it is the best choice. This way the application will run in a sandbox and will not be able to execute any potentially dangerous code. On the other hand it will be safe for user to run it and he will not be troubled by any security alert. If the application attempts to execute dangerous code, the JRE will throw a security exception. In our case it will throw

java.security.AccessControlException: access denied (java.util.PropertyPermission user.home read)
at java.security.AccessControlContext.checkPermission(Unknown Source)
at java.security.AccessController.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPermission(Unknown Source)
at java.lang.SecurityManager.checkPropertyAccess(Unknown Source)
at java.lang.System.getProperty(Unknown Source)
at interesting.Main.hackIt(Main.fx:406)
at interesting.Main.onNext(Main.fx:133)

So if you don't need to do anything dangerous and you are happy to play in the sandbox, unsigned application is the best choice.

Selfsigned application
Example
Most of the samples on JavaFX page are self-signed. It means that the JAR is signed by a certificate that is not verified by any certification authority. In my opinion, that's the worst option you can choose. You force the user to answer following security dialog.

Security Warning

Basically it's the same as executing EXE (or binary) file only more dangerous. Some users already know that they should not execute EXE files from unknown sources, but they don't know that they shouldn't execute Java applications from unknown sources. I am afraid that we will hear about this issue more in the future.

If the user clicks on Run, the application can do whatever it want, if the user clicks on Cancel, the application will not run at all.

Signed application
Example
We can sign the application by a certificate that is validated by a CA. I have used Thawte Freemail Certificate. Sounds trustworthy, doesn't it? If you open the example, you will see following security warning.

Security Warning

It looks less threatening than with the selfsigned certificate. It looks less dangerous. The “Always trust” check-box is even checked by default. But in fact, it's not much safer. It is more complicated to generate such certificate but anyone (even me) can do it. It might be even more dangerous. Everyone who is able to generate a certificate that is validated by the same CA will be allowed to execute the code (if you leave the check box checked). And again, it is all or nothing choice. User can either give the application all permissions or do not run it at all.

Unsigned application with signed JAR
Example
In case you really need to do something potentially dangerous and you do not want to scare the user at the start of the application, you can use signed JAR in an unsigned application. Basically you can put all the dangerous stuff into a jar and sign only this jar. Most of the code can live in the main application which is unsigned. This way the application will start as unsigned and when you attempt to execute the dangerous parts the signed jar will be loaded and the security warning will be shown. In our example the application will start and the security warning will be shown when user clicks on the “next” button. At least that's how it works on my machine. And I like it. This way user can use my application and is notified only when the application needs to do something insecure. And even if he decides that he doesn't trust me, he can still use the application. (This idea came from a guy from Sun, unfortunately I don't remember his name, thanks anyway)

To reiterate, the most secure choice is to write a JavaFX application that does not need any security permissions. If you do not sign it, it runs in the sandbox and everything is fine. If you need to execute some dangerous code, you have to ask user for a permission. Which is good, but users should be instructed that they shouldn't execute any Java(FX) code if they are not sure what it does. So there is a possibility that they will not execute your applications because they will be afraid to do so. I can imagine that in the next versions of JavaFX there will be a signed library provided by Sun that will contain operations that are potentially dangerous but that are in fact safe. Like opening a file using “Open File dialog” etc.

Disclaimer: I am server-side developer, I know nothing about client-side Java, so do not be surprised if something I have written here turns up being wrong. Just correct it in the comments. Thanks.

Date puzzle

Wednesday, November 26th, 2008

I like surprises, I like puzzles, therefore I like Java Date and Calendar library. I already thought that there is nothing it could surprise me with. And I was wrong. Today it got me again. Consider the following code snippet.

		Calendar calendar = Calendar.getInstance();
		calendar.clear();
		calendar.set(Calendar.YEAR, 1970);
		calendar.set(Calendar.MONTH, 0);//month is zero based
		calendar.set(Calendar.DAY_OF_MONTH, 1);
		Date date = calendar.getTime();
		System.out.println(date);
		System.out.println(date.getTime());

The command on the line 07 prints out "Thu Jan 01 00:00:00 GMT 1970", the question is what does the command on the line 08 prints? If you are such looser and you do not remember the JavaDoc of java.util.Date class, here is the description of getTime() method.

Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object.

So to reformulate the question, what is the number of milliseconds between January 1, 1970, 00:00:00 GMT and Thu Jan 01 00:00:00 GMT 1970?

What are your guesses? Make yourself famous by adding a comment with correct explanation. And do not worry, if you do not find the solution until tomorrow evening, I will post it here.