/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 org.apache.activemq.artemis.cli.commands.user; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.activemq.artemis.api.core.Pair; import org.apache.activemq.artemis.utils.StringUtil; import org.apache.commons.configuration2.PropertiesConfiguration; import org.apache.commons.configuration2.builder.FileBasedConfigurationBuilder; import org.apache.commons.configuration2.builder.fluent.Configurations; class FileBasedSecStoreConfig { private static final String LICENSE_HEADER = "## ---------------------------------------------------------------------------\n" + "## Licensed to the Apache Software Foundation (ASF) under one or more\n" + "## contributor license agreements. See the NOTICE file distributed with\n" + "## this work for additional information regarding copyright ownership.\n" + "## The ASF licenses this file to You under the Apache License, Version 2.0\n" + "## (the \"License\"); you may not use this file except in compliance with\n" + "## the License. You may obtain a copy of the License at\n" + "##\n" + "## http://www.apache.org/licenses/LICENSE-2.0\n" + "##\n" + "## Unless required by applicable law or agreed to in writing, software\n" + "## distributed under the License is distributed on an \"AS IS\" BASIS,\n" + "## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" + "## See the License for the specific language governing permissions and\n" + "## limitations under the License.\n" + "## ---------------------------------------------------------------------------\n"; private FileBasedConfigurationBuilder<PropertiesConfiguration> userBuilder; private FileBasedConfigurationBuilder<PropertiesConfiguration> roleBuilder; private PropertiesConfiguration userConfig; private PropertiesConfiguration roleConfig; FileBasedSecStoreConfig(File userFile, File roleFile) throws Exception { Configurations configs = new Configurations(); userBuilder = configs.propertiesBuilder(userFile); roleBuilder = configs.propertiesBuilder(roleFile); userConfig = userBuilder.getConfiguration(); roleConfig = roleBuilder.getConfiguration(); String roleHeader = roleConfig.getLayout().getHeaderComment(); String userHeader = userConfig.getLayout().getHeaderComment(); if (userHeader == null) { if (userConfig.isEmpty()) { //clean and reset header userConfig.clear(); userConfig.setHeader(LICENSE_HEADER); } } if (roleHeader == null) { if (roleConfig.isEmpty()) { //clean and reset header roleConfig.clear(); roleConfig.setHeader(LICENSE_HEADER); } } } void addNewUser(String username, String hash, String... roles) throws Exception { if (userConfig.getString(username) != null) { throw new IllegalArgumentException("User already exist: " + username); } userConfig.addProperty(username, hash); addRoles(username, roles); } void save() throws Exception { userBuilder.save(); roleBuilder.save(); } void removeUser(String username) throws Exception { if (userConfig.getProperty(username) == null) { throw new IllegalArgumentException("user " + username + " doesn't exist."); } userConfig.clearProperty(username); removeRoles(username); } List<String> listUser(String username) { List<String> result = new ArrayList<>(); result.add("--- \"user\"(roles) ---\n"); int totalUsers = 0; if (username != null) { String roles = findRoles(username); result.add("\"" + username + "\"(" + roles + ")"); totalUsers++; } else { Iterator<String> iter = userConfig.getKeys(); while (iter.hasNext()) { String keyUser = iter.next(); String roles = findRoles(keyUser); result.add("\"" + keyUser + "\"(" + roles + ")"); totalUsers++; } } result.add("\n Total: " + totalUsers); return result; } void updateUser(String username, String password, String[] roles) { String oldPassword = (String) userConfig.getProperty(username); if (oldPassword == null) { throw new IllegalArgumentException("user " + username + " doesn't exist."); } if (password != null) { userConfig.setProperty(username, password); } if (roles != null && roles.length > 0) { removeRoles(username); addRoles(username, roles); } } private String findRoles(String uname) { Iterator<String> iter = roleConfig.getKeys(); StringBuilder builder = new StringBuilder(); boolean first = true; while (iter.hasNext()) { String role = iter.next(); List<String> names = roleConfig.getList(String.class, role); for (String value : names) { //each value may be a comma separated list String[] items = value.split(","); for (String item : items) { if (item.equals(uname)) { if (!first) { builder.append(","); } builder.append(role); first = false; } } } } return builder.toString(); } private void addRoles(String username, String[] roles) { for (String role : roles) { List<String> users = roleConfig.getList(String.class, role); if (users == null) { users = new ArrayList<>(); } users.add(username); roleConfig.setProperty(role, StringUtil.joinStringList(users, ",")); } } private void removeRoles(String username) { Iterator<String> iterKeys = roleConfig.getKeys(); List<Pair<String, List<String>>> updateMap = new ArrayList<>(); while (iterKeys.hasNext()) { String theRole = iterKeys.next(); List<String> userList = roleConfig.getList(String.class, theRole); List<String> newList = new ArrayList<>(); boolean roleChaned = false; for (String value : userList) { //each value may be comma separated. List<String> update = new ArrayList<>(); String[] items = value.split(","); boolean found = false; for (String item : items) { if (!item.equals(username)) { update.add(item); } else { found = true; roleChaned = true; } } if (found) { if (update.size() > 0) { newList.add(StringUtil.joinStringList(update, ",")); } } } if (roleChaned) { updateMap.add(new Pair(theRole, newList)); } } //do update Iterator<Pair<String, List<String>>> iterUpdate = updateMap.iterator(); while (iterUpdate.hasNext()) { Pair<String, List<String>> entry = iterUpdate.next(); roleConfig.clearProperty(entry.getA()); if (entry.getB().size() > 0) { roleConfig.addProperty(entry.getA(), entry.getB()); } } } }