Permalink
Browse files

Storing user names, passwords, roles and permissions in database.

  • Loading branch information...
1 parent 60562e9 commit 85434cdc3efea66dfdd64efd30da2bb8f9dce57b meri committed Mar 22, 2011
View
26 pom.xml
@@ -12,14 +12,24 @@
<!-- Compile 3rd party dependencies: -->
<jdk.version>1.6</jdk.version>
<slf4j.version>1.6.1</slf4j.version>
- <shiro.version>1.2.0-SNAPSHOT</shiro.version>
+ <shiro.version>1.2.0-SNAPSHOT</shiro.version>
<!-- Test 3rd-party dependencies: -->
<junit.version>4.8.2</junit.version>
- <jetty.version>6.1.21</jetty.version>
+ <jetty.version>6.1.26</jetty.version>
</properties>
<dependencies>
+ <dependency>
+ <groupId>org.liquibase</groupId>
+ <artifactId>liquibase-core</artifactId>
+ <version>2.0.1</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.derby</groupId>
+ <artifactId>derby</artifactId>
+ <version>10.7.1.1</version>
+ </dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
@@ -77,6 +87,18 @@
<version>${jetty.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-naming</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mortbay.jetty</groupId>
+ <artifactId>jetty-plus</artifactId>
+ <version>${jetty.version}</version>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
@@ -0,0 +1,142 @@
+package org.meri.simpleshirosecuredapplication.realm;
+
+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.AccountException;
+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.UnknownAccountException;
+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;
+
+public class JNDIAndSaltAwareJdbcRealm extends JdbcRealm {
+
+ private static final Logger log = LoggerFactory.getLogger(JNDIAndSaltAwareJdbcRealm.class);
+
+ protected String jndiDataSourceName;
+
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+ UsernamePasswordToken upToken = (UsernamePasswordToken) token;
+ String username = upToken.getUsername();
+
+ // Null username is invalid
+ if (username == null) {
+ throw new AccountException("Null usernames are not allowed by this realm.");
+ }
+
+ Connection conn = null;
+ AuthenticationInfo info = null;
+ try {
+ conn = dataSource.getConnection();
+
+ PasswdSalt passwdSalt = getPasswordForUser(conn, username);
+
+ if (passwdSalt == null) {
+ throw new UnknownAccountException("No account found for user [" + username + "]");
+ }
+
+ SimpleAuthenticationInfo saInfo = new SimpleAuthenticationInfo(username, passwdSalt.password, getName());
+ saInfo.setCredentialsSalt(new SimpleByteSource(passwdSalt.salt));
+
+ info = saInfo;
+
+ } catch (SQLException e) {
+ final String message = "There was a SQL error while authenticating user [" + username + "]";
+ if (log.isErrorEnabled()) {
+ log.error(message, e);
+ }
+
+ // Rethrow any SQL errors as an authentication exception
+ throw new AuthenticationException(message, e);
+ } finally {
+ JdbcUtils.closeConnection(conn);
+ }
+
+ return info;
+ }
+
+ private PasswdSalt getPasswordForUser(Connection conn, String username) throws SQLException {
+
+ PreparedStatement ps = null;
+ ResultSet rs = null;
+ String password = null;
+ String salt = null;
+ try {
+ ps = conn.prepareStatement(authenticationQuery);
+ ps.setString(1, username);
+
+ // Execute query
+ rs = ps.executeQuery();
+
+ // Loop over results - although we are only expecting one result, since usernames should be unique
+ boolean foundResult = false;
+ while (rs.next()) {
+
+ // Check to ensure only one row is processed
+ if (foundResult) {
+ throw new AuthenticationException("More than one user row found for user [" + username + "]. Usernames must be unique.");
+ }
+
+ password = rs.getString(1);
+ if (rs.getMetaData().getColumnCount()>1)
+ salt = rs.getString(2);
+
+ foundResult = true;
+ }
+ } finally {
+ JdbcUtils.closeResultSet(rs);
+ JdbcUtils.closeStatement(ps);
+ }
+
+ return new PasswdSalt(password, salt);
+ }
+
+ 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);
+ }
+ }
+
+
+}
+
+class PasswdSalt {
+
+ public String password;
+ public String salt;
+
+ public PasswdSalt(String password, String salt) {
+ super();
+ this.password = password;
+ this.salt = salt;
+ }
+
+}
@@ -1,8 +1,19 @@
[main]
+# realm to be used
+saltedJdbcRealm=org.meri.simpleshirosecuredapplication.realm.JNDIAndSaltAwareJdbcRealm
+saltedJdbcRealm.jndiDataSourceName=jdbc/SimpleShiroSecuredApplicationDB
+# 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 sec_users where name = ?
+# If not filled, subclasses of JdbcRealm assume "select role_name from user_roles where username = ?"
+saltedJdbcRealm.userRolesQuery = select role_name from sec_users_roles where user_name = ?
+# If not filled, subclasses of JdbcRealm assume "select permission from roles_permissions where role_name = ?"
+saltedJdbcRealm.permissionsQuery = select permission from sec_roles_permissions where role_name = ?
+
# password hashing specification
sha256Matcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
sha256Matcher.hashAlgorithmName=SHA-256
-iniRealm.credentialsMatcher = $sha256Matcher
+saltedJdbcRealm.credentialsMatcher = $sha256Matcher
# authc filter configuration
# specify login page
@@ -19,24 +30,6 @@ authc.successUrl = /simpleshirosecuredapplication/account/personalaccountpage.j
# roles filter: redirect to error page if user does not have access rights
roles.unauthorizedUrl = /simpleshirosecuredapplication/account/accessdenied.jsp
-[users]
-administrator=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,Administrator
-friendlyrepairman=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,repairman
-unfriendlyrepairman=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,repairman
-mathematician=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,scientist
-physicien=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,scientist
-productsales=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,sales
-servicessales=56b1db8133d9eb398aabd376f07bf8ab5fc584ea0b8bd6a1770200cb613ca005,sales
-
-[roles]
-# members of departments should be able to perform all departmental functions
-sales=functions:sale:*
-scientist=functions:science:*
-repairman=functions:repair:*
-
-# administrators are able to do all management functions and repair functions
-Administrator=functions:manage:*,functions:repair:*
-
[urls]
# force ssl for login page
/simpleshirosecuredapplication/account/login.jsp=ssl[8443], authc
@@ -48,4 +41,4 @@ Administrator=functions:manage:*,functions:repair:*
/simpleshirosecuredapplication/adminarea/**=authc, roles[Administrator]
# enable authc filter for all application pages
-/simpleshirosecuredapplication/**=authc
+/simpleshirosecuredapplication/**=authc
Oops, something went wrong.

0 comments on commit 85434cd

Please sign in to comment.