Java tutorial
/* * Copyright 2010-2013, the original author or authors * * 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 localdomain.localhost; import org.jasig.cas.adaptors.jdbc.AbstractJdbcUsernamePasswordAuthenticationHandler; import org.jasig.cas.adaptors.jdbc.SearchModeSearchDatabaseAuthenticationHandler; import org.jasig.cas.authentication.handler.AuthenticationException; import org.jasig.cas.authentication.handler.PasswordEncoder; import org.jasig.cas.authentication.handler.support.AbstractUsernamePasswordAuthenticationHandler; import org.jasig.cas.authentication.principal.UsernamePasswordCredentials; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeansException; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.jmx.export.annotation.ManagedOperation; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.util.ReflectionUtils; import javax.sql.DataSource; import javax.validation.constraints.NotNull; import java.lang.reflect.Field; import java.sql.*; import java.util.NoSuchElementException; /** * <p> * Initialize the application creating a table for {@link SearchModeSearchDatabaseAuthenticationHandler} if needed * and populating it with a user "demo/mode" if no user exist in the database. * </p> * <p> * Don't use SLF4J {@link Logger} but directly {@code System.out} because by default, CAS configures log4j at * {@code ERROR} level. * </p> * * @author <a href="mailto:cleclerc@cloudbees.com">Cyrille Le Clerc</a> */ @ManagedResource public class CasInitializer implements InitializingBean, ApplicationContextAware { protected final Logger logger = LoggerFactory.getLogger(getClass()); final Field tableUsersField = ReflectionUtils.findField(SearchModeSearchDatabaseAuthenticationHandler.class, "tableUsers"); private final Field passwordEncoderField = ReflectionUtils .findField(AbstractUsernamePasswordAuthenticationHandler.class, "passwordEncoder"); private final Field dataSourceField = ReflectionUtils .findField(AbstractJdbcUsernamePasswordAuthenticationHandler.class, "dataSource"); private final Field fieldUserField = ReflectionUtils .findField(SearchModeSearchDatabaseAuthenticationHandler.class, "fieldUser"); private final Field fieldPasswordField = ReflectionUtils .findField(SearchModeSearchDatabaseAuthenticationHandler.class, "fieldPassword"); @NotNull private ApplicationContext applicationContext; { passwordEncoderField.setAccessible(true); dataSourceField.setAccessible(true); fieldUserField.setAccessible(true); fieldPasswordField.setAccessible(true); tableUsersField.setAccessible(true); } private DataSource dataSource; private String fieldUser; private String fieldPassword; private String tableUsers; private PasswordEncoder passwordEncoder; private SearchModeSearchDatabaseAuthenticationHandler authenticationHandler; public static void rollbackQuietly(Connection cnn) { if (cnn == null) return; try { cnn.rollback(); } catch (Exception e) { // ignore } } public static void closeQuietly(Statement stmt) { if (stmt == null) return; try { stmt.close(); } catch (Exception e) { // ignore } } public static void closeQuietly(Connection cnn) { if (cnn == null) return; try { cnn.close(); } catch (Exception e) { // ignore } } public static void closeQuietly(ResultSet rst) { if (rst == null) return; try { rst.close(); } catch (Exception e) { // ignore } } public static void closeQuietly(Statement stmt, ResultSet rst) { closeQuietly(rst); closeQuietly(stmt); } public static void closeQuietly(Connection cnn, Statement stmt, ResultSet rst) { closeQuietly(rst); closeQuietly(stmt); closeQuietly(cnn); } public static void closeQuietly(Connection cnn, Statement stmt) { closeQuietly(stmt); closeQuietly(cnn); } @Override public void afterPropertiesSet() throws Exception { System.err.println( "##############################################################################################"); System.err.println( "##############################################################################################"); System.err.println( "# #"); System.err.println( "# CLOUDBEES JASIG CAS SSO SERVER CLICKSTART #"); System.err.println( "# #"); System.err.println( "# See documentation at https://github.com/CloudBees-community/jasig-cas-clickstart/wiki #"); System.err.println( "# #"); System.err.println( "##############################################################################################"); System.err.println( "##############################################################################################"); try { authenticationHandler = applicationContext.getBean(SearchModeSearchDatabaseAuthenticationHandler.class); } catch (NoSuchBeanDefinitionException e) { String msg = "No Spring bean of type " + SearchModeSearchDatabaseAuthenticationHandler.class + " found, initializer can not run"; logger.warn(msg); throw new IllegalStateException(msg, e); } dataSource = (DataSource) ReflectionUtils.getField(dataSourceField, authenticationHandler); fieldUser = (String) ReflectionUtils.getField(fieldUserField, authenticationHandler); fieldPassword = (String) ReflectionUtils.getField(fieldPasswordField, authenticationHandler); tableUsers = (String) ReflectionUtils.getField(tableUsersField, authenticationHandler); passwordEncoder = (PasswordEncoder) ReflectionUtils.getField(passwordEncoderField, authenticationHandler); final Connection cnn = dataSource.getConnection(); Statement stmt = null; ResultSet rst = null; try { logger.info("Create table " + tableUsers + " if not exist"); stmt = cnn.createStatement(); String createTableDdl = "CREATE TABLE IF NOT EXISTS `" + tableUsers + "` (" + " `" + fieldUser + "` varchar(255) DEFAULT NULL,\n" + " `" + fieldPassword + "` varchar(255) DEFAULT NULL,\n" + " PRIMARY KEY (`" + fieldUser + "`)\n" + ")"; stmt.execute(createTableDdl); closeQuietly(stmt); logger.info("Validate table columns"); stmt = cnn.createStatement(); String sqlCheckDatabaseTable = "select `" + fieldUser + "`,`" + fieldPassword + "`" + " from `" + tableUsers + "` where 0=1"; try { stmt.execute(sqlCheckDatabaseTable); } catch (SQLException e) { throw new IllegalStateException("Invalid table structure:" + sqlCheckDatabaseTable, e); } closeQuietly(stmt); stmt = cnn.createStatement(); String sqlCountUsers = "select count(*) from `" + tableUsers + "`"; rst = stmt.executeQuery(sqlCountUsers); rst.next(); int usersCount = rst.getInt(1); closeQuietly(stmt, rst); if (usersCount == 0) { insertUser("demo", "mode", cnn); } if (!cnn.getAutoCommit()) { cnn.commit(); } logger.info("CAS CLICKSTART INITIALIZED"); } finally { closeQuietly(cnn, stmt, rst); } } protected void insertUser(@NotNull String username, @NotNull String clearTextPassword, Connection cnn) throws SQLException { logger.info("Create user '" + username + "'"); PreparedStatement stmt = null; try { stmt = cnn.prepareStatement("insert into `" + tableUsers + "` " + "(`" + fieldUser + "`, `" + fieldPassword + "`) values (?, ?)"); stmt.setString(1, username); stmt.setString(2, passwordEncoder.encode(clearTextPassword)); int rowCount = stmt.executeUpdate(); if (rowCount != 1) { logger.warn("More/less (" + rowCount + ") than 1 row inserted for username '" + username + "'"); } } finally { closeQuietly(stmt); } } @ManagedOperation public void createUser(@NotNull String username, @NotNull String clearTextPassword) { Connection cnn = null; try { cnn = dataSource.getConnection(); cnn.setAutoCommit(false); insertUser(username, clearTextPassword, cnn); cnn.commit(); } catch (RuntimeException e) { rollbackQuietly(cnn); String msg = "Exception creating '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } catch (SQLException e) { rollbackQuietly(cnn); String msg = "Exception creating '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } finally { closeQuietly(cnn); } } @ManagedOperation public void deleteUser(@NotNull String username) { Connection cnn = null; PreparedStatement stmt = null; try { cnn = dataSource.getConnection(); cnn.setAutoCommit(false); stmt = cnn.prepareStatement("delete from `" + tableUsers + "` where `" + fieldUser + "` like ?"); stmt.setString(1, username); int rowCount = stmt.executeUpdate(); if (rowCount == 0) { throw new NoSuchElementException("No user '" + username + "' found"); } else if (rowCount == 1) { logger.info("User '" + username + "' was deleted"); } else { new IllegalArgumentException( "More (" + rowCount + ") than 1 row deleted for username '" + username + "', rollback"); } logger.info("User '" + username + "' deleted"); cnn.commit(); } catch (RuntimeException e) { rollbackQuietly(cnn); String msg = "Exception deleting user '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } catch (SQLException e) { rollbackQuietly(cnn); String msg = "Exception deleting user '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } finally { closeQuietly(cnn, stmt); } } @ManagedOperation public void changeUserPassword(@NotNull String username, @NotNull String clearTextPassword) { Connection cnn = null; PreparedStatement stmt = null; try { cnn = dataSource.getConnection(); cnn.setAutoCommit(false); stmt = cnn.prepareStatement( "update `" + tableUsers + "` set `" + fieldPassword + "` = ? where `" + fieldUser + "` like ?"); stmt.setString(1, passwordEncoder.encode(clearTextPassword)); stmt.setString(2, username); int rowCount = stmt.executeUpdate(); if (rowCount == 0) { throw new NoSuchElementException("No user '" + username + "' found"); } else if (rowCount == 1) { logger.info("Password of user '" + username + "' was updated"); } else { new IllegalArgumentException( "More (" + rowCount + ") than 1 row deleted for username '" + username + "', rollback"); } logger.info("User '" + username + "' deleted"); cnn.commit(); } catch (RuntimeException e) { rollbackQuietly(cnn); String msg = "Exception changing password for user '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } catch (SQLException e) { rollbackQuietly(cnn); String msg = "Exception changing password for user '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } finally { closeQuietly(cnn, stmt); } } @ManagedOperation public void checkUserPassword(@NotNull String username, @NotNull String clearTextPassword) { UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(); credentials.setUsername(username); credentials.setPassword(clearTextPassword); boolean authenticated; try { authenticated = authenticationHandler.authenticate(credentials); } catch (AuthenticationException e) { String msg = "Exception authenticating login/password for username '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } catch (RuntimeException e) { String msg = "Invalid login/password for username '" + username + "': " + e; logger.warn(msg, e); throw new RuntimeException(msg); } if (!authenticated) { String msg = "Invalid login/password for username '" + username + "'"; logger.warn(msg); throw new RuntimeException(msg); } } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }