org.opennms.upgrade.implementations.MagicUsersMigratorOffline.java Source code

Java tutorial

Introduction

Here is the source code for org.opennms.upgrade.implementations.MagicUsersMigratorOffline.java

Source

/*******************************************************************************
 * This file is part of OpenNMS(R).
 *
 * Copyright (C) 2014 The OpenNMS Group, Inc.
 * OpenNMS(R) is Copyright (C) 1999-2014 The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc.
 *
 * OpenNMS(R) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published
 * by the Free Software Foundation, either version 3 of the License,
 * or (at your option) any later version.
 *
 * OpenNMS(R) 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with OpenNMS(R).  If not, see:
 *      http://www.gnu.org/licenses/
 *
 * For more information contact:
 *     OpenNMS(R) Licensing <license@opennms.org>
 *     http://www.opennms.org/
 *     http://www.opennms.com/
 *******************************************************************************/

package org.opennms.upgrade.implementations;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.opennms.core.utils.BundleLists;
import org.opennms.core.utils.ConfigFileConstants;
import org.opennms.netmgt.config.UserFactory;
import org.opennms.netmgt.config.UserManager;
import org.opennms.netmgt.model.OnmsUser;
import org.opennms.upgrade.api.AbstractOnmsUpgrade;
import org.opennms.upgrade.api.OnmsUpgradeException;
import org.opennms.web.api.Authentication;

/**
 * Migrate the content from magic-users.properties into the users.xml file
 * 
 * <p>Issues fixed:</p>
 * <ul>
 * <li>HZN-871</li>
 * </ul>
 * 
 * @author <a href="mailto:agalue@opennms.org">Alejandro Galue</a> 
 */
public class MagicUsersMigratorOffline extends AbstractOnmsUpgrade {

    /** The magic users file. */
    private File magicUsersFile;

    /** The users file. */
    private File usersFile;

    /**
     * Instantiates a new magic users migrator offline.
     *
     * @throws OnmsUpgradeException the OpenNMS upgrade exception
     */
    public MagicUsersMigratorOffline() throws OnmsUpgradeException {
        super();
        try {
            magicUsersFile = ConfigFileConstants.getConfigFileByName("magic-users.properties");
            usersFile = ConfigFileConstants.getFile(ConfigFileConstants.USERS_CONF_FILE_NAME);
        } catch (Exception e) {
        }
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#getOrder()
     */
    @Override
    public int getOrder() {
        return 12;
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#getDescription()
     */
    @Override
    public String getDescription() {
        return "Moves security roles from magic-users.properties into the users.xml file: HZN-871";
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#requiresOnmsRunning()
     */
    @Override
    public boolean requiresOnmsRunning() {
        return false;
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#preExecute()
     */
    @Override
    public void preExecute() throws OnmsUpgradeException {
        if (!canRun())
            return;

        try {
            File[] files = { magicUsersFile, usersFile };
            for (File file : files) {
                log("Backing up %s\n", file);
                zipFile(file);
            }
        } catch (Exception e) {
            throw new OnmsUpgradeException("Can't backup files because " + e.getMessage());
        }
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#postExecute()
     */
    @Override
    public void postExecute() throws OnmsUpgradeException {
        if (!canRun())
            return;

        // Delete the original configuration file so that it doesn't get re-migrated later
        if (magicUsersFile.exists()) {
            log("Removing original config file %s\n", magicUsersFile);
            FileUtils.deleteQuietly(magicUsersFile);
        }
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#rollback()
     */
    @Override
    public void rollback() throws OnmsUpgradeException {
        if (!canRun())
            return;

        File[] files = { magicUsersFile, usersFile };
        for (File file : files) {
            log("Restoring backup %s\n", file);
            File zip = new File(file.getAbsolutePath() + ZIP_EXT);
            FileUtils.deleteQuietly(file);
            unzipFile(zip, zip.getParentFile());
        }
    }

    /* (non-Javadoc)
     * @see org.opennms.upgrade.api.OnmsUpgrade#execute()
     */
    @Override
    public void execute() throws OnmsUpgradeException {
        if (!canRun()) {
            log("Error: ignoring the execution of the task because the file magic-users.properties was not found. Maybe the task was already successfully executed before.\n");
            return;
        }

        // Parse read-only attributes
        final List<String> readOnlyUsers = new ArrayList<String>();
        try {
            boolean readOnly = false;
            for (String line : Files.readAllLines(usersFile.toPath())) {
                if (line.contains("read-only")) {
                    Matcher m = Pattern.compile("read-only=\"(.+)\"").matcher(line);
                    if (m.find()) {
                        readOnly = Boolean.parseBoolean(m.group(1));
                    }
                }
                if (line.contains("user-id")) {
                    if (readOnly) {
                        Matcher m = Pattern.compile("user-id[>](.+)[<][/]user-id").matcher(line);
                        if (m.find()) {
                            log("Warning: User %s has read-only flag\n", m.group(1));
                            readOnlyUsers.add(m.group(1));
                        }
                    }
                    readOnly = false;
                }
            }
            if (!readOnlyUsers.isEmpty()) {
                log("Removing the read-only flags from users.xml\n");
                String content = new String(Files.readAllBytes(usersFile.toPath()), StandardCharsets.UTF_8);
                content = content.replaceAll(" read-only=\".+\"", "");
                Files.write(usersFile.toPath(), content.getBytes(StandardCharsets.UTF_8));
            }
        } catch (Exception e) {
            throw new OnmsUpgradeException("Can't fix configuration because " + e.getMessage(), e);
        }

        log("Moving security roles into users.xml...\n");
        try {
            UserFactory.init();
            UserManager userManager = UserFactory.getInstance();

            // Retrieve all the currently configured users.
            final List<OnmsUser> users = new ArrayList<OnmsUser>();
            for (final String userName : userManager.getUserNames()) {
                log("Loading configured user: %s...\n", userName);
                users.add(userManager.getOnmsUser(userName));
            }

            // Parse magic-users.properties
            Properties properties = new Properties();
            properties.load(new FileInputStream(magicUsersFile));

            // Look up for custom users and their passwords
            String[] configuredUsers = BundleLists.parseBundleList(properties.getProperty("users"));
            for (String user : configuredUsers) {
                String username = properties.getProperty("user." + user + ".username");
                String password = properties.getProperty("user." + user + ".password");
                OnmsUser newUser = new OnmsUser();
                newUser.setUsername(username);
                newUser.setFullName(user);
                newUser.setComments("This is a system user, do not delete");
                newUser.setPassword(userManager.encryptedPassword(password, true));
                newUser.setPasswordSalted(true);
                users.add(0, newUser);
            }

            // Configure security roles
            String[] configuredRoles = BundleLists.parseBundleList(properties.getProperty("roles"));
            for (final String role : configuredRoles) {
                String userList = properties.getProperty("role." + role + ".users");
                if (userList == null) {
                    log("Warning: Role configuration for '%s' does not have 'users' parameter.  Expecting a 'role.%s.users' property. The role will not be usable.\n",
                            role, role);
                    continue;
                }
                String[] authUsers = BundleLists.parseBundleList(userList);

                boolean notInDefaultGroup = "true"
                        .equals(properties.getProperty("role." + role + ".notInDefaultGroup"));
                String securityRole = "ROLE_" + role.toUpperCase();

                List<String> customRoles = new ArrayList<String>();
                for (final String username : authUsers) {
                    OnmsUser onmsUser = getUser(users, username);
                    if (onmsUser == null) {
                        log("Warning: User %s doesn't exist on users.xml, Ignoring.\n", username);
                    } else {
                        addRole(onmsUser, securityRole);
                        if (!notInDefaultGroup && !securityRole.equals(Authentication.ROLE_ADMIN)) {
                            addRole(onmsUser, Authentication.ROLE_USER);
                        }
                        if (!Authentication.isValidRole(securityRole)) {
                            log("Warning: %s is a custom role.\n", securityRole);
                            customRoles.add(role);
                        }
                    }
                }

                if (!customRoles.isEmpty()) {
                    String roleList = StringUtils.join(customRoles, ',');
                    log("Creating %s with roles: %s\n", Authentication.ROLE_CONFIGURATION_FILE, roleList);
                    Properties p = new Properties();
                    p.put("roles", roleList);
                    File configFile = new File(ConfigFileConstants.getHome(),
                            "etc" + File.separator + Authentication.ROLE_CONFIGURATION_FILE);
                    p.store(new FileWriter(configFile), "Custom Roles");
                }
            }

            // Update users.xml
            for (final OnmsUser user : users) {
                if (readOnlyUsers.contains(user.getUsername())) {
                    addRole(user, Authentication.ROLE_READONLY);
                    if (!user.getRoles().contains(Authentication.ROLE_USER)) {
                        addRole(user, Authentication.ROLE_USER);
                    }
                }
                userManager.save(user);
            }
        } catch (Throwable e) {
            throw new OnmsUpgradeException("Can't fix configuration because " + e.getMessage(), e);
        }
    }

    /**
     * Gets the user.
     *
     * @param users the users
     * @param userName the user name
     * @return the user
     */
    private OnmsUser getUser(List<OnmsUser> users, String userName) {
        for (final OnmsUser user : users) {
            if (user.getUsername().equals(userName)) {
                return user;
            }
        }
        return null;
    }

    /**
     * Adds the role.
     *
     * @param onmsUser the OpenNMS user
     * @param securityRole the security role
     */
    private void addRole(OnmsUser onmsUser, String securityRole) {
        log("Adding role %s to user %s\n", securityRole, onmsUser.getUsername());
        onmsUser.addRole(securityRole);
    }

    /**
     * Can run.
     *
     * @return true, if successful
     */
    private boolean canRun() {
        return magicUsersFile != null && magicUsersFile.exists();
    }
}