Java tutorial
/** * Copyright 2013 Jee Vang Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ package demo.learn.shiro.realm; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; 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.codec.Base64; import org.apache.shiro.config.ConfigurationException; import org.apache.shiro.realm.jdbc.JdbcRealm; import org.apache.shiro.util.JdbcUtils; import org.apache.shiro.util.SimpleByteSource; import demo.learn.shiro.util.SqlUtil; /** * http://shiro.apache.org/realm.html * @author root * */ public class CustomRealm extends JdbcRealm { /** * SQL to get password. */ protected static final String AUTHENTICATION_QUERY = "select password from user where username = ?"; /** * SQL to get password + password salt. */ protected static final String SALTED_AUTHENTICATION_QUERY = "select password, passsalt from user where username = ?"; /** * SQL to get role name. */ protected static final String USER_ROLES_QUERY = "select rolename from role where username = ?"; /** * Constructor. */ public CustomRealm() { super(); setDataSource(SqlUtil.getDefaultDataSource()); setSaltStyle(SaltStyle.COLUMN); setAuthenticationQuery(SALTED_AUTHENTICATION_QUERY); setUserRolesQuery(USER_ROLES_QUERY); setPermissionsLookupEnabled(false); setName("learn.shiro"); } @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; SimpleAuthenticationInfo info = null; try { conn = dataSource.getConnection(); String password = null; String salt = null; switch (saltStyle) { case NO_SALT: password = getUserPassword(conn, username)[0]; break; case CRYPT: // TODO: separate password and hash from getPasswordForUser[0] throw new ConfigurationException("Not implemented yet"); //break; case COLUMN: String[] queryResults = getUserPassword(conn, username); password = queryResults[0]; salt = queryResults[1]; break; case EXTERNAL: password = getUserPassword(conn, username)[0]; salt = getSaltForUser(username); } if (password == null) { throw new UnknownAccountException("No account found for user [" + username + "]"); } info = new SimpleAuthenticationInfo(username, password.toCharArray(), getName()); if (salt != null) { SimpleByteSource simpleByteSource = new SimpleByteSource(Base64.decode(salt)); info.setCredentialsSalt(simpleByteSource); } } catch (SQLException e) { final String message = "There was a SQL error while authenticating user [" + username + "]"; throw new AuthenticationException(message, e); } finally { JdbcUtils.closeConnection(conn); } return info; } /** * Gets the user's password + salt. * @param conn {@link Connection}. * @param username Username. * @return String array of length 2. 0-th index string is * password and 1-st index string is password salt. * @throws SQLException */ @SuppressWarnings("resource") protected String[] getUserPassword(Connection conn, String username) throws SQLException { String[] result; boolean returningSeparatedSalt = false; switch (saltStyle) { case NO_SALT: case CRYPT: case EXTERNAL: result = new String[1]; break; default: result = new String[2]; returningSeparatedSalt = true; } PreparedStatement ps = null; ResultSet rs = 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."); } result[0] = rs.getString(1); if (returningSeparatedSalt) { result[1] = rs.getString(2); } foundResult = true; } } finally { JdbcUtils.closeResultSet(rs); JdbcUtils.closeStatement(ps); } return result; } }