All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.payneteasy.superfly.password.PasswordEncryptor Maven / Gradle / Ivy

package com.payneteasy.superfly.password;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

import com.payneteasy.superfly.hotp.HOTPProviderContextImpl;
import com.payneteasy.superfly.hotp.HOTPProviderUtils;
import com.payneteasy.superfly.hotp.NullHOTPProvider;
import com.payneteasy.superfly.spi.HOTPProvider;
import com.payneteasy.superfly.spisupport.HOTPDao;
import com.payneteasy.superfly.spisupport.HOTPData;
import com.payneteasy.superfly.spisupport.HOTPProviderContext;
import com.payneteasy.superfly.spisupport.HOTPService;
import com.payneteasy.superfly.spisupport.ObjectResolver;
import com.payneteasy.superfly.spisupport.SaltGenerator;

/**
 * Encrypts passwords in the database. It assumes they are not encoded yet.
 * Run without parameters to get help.
 * WARNING! If some of your passwords are already encrypted, this may
 * re-encrypt them (i.e. make then non-usable). Encryptor tries to avoid this
 * by skipping users for which password length matches the new encrypted
 * password length, but it's just a heuristic.
 *
 * @author Roman Puchkovskiy
 */
public class PasswordEncryptor {
    public static void main(String[] args) throws Exception {
        if (args.length != 5) {
            printUsage();
            System.exit(1);
        }

        String algorithm = args[0];
        String url = args[1];
        String username = args[2];
        String password = args[3];
        int hotpCodeDigits = Integer.parseInt(args[4]);

        System.out.println("Please enter hotp master key");
        Scanner scanner = new Scanner(System.in);
        String hotpMasterKey = scanner.nextLine();

        PasswordEncoder passwordEncoder = createPasswordEncoder(algorithm);
        SaltGenerator saltGenerator = createSaltGenerator();

        HOTPProvider hotpProvider = instantiateHOTPProvider(scanner);

        String test = passwordEncoder.encode("password", saltGenerator.generate());

        final Connection conn = createAndInitConnection(url, username, password);

        HOTPProviderContext hotpProviderContext = createHOTPProviderContext(
                hotpMasterKey, hotpCodeDigits, conn);

        hotpProvider.init(hotpProviderContext);
        
        Statement st = conn.createStatement();
        PreparedStatement updatePasswordSt = conn.prepareStatement("update users set user_password = ?, salt = ? where user_id = ?");
        PreparedStatement insertHistorySt = conn.prepareStatement("insert into user_history (user_user_id, user_password, salt, number_history, start_date, end_date) values (?, ?, ?, (select coalesce(max(uh2.number_history), 0) + 1 from user_history uh2 where uh2.user_user_id = ?), now(), '2999-12-31')");
        
        System.out.println("Starting password encryption");
        Set processedNames = new HashSet();
        ResultSet rs = st.executeQuery("select user_id, user_name, user_password from users where (user_password is null or user_password = '' or length(user_password) <> " + test.length() + ")");
        while (rs.next()) {
            long id = rs.getLong("user_id");
            username = rs.getString("user_name");
            password = rs.getString("user_password");
            String salt = saltGenerator.generate();
            String newPassword = passwordEncoder.encode(password != null ? password : "", salt);
//            System.out.println(String.format("User %s (%d): old password '%s', salt '%s', new password '%s'",
//                    username, id, password, salt, newPassword));
            updatePasswordSt.setString(1, newPassword);
            updatePasswordSt.setString(2, salt);
            updatePasswordSt.setLong(3, id);
            updatePasswordSt.addBatch();

            insertHistorySt.setLong(1, id);
            insertHistorySt.setString(2, newPassword);
            insertHistorySt.setString(3, salt);
            insertHistorySt.setLong(4, id);
            insertHistorySt.addBatch();

            processedNames.add(username);
        }
        rs.close();
        st.close();
        
        updatePasswordSt.executeBatch();
        insertHistorySt.executeBatch();

        conn.commit();
        
        updatePasswordSt.close();
        insertHistorySt.close();

        System.out.println("Finished password encryption");
        
        System.out.println("Computing HOTP values for admins");
        
        st = conn.createStatement();
        rs = st.executeQuery("(select user_id, user_name, hotp_counter" +
                " from users u" +
                " join user_roles ur on u.user_id = ur.user_user_id" +
                " join roles r on r.role_id = ur.role_role_id" +
                " join role_groups rg on r.role_id = rg.role_role_id" +
                " join groups g on rg.grop_grop_id = g.grop_id" +
                " join group_actions ga on g.grop_id = ga.actn_actn_id" +
                " join actions a on a.actn_id = ga.actn_actn_id" +
                " where a.action_name = 'admin' and a.ssys_ssys_id = (select ssys_id from subsystems where subsystem_name = 'superfly'))" +
                " union distinct" +
                " (select user_id, user_name, hotp_counter" +
                " from users u" +
                " join user_roles ur on u.user_id = ur.user_user_id" +
                " join roles r on r.role_id = ur.role_role_id" +
                " join role_actions ra on r.role_id = ra.actn_actn_id" +
                " join actions a on a.actn_id = ra.actn_actn_id" +
                " where a.action_name = 'admin' and a.ssys_ssys_id = (select ssys_id from subsystems where subsystem_name = 'superfly'))");
        while (rs.next()) {
            username = rs.getString("user_name");
            if (processedNames.contains(username)) {
                long counter = rs.getLong("hotp_counter");
                System.out.println(String.format("HOTP values for %s: %s, %s, %s", username,
                        hotpProvider.computeValue(username, counter),
                        hotpProvider.computeValue(username, counter + 1),
                        hotpProvider.computeValue(username, counter + 2)));
            }
        }
        
        System.out.println("Finished computing HOTP values for admins");
        
        st.close();
        
        conn.close();
    }

    private static HOTPProviderContext createHOTPProviderContext(
            String hotpMasterKey, int hotpCodeDigits, final Connection conn) {
        final HOTPDao hotpDao = createHOTPDao(conn);
        SaltGenerator saltGenerator = createSaltGenerator();
        HOTPService hotpService = createHOTPService();
        ObjectResolver objectResolver = createObjectResolver(hotpDao, saltGenerator, hotpService);
        HOTPProviderContext hotpProviderContext = new HOTPProviderContextImpl(objectResolver, hotpMasterKey, hotpCodeDigits, 10, 100);
        return hotpProviderContext;
    }

    private static HOTPService createHOTPService() {
        return new HOTPService() {
            public void sendTableIfSupported(String subsystemIdentifier, long userId) {
            }

            public void resetTableAndSendIfSupported(String subsystemIdentifier, long userId) {
            }
        };
    }

    private static ObjectResolver createObjectResolver(final HOTPDao hotpDao, final SaltGenerator saltGenerator, final HOTPService hotpService) {
        ObjectResolver objectResolver = new ObjectResolver() {
            @SuppressWarnings("unchecked")
            public  T resolve(Class clazz) {
                if (clazz == HOTPDao.class) {
                    return (T) hotpDao;
                }
                if (clazz == SaltGenerator.class) {
                    return (T) saltGenerator;
                }
                if (clazz == HOTPService.class) {
                    return (T) hotpService;
                }
                throw new IllegalStateException("Unexpected class requested: " + clazz);
            }
        };
        return objectResolver;
    }

    private static HOTPDao createHOTPDao(final Connection conn) {
        final HOTPDao hotpDao = new HOTPDao() {
            public void updateCounter(String username, long newValue) {
            }

            public HOTPData getHOTPData(String username) {
                PreparedStatement st = null;
                ResultSet rs = null;
                try {
                    st = conn.prepareStatement("select hotp_salt, hotp_counter from users where user_name = ?");
                    st.setString(1, username);
                    rs = st.executeQuery();
                    if (!rs.next()) {
                        return null;
                    }
                    HOTPData data = new HOTPData();
                    data.setUsername(username);
                    data.setSalt(rs.getString("hotp_salt"));
                    data.setCounter(rs.getLong("hotp_counter"));
                    return data;
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                } finally {
                    if (rs != null) {
                        try {
                            rs.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                    if (st != null) {
                        try {
                            st.close();
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }

            public void resetHOTP(String username, String hotpSalt) {
            }
        };
        return hotpDao;
    }

    private static HOTPProvider instantiateHOTPProvider(Scanner scanner) {
        HOTPProvider hotpProvider = HOTPProviderUtils.instantiateProvider(false);
        if (hotpProvider == null) {
            System.out.println("Did not find a HOTPProvider provider on the classpath. Are you SURE you want to use null implementation? Be aware that if your Superfly server actually uses a HOTP provider and you don't supply it here, generated HOTP values will be INCORRECT and you will NOT GET ACCESS to your Superfly server!!!");
            System.out.println("Also, be sure that the provider that you supply here is the same as the one that will be used on your Server!");
            System.out.println("So, do you still want to use null provider? (Yes/No)");
            String answer = scanner.nextLine();
            if (!"yes".equalsIgnoreCase(answer)) {
                System.out.println("Exiting");
                System.exit(0);
            }
            hotpProvider = new NullHOTPProvider();
        } else {
            System.out.println("Found the following implementation: " + hotpProvider.getClass().getName());
            System.out.println("Please note that you MUST check CAREFULLY whether this is right, or you may lose control of your server as HOTP codes will be incorrect!");
            System.out.println("Is above implementation correct?");
            String answer = scanner.nextLine();
            if (!"yes".equalsIgnoreCase(answer)) {
                System.out.println("Exiting");
                System.exit(0);
            }
        }
        return hotpProvider;
    }

    private static Connection createAndInitConnection(String url,
            String username, String password) throws InstantiationException,
            IllegalAccessException, ClassNotFoundException, SQLException {
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        Connection conn = DriverManager.getConnection(url, username, password);
        conn.setAutoCommit(false);
        return conn;
    }

    private static void printUsage() {
        System.out.println("Parameters:     ");
        System.out.println("  \t\t\thash algorithm (for instance, md-5, sha1, sha-256)");
        System.out.println("  \t\t\tURL of the database (for instance, jdbc:mysql://localhost/sso?characterEncoding=utf8");
        System.out.println("  \t\t\tusername to connect to database");
        System.out.println("  \t\t\tpassword of the database user");
        System.out.println("  \t\tNumber of digits in HOTP value (must match the value configured in Superfly web-app)");
        System.out.println("Example: sha-256 jdbc:mysql://localhost/sso?characterEncoding=utf8 sso 123sso123 6");
    }

    private static SHA256RandomGUIDSaltGenerator createSaltGenerator() {
        return new SHA256RandomGUIDSaltGenerator();
    }

    private static MessageDigestPasswordEncoder createPasswordEncoder(String algorithm) {
        MessageDigestPasswordEncoder encoder = new MessageDigestPasswordEncoder();
        encoder.setAlgorithm(algorithm);
        return encoder;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy