Folks,
Here is my use model for users.
Login attempt
if user exists, then login them in (works fine)elseuser does not existinside
doGetAuthenticationInfo I create the user and return
Case #2 never makes it to doGetAurthorization method my login returns with "no
account for this user exists within shiro". But by this time the attempted
login created a user in the database.
On the second login attempt... all goes well and the user is logged in.
Can someone tell me whats going on here ?
Did I miss doing somethign within doGetAuthenticationInfo to let shiro know
that a user is now authenticated ?
Thanks for any help
Here is my realm...
package org.tynamo.examples.pphl.services.realms;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.shiro.authc.AccountException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.SaltedAuthenticationInfo;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.authz.permission.WildcardPermissionResolver;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.Sha1Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.SimpleByteSource;
import org.apache.tapestry5.alerts.AlertManager;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.services.ApplicationStateManager;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;
import org.slf4j.Logger;
import org.tynamo.builder.BuilderDirector;
import
org.tynamo.common.services.authenticationlisteners.SecurityAuthenticationToken;
import org.tynamo.examples.pphl.AdminLayoutBuilder;
import org.tynamo.examples.pphl.HitCounterBuilder;
import org.tynamo.examples.pphl.PersonBuilder;
import org.tynamo.examples.pphl.model.AdminLayout;
import org.tynamo.examples.pphl.model.HitCounter;
import org.tynamo.examples.pphl.model.Person;
import org.tynamo.examples.pphl.model.Person.Permission;
import org.tynamo.examples.pphl.model.Person.Role;
import org.tynamo.security.federatedaccounts.services.FederatedAccountService;
import org.tynamo.services.DescriptorService;
import org.tynamo.services.PersistenceService;
import org.tynamo.util.Utils;
/**
* Refer to RollingTokenRealm to finish proper federate logic
*
* @author Owner
*
*/
public class HibernateUserRealm extends AuthorizingRealm
{
public static final String HIBERNATEUSER_CLIENTID_USERNAME =
"hibernateuser.clientid";
public static final String HIBERNATEUSER_CLIENTSECRET_PASSWORD =
"hibernateuser.clientsecret";
public static final String HIBERNATEUSER_PERMISSIONS =
"hibernateuser.permissions";
public static final String HIBERNATEUSER_PRINCIPAL =
"hibernateuser.principal";
/**
* All we need to get into facebook and drill down is the login
* email/password and id for reference
*/
public static enum PrincipalProperty
{
id, email, name
};
private PrincipalProperty principalProperty;
private final Logger logger;
private FederatedAccountService federatedAccountService;
private Session session;
private String clientIdUserName;
private String clientSecretPassword;
private String permissions;
public HibernateUserRealm(Logger logger, FederatedAccountService
federatedAccountService, Session session,
@Inject @Symbol(HibernateUserRealm.HIBERNATEUSER_CLIENTID_USERNAME)
String clientIdUserName,
@Inject
@Symbol(HibernateUserRealm.HIBERNATEUSER_CLIENTSECRET_PASSWORD) String
clientSecretPassword,
@Inject @Symbol(HibernateUserRealm.HIBERNATEUSER_PERMISSIONS)
String permissions,
@Inject @Symbol(HibernateUserRealm.HIBERNATEUSER_PRINCIPAL) String
principalPropertyName)
{
super(new MemoryConstrainedCacheManager()); // caches your user account
// on next iterations thru
this.logger = logger;
this.federatedAccountService = federatedAccountService;
this.session = session;
// Let this throw IllegalArgumentException if value is not supported
this.clientIdUserName = clientIdUserName;
this.clientSecretPassword = clientSecretPassword;
this.permissions = permissions;
this.principalProperty =
PrincipalProperty.valueOf(principalPropertyName);
setName(HibernateUserRealm.class.getSimpleName());
// setAuthenticationTokenClass(FacebookAccessToken.class);
//setAuthenticationTokenClass(UsernamePasswordToken.class);
// !!!!!!! LISTENER SETUP HERE !!!!!!!
setAuthenticationTokenClass(SecurityAuthenticationToken.class);
setPermissionResolver(new WildcardPermissionResolver());
//setCredentialsMatcher(new
HashedCredentialsMatcher(Sha1Hash.ALGORITHM_NAME));
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principals)
{
if (principals == null)
throw new AuthorizationException("PrincipalCollection was null,
which should not happen");
if (principals.isEmpty())
{
System.out.println("principals collection is empty");
return null;
}
if (principals.fromRealm(getName()).size() <= 0)
{
System.out.println("principals from realm collection is empty");
return null;
}
//String username = (String)
principals.fromRealm(getName()).iterator().next();
//String username = (String)
principals.fromRealm(getName()).iterator().next();
//if (username == null)
// return null;
//Person person = findByUsername(username);
//if (person == null)
// return null;
Person user = applicationStateManager.get(Person.class);
// do roles
Set<String> rroles = new HashSet<String>(user.getRoles().size());
Set<Role> roles = user.getRoles();
for (Role role : roles)
rroles.add(role.name());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(rroles);
// do permissions
// this is enum - Set<String> permissions = new HashSet<String>();
Set<Permission> permissions = user.getPermissions();
for (Permission permission : permissions)
if (!principals.fromRealm(getName()).isEmpty())
info.addStringPermission(permission.name());
//SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
/*
Set<String> shiroPermissions = new HashSet<String>();
for (Person.Permission permission : Person.Permission.values())
{
shiroPermissions.add(permission.toString());
}
info.setStringPermissions(shiroPermissions);
Set<org.apache.shiro.authz.Permission> userPermissions = new
HashSet<org.apache.shiro.authz.Permission>();
for (Person.Permission permission : Person.Permission.values())
{
info.addObjectPermission(getPermissionResolver().resolvePermission(permission.name()));
// org.apache.shiro.authz.Permission p =
// getPermissionResolver().resolvePermission(permission.name());
// userPermissions.add(p);
}
// info.setObjectPermissions(userPermissions);
*/
return info;
}
private Person findByUsername(String username)
{
return (Person)
session.createCriteria(Person.class).add(Restrictions.eq("username",
username)).uniqueResult();
}
private Set<String> findRolesByUsername(Person person)
{
Set<String> result = new HashSet<String>();
Iterator<Role> iterator = person.getRoles().iterator();
while (iterator.hasNext())
{
Role role = iterator.next();
result.add(role.toString());
}
return result;
}
private Set<String> findPermissionsByUsername(Person person)
{
Set<Permission> permissions = new HashSet<Permission>();
Criteria criteria = session.createCriteria(Person.Permission.class);
criteria.add(Restrictions.eq("Person_id", person.getId()));
permissions.addAll(criteria.list());
Set<String> result = new HashSet<String>();
Iterator<Permission> iterator = permissions.iterator();
while (iterator.hasNext())
{
Permission permission = iterator.next();
result.add(permission.toString());
}
return result;
}
@Inject
private DescriptorService descriptorService;
@Inject
private BuilderDirector builderDirector;
@Inject
private PersistenceService persistenceService;
private PersonBuilder pb = new PersonBuilder();
private AdminLayoutBuilder ab = new AdminLayoutBuilder();
private HitCounterBuilder hcb = new HitCounterBuilder();
@Inject
private Messages messages;
@Inject
private AlertManager alertManager;
@Inject
private ApplicationStateManager applicationStateManager;
Person createPerson(String username, String password)
{
// Person bean = builderDirector.createNewInstance(Coach.class);
Person bean = pb.build();
bean.setUsername(username);
bean.setEmailAddress(username);
bean.setPassword(password);
bean.setFirstName(username.substring(username.indexOf('@') + 1));
bean.setLastName(username.substring(username.indexOf('@') + 1));
try
{
Transaction tx = session.beginTransaction();
persistenceService.save(bean);
alertManager.info(messages.getFormatter(Utils.ADDED_MESSAGE).format(bean));
tx.commit();
// session.flush();
// Transaction tx = session.beginTransaction();
// persistenceService.save(bean);
// session.save(bean);
//
alertManager.info(messages.getFormatter(Utils.ADDED_MESSAGE).format(bean));
return bean;
} catch (RuntimeException e)
{
// java.lang.RuntimeException: Exception constructing service
// 'DescriptorService': Error invoking constructor public
//
org.tynamo.services.DescriptorServiceImpl(java.util.Collection,org.tynamo.descriptor.factories.DescriptorFactory):
// java.lang.NullPointerException
alertManager.info(e.toString());
}
return null;
}
AdminLayout createAdminLayout()
{
// Person bean = builderDirector.createNewInstance(Coach.class);
AdminLayout bean = ab.build();
try
{
Transaction tx = session.beginTransaction();
persistenceService.save(bean);
alertManager.info(messages.getFormatter(Utils.ADDED_MESSAGE).format(bean));
tx.commit();
// session.flush();
// Transaction tx = session.beginTransaction();
// persistenceService.save(bean);
// session.save(bean);
//
alertManager.info(messages.getFormatter(Utils.ADDED_MESSAGE).format(bean));
return bean;
} catch (RuntimeException e)
{
// java.lang.RuntimeException: Exception constructing service
// 'DescriptorService': Error invoking constructor public
//
org.tynamo.services.DescriptorServiceImpl(java.util.Collection,org.tynamo.descriptor.factories.DescriptorFactory):
// java.lang.NullPointerException
alertManager.info(e.toString());
}
return null;
}
HitCounter createHitCounter()
{
// Person bean = builderDirector.createNewInstance(Coach.class);
HitCounter bean = hcb.build();
try
{
Transaction tx = session.beginTransaction();
bean.setLoginPageHits(new Integer(0));
persistenceService.save(bean);
alertManager.info(messages.getFormatter(Utils.ADDED_MESSAGE).format(bean));
tx.commit();
return bean;
} catch (RuntimeException e)
{
alertManager.info(e.toString());
}
return bean;
}
@Override
protected SaltedAuthenticationInfo
doGetAuthenticationInfo(AuthenticationToken token)
throws AuthenticationException
{
SecurityAuthenticationToken upToken = (SecurityAuthenticationToken)
token;
//UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = new String((String) upToken.getPrincipal()); //
typically
// a
//
username
// for a
// upt
String password = new String((String) upToken.getCredentials()); //
typically
//String password = new String(upToken.getPassword()); // typically
//
password
// for
// a
// upt
boolean rememberMe = upToken.isRememberMe();
// Null username is invalid
if (username == null)
{
throw new AccountException("Null usernames are not allowed by this
realm.");
}
if (password.toString().length() < 1)
{
throw new IncorrectCredentialsException("Password cannot be null.");
}
// Person person = findByUsername(username);
Criteria criteria = session.createCriteria(Person.class);
criteria.add(Restrictions.ilike("username", username));
Person person = (Person) criteria.uniqueResult();
HitCounter hc = findHitCounter();
if (person == null)
{
person = createPerson(username, password);
hc.setCreatedUsers( hc.getCreatedUsers() + 1 );
}
hc.setLoginPageHits( hc.getLoginPageHits() + 1 );
applicationStateManager.set(HitCounter.class, updateHitCounter(hc));
synchronized (applicationStateManager)
{
applicationStateManager.set(Person.class, person);
if (findAdminLayout() != null)
applicationStateManager.set(AdminLayout.class,
findAdminLayout());
else
{
createAdminLayout();
applicationStateManager.set(AdminLayout.class,
findAdminLayout());
}
}
SimpleByteSource bs = new
SimpleByteSource(Base64.decode(person.getPasswordSalt()));
return new SimpleAuthenticationInfo(username, token.getCredentials(),
bs, getName());
}
private HitCounter updateHitCounter(HitCounter bean)
{
try
{
Transaction tx = session.beginTransaction();
persistenceService.save(bean);
alertManager.info(messages.getFormatter(Utils.SAVED_MESSAGE).format(bean));
tx.commit();
} catch (RuntimeException e)
{
alertManager.info(e.toString());
}
return bean;
}
/**
* Find Methods
*
* @return
*/
private AdminLayout findAdminLayout()
{
return (AdminLayout)
session.createCriteria(AdminLayout.class).add(Restrictions.eq("id",
1)).uniqueResult();
}
private HitCounter findHitCounter()
{
HitCounter bean = (HitCounter)
session.createCriteria(HitCounter.class).add(Restrictions.eq("id",
1)).uniqueResult();
if (bean == null)
bean = createHitCounter();
return bean;
}
}