Friday, March 21, 2008

Hibernate Session vs. EntityManager

The answer to the question below is depressingly easy. I was overthinking the problem. Session is Hibernate's custom implementation; EntityManager is the standard JPA creature. If you want to stick to the standards (in this case, I do, although the odds of our shifting to a different JPA provider are very slender), stick to EntityManager. The big thing I'm missing out on so far is access to Hibernate's various CascadeTypes; the JPA default CascadeTypes are rather limited.

The way I'm working lately

This is actually almost fun.

Figure out some functionality that needs to exist. Within a unit test, write the top-level code for it regardless of whether the supporting methods exist or not.

List people = populationDao.getPeople();

...even if I haven't written populationDao.getPeople() yet.

Eclipse will complain that I have written references to methods that don't exist. Hit control-1 and choose the answer that is "create method 'getPeople' in interface 'populationDao'." Then, of course, PopulationDaoImpl will have errors, because I have a method in populationDao that I haven't implemented. Open up PopulationDaoImpl, control-1, 'add unimplemented methods,' and write the implementation for getPeople().

This way I know that getPeople() has at least some test coverage right from the start.

Monday, March 17, 2008

Open Hibernate Question

Open question: I see in the Hibernate documentation that Hibernate's EntityManager is "similar to" Hibernate's Session interface. But it isn't clear when I should be using one versus the other. I'm using the EntityManager now and everything's going fine. But I want to make sure I'm doing this The Right Way so that I don't have to rip it apart and rewrite it in three months when I better understand the business problems I'm fighting. Any readers have any insight?

Friday, March 7, 2008

Acegi: It Makes Sense Now

I was trying to write a massive security infrastructure beast. I don't need to do that.

The first thing I've done since the last post is to write my own 'SecurityService' class that implements the UserDetailsService interface. UserDetailsService has just one method -- UserDetails loadUserByUsername(String). So it takes a username and loads that whole user object.

Well this confused me. Where the hell, I thought, does the password get dealt with here?

The answer is that the password is handled by the Authentication Provider (in this example, an org.acegisecurity.providers.dao.DaoAuthenticationProvider). So this particular authentication provider accepts a username and password, uses the username to pull the UserDetails data out of the UserDetailsService, and then (in memory) (presumably) compares the submitted password to the password returned from the UserDetails object's getPassword() method.

I'm not thrilled by this implementation, because it assumes that passwords will be stored in plaintext! They shouldn't be.

Anyway, I verified all of this by building out a deliberately stupid implementation of the UserDetailsService and wiring it into my application -- specifically I wrote one that always returns the same UserDetails object, with a known and bogus username and password. I tested this and it worked, so it all makes more sense to me now. Next step is to rewrite my bogus UserDetailsService to talk to my actual application code and return real user objects.

Down the road a bit I'm probably going to have to look at the other authentication providers, so that I can handle encrypted passwords. But in the interim this is good progress.

Stupid side note: for some reason, whenever I log in, users are getting redirected to an image file the first time.

Back with Acegi

After a ColdFusion-induced layoff I'm back hacking at Acegi Security.

At this point I have a simple (very simple) Struts 2 application in place and I'm applying Acegi Security to it.

What I've done so far is taken the Acegi Petclinic Tutorial and applied it to my application. I used just about the simplest possible security implementation there -- I changed some names in their default users.properties file and implemented properties-file-driven security.

So far it does work, though -- the login page is exposed to all comers, while the more secure pages deeper in the app are hidden. Routing to the "landing" page upon login works correctly as well.

Next I want to change authentication so that it looks at my users table instead of looking at the properties file. I'll continue to assume just two levels of authorization (anonymous and logged-in user). The Acegi Security reference documentation suggests that I'm going to want to implement the UserDetailsService interface... but of course UserDetailsService doesn't accept a password argument. So I'm going to have to figure out what to do to really authenticate the user, as opposed to just looking them up.