Getting started on seam-security, picketlink IDM and JPAIdentityStore

I love how JBoss 7(.1) has everything working out of the box – not much fiddling with jars or suchlike and with Arquillian, everything really was a treat to get started on a new project. This was until I had to sort out security with seam-security.

To be fair, the main issue was just poor documentation. It took me a day to sort out what should essentially have taken an hour(or two)

The documentation you get to from http://www.seamframework.org/Seam3/SecurityModule seems to be out of date. The fact that the page referes to version 3.0.0.Alpha1 and Alpha2 should have tipped me off but the url for the doc suggested it was the latest.

The more up to date documentation I found was at http://docs.jboss.org/seam/3/3.1.0.Final/reference/en-US/html/pt04.html

I followed chapter 33 on there and I won’t repeat it here for the sake of brevity.

What follows are the additional steps I had to take to get it to work.

I ran into a javax.enterprise.inject.CreationException, the relevant part of the stack trace being:

Caused by: java.lang.IllegalArgumentException: targetClass parameter may not be null
	at org.jboss.solder.properties.query.PropertyQuery.(PropertyQuery.java:54) [solder-impl-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.solder.properties.query.PropertyQueries.createQuery(PropertyQueries.java:39) [solder-impl-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.findNamedProperty(JpaIdentityStore.java:441) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.configureRoleTypeName(JpaIdentityStore.java:877) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.bootstrap(JpaIdentityStore.java:328) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.picketlink.idm.impl.configuration.IdentityConfigurationImpl.createRealmMap(IdentityConfigurationImpl.java:192) [picketlink-idm-core-1.5.0.Alpha02.jar:1.5.0.Alpha02]
	at org.picketlink.idm.impl.configuration.IdentityConfigurationImpl.buildIdentitySessionFactory(IdentityConfigurationImpl.java:147) [picketlink-idm-core-1.5.0.Alpha02.jar:1.5.0.Alpha02]
	... 109 more

To resolve this,  I had to add in the @IdentityEntity Annotation to the IdentityObjectType class

@Entity
@IdentityEntity(EntityType.IDENTITY_ROLE_NAME)
public class IdentityObjectType {
...

The next exception was org.picketlink.idm.common.exception.IdentityException: Error creating identity object. The relevant part of the strack trace being:

Caused by: java.lang.NullPointerException
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.lookupIdentityType(JpaIdentityStore.java:966) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.createIdentityObject(JpaIdentityStore.java:999) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	... 87 more

It turned out that the entitymanager was not being picked up and it was null. This part was probably in the documentation earlier with regards to configuring seam but I had skipped directly to the security section so missed it. We need to define the persistence unit with the beans.xml. I have included my full file below.

<?xml version="1.0"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:em="urn:java:javax.persistence"
	xmlns:s="urn:java:ee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://jboss.org/schema/cdi/beans_1_0.xsd">

	<interceptors>
		<class>org.jboss.seam.security.SecurityInterceptor</class>
	</interceptors>

	<em:EntityManager>
		<s:Produces />
		<em:PersistenceContext unitName="invision-users" />
	</em:EntityManager>
</beans>

This brought us further forward still. The next exception was:

javax.persistence.NoResultException: No entity found for query
	at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:286) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
	at org.hibernate.ejb.criteria.CriteriaQueryCompiler$3.getSingleResult(CriteriaQueryCompiler.java:264) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.lookupCredentialTypeEntity(JpaIdentityStore.java:1112) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.updateCredential(JpaIdentityStore.java:1633) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.picketlink.idm.impl.repository.WrapperIdentityStoreRepository.updateCredential(WrapperIdentityStoreRepository.java:310) [picketlink-idm-core-1.5.0.Alpha02.jar:1.5.0.Alpha02]
	at org.picketlink.idm.impl.api.session.managers.AttributesManagerImpl.updatePassword(AttributesManagerImpl.java:563) [picketlink-idm-core-1.5.0.Alpha02.jar:1.5.0.Alpha02]

This was related to missing data in the database. It needed a credential type. I created one for password.

INSERT INTO CredentialType(id, name) VALUES (1, 'password');

This brought us forward on to the next exception: org.picketlink.idm.common.exception.IdentityException: Exception creating relationship

with the relevant part of

Caused by: javax.persistence.NoResultException: No entity found for query
	at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:286) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
	at org.hibernate.ejb.criteria.CriteriaQueryCompiler$3.getSingleResult(CriteriaQueryCompiler.java:264) [hibernate-entitymanager-4.0.1.Final.jar:4.0.1.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.lookupRelationshipType(JpaIdentityStore.java:1127) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	at org.jboss.seam.security.management.picketlink.JpaIdentityStore.createRelationship(JpaIdentityStore.java:1066) [seam-security-3.1.0.Final.jar:3.1.0.Final]
	... 86 more

This was solved by adding in a relationship type

INSERT INTO RelationshipType(id, name) VALUES (1, 'JBOSS_IDENTITY_MEMBERSHIP');

Both the sql statements were put into import.sql and hibernate is configured to create tables. My test case is as follows. It was taken from https://github.com/seam/seam-example-confbuzz/blob/develop/src/test/java/seam/example/confbuzz/test/integration/LoginIntegrationTest.java and modified.

@RunWith(Arquillian.class)
public class LoginIntegrationTest {

	@Inject
	private IdentitySession identitySession;

	@Inject
	private Identity identity;

	@Inject
	@DefaultTransaction
	SeamTransaction tx;

	@Deployment(name = "authentication")
	public static Archive createLoginDeployment() {
		// This is the simplest way to test the full archive as you will be
		// deploying it
		final MavenDependencyResolver resolver =
				DependencyResolvers.use(MavenDependencyResolver.class)
					.loadMetadataFromPom("pom.xml")
					.goOffline();

		Archive archive = ShrinkWrap
				.create(WebArchive.class)
				.addPackages(true, "uk.co.kraya.test-seam.auth")
				.addAsResource("META-INF/test-persistence.xml", "META-INF/persistence.xml")
				.addAsResource("META-INF/beans.xml", "META-INF/beans.xml")
				.addAsResource("test-import.sql", "import.sql")
				.addAsLibraries(resolver.artifact("org.jboss.seam.security:seam-security").resolveAsFiles());

		System.out.println(archive.toString(true));

		return archive;

	}

	@Before
	public void setupTestUser() throws IdentityException, SystemException,
			NotSupportedException, RollbackException,
			HeuristicRollbackException, HeuristicMixedException {

		if (!tx.isActive())
			tx.begin();

		final PersistenceManager pm = identitySession.getPersistenceManager();
		final AttributesManager am = identitySession.getAttributesManager();
		final RelationshipManager rm = identitySession.getRelationshipManager();

		// Setup the group we want our user to belong to
		final Group memberGroup = pm.createGroup("member2", "USER2");
		final User user = pm.createUser("test");

		am.updatePassword(user, "password");

		rm.associateUser(memberGroup, user);

		tx.commit();
	}

	@Test
	public void assertUserCanAuthenticate(Credentials credentials) {
		credentials.setUsername("test");
		credentials.setCredential(new PasswordCredential("password"));
		assertEquals(identity.login(), Identity.RESPONSE_LOGIN_SUCCESS);
	}

Do comment and let me know if it helped 😀

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.