/** * Copyright (C) 2013 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.services.organization.idm; import java.io.InputStream; import java.net.URL; import java.security.PrivilegedAction; import java.util.List; import java.util.Properties; import org.exoplatform.commons.utils.SecurityHelper; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.picketlink.idm.api.Attribute; import org.picketlink.idm.api.AttributesManager; import org.picketlink.idm.api.IdentitySession; import org.picketlink.idm.api.IdentitySessionFactory; import org.picketlink.idm.api.SortOrder; import org.picketlink.idm.api.Transaction; import org.picketlink.idm.api.User; import org.picketlink.idm.api.cfg.IdentityConfiguration; import org.picketlink.idm.api.query.UserQuery; import org.picketlink.idm.api.query.UserQueryBuilder; import org.picketlink.idm.common.exception.IdentityConfigurationException; import org.picketlink.idm.impl.api.SimpleAttribute; import org.picketlink.idm.impl.configuration.IdentityConfigurationImpl; import org.picketlink.idm.impl.configuration.jaxb2.JAXB2IdentityConfiguration; import org.picketlink.idm.spi.configuration.metadata.IdentityConfigurationMetaData; public class DisabledUserMigrationScript { private String realmName; private IdentitySessionFactory identitySessionFactory; private SessionFactory sessionFactory_; private int batch; private static final Log log = ExoLogger.getExoLogger(DisabledUserMigrationScript.class); public DisabledUserMigrationScript(Properties config) throws Exception { // setup Hibernate setupHibernate(config); // setup PicketLink setupPicketlink(config); String b = config.getProperty("batch"); this.batch = Integer.parseInt(b == null ? "100" : b); } public void enableAll(int first) throws Exception { final long startTime = System.currentTimeMillis(); startTransaction(); final int size = getIdentitySession().getPersistenceManager().getUserCount(); log.info("Starting enable for {} users", size - first); int length = batch > size ? size : batch; while (length > 0) { try { log.info("enable for user from {} to {}", first, (first + length)); startTransaction(); UserQueryBuilder qb = getIdentitySession().createUserQueryBuilder(); List<User> users = load(qb, first, length); for (User user : users) { setEnabled(user.getId(), true); } getIdentitySession().save(); endTransaction(); } catch (Exception e) { log.info("fail to migrate for users from index: {}", first); recoverFromIDMError(e); break; } first = first + batch; length = batch + first > size ? size - first : batch; } log.info("Finish enable all users in : {}ms", (System.currentTimeMillis() - startTime)); } private List<org.picketlink.idm.api.User> load(UserQueryBuilder qb, int index, int length) throws Exception { qb.sort(SortOrder.ASCENDING).page(index, length); UserQuery query = qb.createQuery(); return getIdentitySession().list(query); } public void setEnabled(String userName, boolean enabled) throws Exception { Attribute[] attrs = new Attribute[] { new SimpleAttribute(UserDAOImpl.USER_ENABLED, String.valueOf(enabled)) }; IdentitySession session = getIdentitySession(); AttributesManager am = session.getAttributesManager(); am.updateAttributes(userName, attrs); } public void startTransaction() throws Exception { if (!getIdentitySession().getTransaction().isActive()) { getIdentitySession().beginTransaction(); } } public void endTransaction() throws Exception { if (getIdentitySession().getTransaction().isActive()) { getIdentitySession().getTransaction().commit(); } } public void recoverFromIDMError(Exception e) { log.error(e); try { // We need to restart Hibernate transaction if it's available. First rollback old one and then start new one Transaction idmTransaction = getIdentitySession().getTransaction(); if (idmTransaction.isActive()) { idmTransaction.rollback(); log.info("IDM error recovery finished. Old transaction has been rolled-back"); } } catch (Exception e1) { log.warn("Error during recovery of old error", e1); } } private void setupHibernate(Properties config) throws Exception { final Configuration conf_ = new Configuration(); conf_.setProperty("hibernate.connection.driver_class", config.getProperty("hibernate.connection.driver_class")); conf_.setProperty("hibernate.connection.url", config.getProperty("hibernate.connection.url")); conf_.setProperty("hibernate.connection.username", config.getProperty("hibernate.connection.username")); conf_.setProperty("hibernate.connection.password", config.getProperty("hibernate.connection.password")); conf_.setProperty("hibernate.dialect", config.getProperty("hibernate.dialect")); String config_path = config.getProperty("hibernate.config_path"); URL url = Thread.currentThread().getContextClassLoader().getResource(config_path); if (url == null) { log.error("hibernate config file not found: {}", config_path); } else { log.info("adding hibernate config file {}", config_path); conf_.addURL(url); } sessionFactory_ = SecurityHelper.doPrivilegedAction(new PrivilegedAction<SessionFactory>() { public SessionFactory run() { SessionFactory factory = conf_.configure().buildSessionFactory(); return factory; } }); } private void setupPicketlink(Properties config) throws Exception { String pkConfig = config.getProperty("picketlink.config_file_path"); URL pk_config_url = Thread.currentThread().getContextClassLoader().getResource(pkConfig); if (pk_config_url == null) { throw new IllegalStateException("Cannot fine resource: " + pkConfig); } this.realmName = config.getProperty("picketlink.realmName", "idm_realm"); IdentityConfigurationMetaData configMD = JAXB2IdentityConfiguration.createConfigurationMetaData(pk_config_url.openStream()); IdentityConfiguration identityConfiguration = new IdentityConfigurationImpl().configure(configMD); identityConfiguration.getIdentityConfigurationRegistry().register(sessionFactory_, "hibernateSessionFactory"); if (identitySessionFactory == null) { try { identitySessionFactory = identityConfiguration.buildIdentitySessionFactory(); } catch (IdentityConfigurationException e) { throw new RuntimeException(e); } } } public IdentitySession getIdentitySession() throws Exception { return identitySessionFactory.getCurrentIdentitySession(realmName); } public static void main(String[] args) throws Exception { Properties config = new Properties(); String config_path = args.length > 0 ? args[0] : null; if (config_path != null) { URL config_url = Thread.currentThread().getContextClassLoader().getResource(config_path); if (config_url == null) { log.error("config file is not found: {}", config_path); } else { log.info("using config file {}", config_url); config.load(config_url.openStream()); } } else { log.info("using default config file"); InputStream defInput = Thread.currentThread().getContextClassLoader() .getResourceAsStream("configuration.properties"); config.load(defInput); } for (Object key : System.getProperties().keySet()) { config.setProperty((String) key, System.getProperty((String) key)); } int first = Integer.parseInt(config.getProperty("enable_user_from", "0")); DisabledUserMigrationScript service = new DisabledUserMigrationScript(config); service.enableAll(first); service.sessionFactory_.close(); } }