[main]
saltedJdbcRealm=com.ctr.mdl.commons.web.security.shiro.JdbcRealmImpl
# any object property is automatically configurable in Shiro.ini file
saltedJdbcRealm.jndiDataSourceName=dummyDS
# the realm should handle also authorization
saltedJdbcRealm.permissionsLookupEnabled=true
# If not filled, subclasses of JdbcRealm assume "select password from users where username = ?"
# first result column is password, second result column is salt
saltedJdbcRealm.authenticationQuery = SELECT password, salt FROM crm_users WHERE username = ?
# If not filled, subclasses of JdbcRealm assume "select role_name from user_roles where username = ?"
saltedJdbcRealm.userRolesQuery = SELECT name FROM crm_roles a INNER JOIN crm_user_roles b ON a.id=b.role_id INNER JOIN crm_users c ON c.id=b.user_id WHERE c.username = ?
# If not filled, subclasses of JdbcRealm assume "select permission from roles_permissions where role_name = ?"
saltedJdbcRealm.permissionsQuery = SELECT action FROM crm_permissions WHERE role = ?
# password hashing specification, put something big for hasIterations
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName=SHA-256
sha256Matcher.hashIterations=1
saltedJdbcRealm.credentialsMatcher = $sha256Matcher
cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile=classpath:ehcache.xml
securityManager.cacheManager=$cacheManager
shiro.loginUrl = /login.xhtml
[urls]
/login.xhtml = authc
/logout = logout
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.1</version>
</dependency>
package com.ctr.mdl.commons.web.security.shiro;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.util.JdbcUtils;
import org.apache.shiro.util.SimpleByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author Edward P. Legaspi
* @since Oct 15, 2012
*/
public class JdbcRealmImpl extends JdbcRealm {
private static final Logger log = LoggerFactory
.getLogger(JdbcRealmImpl.class);
protected String jndiDataSourceName;
public JdbcRealmImpl() {
}
public String getJndiDataSourceName() {
return jndiDataSourceName;
}
public void setJndiDataSourceName(String jndiDataSourceName) {
this.jndiDataSourceName = jndiDataSourceName;
this.dataSource = getDataSourceFromJNDI(jndiDataSourceName);
}
private DataSource getDataSourceFromJNDI(String jndiDataSourceName) {
try {
InitialContext ic = new InitialContext();
return (DataSource) ic.lookup(jndiDataSourceName);
} catch (NamingException e) {
log.error("JNDI error while retrieving " + jndiDataSourceName, e);
throw new AuthorizationException(e);
}
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
// identify account to log to
UsernamePasswordToken userPassToken = (UsernamePasswordToken) token;
String username = userPassToken.getUsername();
if (username == null) {
log.debug("Username is null.");
return null;
}
// read password hash and salt from db
PasswdSalt passwdSalt = getPasswordForUser(username);
if (passwdSalt == null) {
log.debug("No account found for user [" + username + "]");
return null;
}
// return salted credentials
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username,
passwdSalt.password, getName());
info.setCredentialsSalt(new SimpleByteSource(passwdSalt.salt));
return info;
}
private PasswdSalt getPasswordForUser(String username) {
PreparedStatement statement = null;
ResultSet resultSet = null;
Connection conn = null;
try {
conn = dataSource.getConnection();
statement = conn.prepareStatement(authenticationQuery);
statement.setString(1, username);
resultSet = statement.executeQuery();
boolean hasAccount = resultSet.next();
if (!hasAccount)
return null;
String salt = null;
String password = resultSet.getString(1);
if (resultSet.getMetaData().getColumnCount() > 1)
salt = resultSet.getString(2);
if (resultSet.next()) {
throw new AuthenticationException(
"More than one user row found for user [" + username
+ "]. Usernames must be unique.");
}
return new PasswdSalt(password, salt);
} catch (SQLException e) {
final String message = "There was a SQL error while authenticating user ["
+ username + "]";
if (log.isErrorEnabled()) {
log.error(message, e);
}
throw new AuthenticationException(message, e);
} finally {
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(statement);
JdbcUtils.closeConnection(conn);
}
}
class PasswdSalt {
public String password;
public String salt;
public PasswdSalt(String password, String salt) {
super();
this.password = password;
this.salt = salt;
}
}
}
@EntityRole.java
@Table(name = "CRM_USERS")
@SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CRM_USERS_SEQ")
public class User implements Serializeable {
private static final long serialVersionUID = 6142315693769197546L;
@Id
@GeneratedValue(generator = "ID_GENERATOR")
private Long id;
@Column(name = "USERNAME", length = 50, unique = true)
private String userName;
@Column(name = "PASSWORD", length = 250)
private String password;
@Column(name = "SALT", length = 100)
private String salt;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "CRM_USER_ROLES", joinColumns = @JoinColumn(name = "USER_ID"), inverseJoinColumns = @JoinColumn(name = "ROLE_ID"))
private Listroles = new ArrayList ();
}
@Entity(name = "com.ctr.mdl.models.user.Role")Permission.java
@Table(name = "CRM_ROLES")
@SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CRM_ROLES_SEQ")
public class Role implements Serializable {
private static final long serialVersionUID = 6142315693769197546L;
@Id
@GeneratedValue(generator = "ID_GENERATOR")
private Long id;
@Column(name = "NAME", nullable = false, length = 50)
private String name;
@Column(name = "DESCRIPTION", nullable = false, length = 50)
private String description;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name = "CRM_USER_ROLES", joinColumns = @JoinColumn(name = "ROLE_ID"), inverseJoinColumns = @JoinColumn(name = "USER_ID"))
private Listusers = new ArrayList ();
}
@Entity
@Table(name = "CRM_PERMISSIONS")
@SequenceGenerator(name = "ID_GENERATOR", sequenceName = "CRM_PERMISSIONS_SEQ")
public class Permission implements Serializeable {
private static final long serialVersionUID = -2844386098501951453L;
@Column(name = "ROLE", nullable = false)
private String role;
@Column(name = "ACTION", nullable = false, length = 1500)
private String action;
public String getRole() {
return role;
}
}