/* * ProActive Parallel Suite(TM): * The Open Source library for parallel and distributed * Workflows & Scheduling, Orchestration, Cloud Automation * and Big Data Analysis on Enterprise Grids & Clouds. * * Copyright (c) 2007 - 2017 ActiveEon * Contact: contact@activeeon.com * * This library 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: version 3 of * the License. * * This program 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 this program. If not, see <http://www.gnu.org/licenses/>. * * If needed, contact us to obtain a release under GPL Version 2 or 3 * or a different license than the AGPL. */ package org.ow2.proactive.scheduler.authentication; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.security.KeyException; import java.security.PrivateKey; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import org.ow2.proactive.authentication.FileLoginModule; import org.ow2.proactive.authentication.crypto.Credentials; import org.ow2.proactive.authentication.crypto.HybridEncryptionUtil; import org.ow2.proactive.authentication.crypto.KeyGen; import org.ow2.tests.ProActiveTest; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; /** * Tests creation, modification and deletion of users with ManageUsers tool */ public class ManageUsersTest extends ProActiveTest { @Rule public TemporaryFolder tmpFolder = new TemporaryFolder(); File loginFile; File groupFile; File sourceLoginFile; File sourceGroupFile; private File privateKeyFile; private File publicKeyFile; PrivateKey privateKey; final List<String> sourceUsers1 = ImmutableList.of("user1:pwd1", "user2:pwd2", "userà:pwdà", "admin1:pwd3", "admin2:pwd4", "usernopwd:", ":nologin", "usernogroup:toobad"); final List<String> sourceUsers2 = ImmutableList.of("user1:pwda", "user2:pwdb", "userà:pwdé", "admin1:pwdc", "admin2:pwdd", "usernopwd:", ":nologin", "usernogroup:toobad"); final List<String> sourceGroups1 = ImmutableList.of("user1:user", "user2:user", "user2:other", "userà:groupà", "admin1:admin", "admin2:admin", "admin2:other", "useremptygroup:", ":nologin", "userwithoutcredentials:admin"); final List<String> sourceGroups2 = ImmutableList.of("user1:user", "user1:other", "user2:user", "userà:groupé", "admin1:admin", "admin1:other", "admin2:admin", "useremptygroup:", ":nologin", "userwithoutcredentials:admin"); final Map<String, String> users = ImmutableMap.<String, String> builder() .put("user1", "pwd1") .put("user2", "pwd2") .put("userà", "pwdà") .put("admin1", "pwd3") .put("admin2", "pwd4") .build(); final Map<String, String> users2 = ImmutableMap.<String, String> builder() .put("user1", "pwda") .put("user2", "pwdb") .put("userà", "pwdé") .put("admin1", "pwdc") .put("admin2", "pwdd") .build(); final Multimap<String, String> groups = ImmutableMultimap.<String, String> builder() .putAll("user1", "user") .putAll("user2", "user", "other") .putAll("userà", "groupà") .putAll("admin1", "admin") .putAll("admin2", "admin", "other") .build(); final Multimap<String, String> groups2 = ImmutableMultimap.<String, String> builder() .putAll("user1", "user", "other") .putAll("user2", "user") .putAll("userà", "groupé") .putAll("admin1", "admin", "other") .putAll("admin2", "admin") .build(); @Before public void init() throws Exception { loginFile = tmpFolder.newFile("login"); groupFile = tmpFolder.newFile("group"); sourceLoginFile = tmpFolder.newFile("sourcelogin"); sourceGroupFile = tmpFolder.newFile("sourcegroup"); privateKeyFile = tmpFolder.newFile("priv.key"); publicKeyFile = tmpFolder.newFile("pub.key"); KeyGen.main(new String[] { "-P", publicKeyFile.getAbsolutePath(), "-p", privateKeyFile.getAbsolutePath() }); privateKey = Credentials.getPrivateKey(privateKeyFile.getAbsolutePath()); } @Test public void testUsers() throws Exception { createUsers(); updateUsers(); deleteUsers(); } @Test public void testBulkLoadUsers() throws Exception { createBulkUsers(); updateBulkUsers(); deleteUsers(); } @Test public void testBulkLoadUsersPartialFiles() throws Exception { createBulkUsers(); updateBulkUsersLoginFile(); updateBulkUsersGroupFile(); validateContents(users2, groups2); deleteUsers(); } private String getGroupString(String user, Multimap<String, String> groupsToUser) { StringBuilder answer = new StringBuilder(); for (String group : groupsToUser.get(user)) { answer.append(group).append(","); } answer.deleteCharAt(answer.length() - 1); return answer.toString(); } private void createUsers() throws Exception { for (Map.Entry<String, String> user : users.entrySet()) { ManageUsers.manageUsers("-" + ManageUsers.CREATE_OPTION, "-" + ManageUsers.LOGIN_OPTION, user.getKey(), "-" + ManageUsers.PWD_OPTION, user.getValue(), "-" + ManageUsers.GROUPS_OPTION, getGroupString(user.getKey(), groups), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); } validateContents(users, groups); } private void createBulkUsers() throws Exception { FileUtils.writeLines(sourceLoginFile, sourceUsers1); FileUtils.writeLines(sourceGroupFile, sourceGroups1); ManageUsers.manageUsers("-" + ManageUsers.CREATE_OPTION, "-" + ManageUsers.SOURCE_LOGINFILE_OPTION, sourceLoginFile.getAbsolutePath(), "-" + ManageUsers.SOURCE_GROUPFILE_OPTION, sourceGroupFile.getAbsolutePath(), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); validateContents(users, groups); } private void updateUsers() throws Exception { for (Map.Entry<String, String> user : users2.entrySet()) { ManageUsers.manageUsers("-" + ManageUsers.UPDATE_OPTION, "-" + ManageUsers.LOGIN_OPTION, user.getKey(), "-" + ManageUsers.PWD_OPTION, user.getValue(), "-" + ManageUsers.GROUPS_OPTION, getGroupString(user.getKey(), groups2), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); } validateContents(users2, groups2); } private void updateBulkUsers() throws Exception { FileUtils.writeLines(sourceLoginFile, sourceUsers2); FileUtils.writeLines(sourceGroupFile, sourceGroups2); ManageUsers.manageUsers("-" + ManageUsers.UPDATE_OPTION, "-" + ManageUsers.SOURCE_LOGINFILE_OPTION, sourceLoginFile.getAbsolutePath(), "-" + ManageUsers.SOURCE_GROUPFILE_OPTION, sourceGroupFile.getAbsolutePath(), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); validateContents(users2, groups2); } private void updateBulkUsersLoginFile() throws Exception { FileUtils.writeLines(sourceLoginFile, sourceUsers2); ManageUsers.manageUsers("-" + ManageUsers.UPDATE_OPTION, "-" + ManageUsers.SOURCE_LOGINFILE_OPTION, sourceLoginFile.getAbsolutePath(), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); } private void updateBulkUsersGroupFile() throws Exception { FileUtils.writeLines(sourceGroupFile, sourceGroups2); ManageUsers.manageUsers("-" + ManageUsers.UPDATE_OPTION, "-" + ManageUsers.SOURCE_GROUPFILE_OPTION, sourceGroupFile.getAbsolutePath(), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); } private void deleteUsers() throws Exception { for (Map.Entry<String, String> user : users.entrySet()) { ManageUsers.manageUsers("-" + ManageUsers.DELETE_OPTION, "-" + ManageUsers.LOGIN_OPTION, user.getKey(), "-" + ManageUsers.LOGINFILE_OPTION, loginFile.getAbsolutePath(), "-" + ManageUsers.GROUPFILE_OPTION, groupFile.getAbsolutePath(), "-" + ManageUsers.KEYFILE_OPTION, publicKeyFile.getAbsolutePath()); } String loginContent = IOUtils.toString(loginFile.toURI()); System.out.println("Login file content after deletion:"); System.out.println(loginContent); Assert.assertTrue("login file should be empty", loginContent.trim().isEmpty()); String groupContent = IOUtils.toString(groupFile.toURI()); System.out.println("Group file content after deletion:"); System.out.println(groupContent); Assert.assertTrue("group file should be empty", groupContent.trim().isEmpty()); } private void validateContents(Map<String, String> usersToCheck, Multimap<String, String> groupsToCheck) throws IOException, KeyException { Properties props = new Properties(); try (Reader reader = new InputStreamReader(new FileInputStream(loginFile))) { props.load(reader); String groupContent = IOUtils.toString(groupFile.toURI()); for (Map.Entry<String, String> user : usersToCheck.entrySet()) { Assert.assertTrue("login file should contain " + user.getKey(), props.containsKey(user.getKey())); String encryptedPassword = (String) props.get(user.getKey()); String password = HybridEncryptionUtil.decryptBase64String(encryptedPassword, privateKey, FileLoginModule.ENCRYPTED_DATA_SEP); Assert.assertEquals("decrypted password for user " + user.getKey() + " should match", user.getValue(), password); for (String group : groupsToCheck.get(user.getKey())) { Assert.assertTrue("group file should contain " + user.getKey() + ":" + group, groupContent.contains(user.getKey() + ":" + group)); } } } } }