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

org.wildfly.extras.creaper.commands.auth.PropertiesFileAuth Maven / Gradle / Ivy

There is a newer version: 2.0.3
Show newest version
package org.wildfly.extras.creaper.commands.auth;

import com.google.common.base.Charsets;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Predicates;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;
import org.wildfly.extras.creaper.core.CommandFailedException;
import org.wildfly.extras.creaper.core.offline.OfflineCommand;
import org.wildfly.extras.creaper.core.offline.OfflineCommandContext;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 

Provides a set of offline commands to manipulate authentication and authorization {@code .properties} files.

* *

The generic factory methods ({@link #inConfigurationDirectory(String)} or {@link #of(java.io.File)}}) return * an instance of this class, so that methods for working with users and methods for working with user mappings * are both available.

* *

The configuration file specific factory methods ({@link #applicationUsers()}, {@link #applicationRoles()}, * {@link #mgmtUsers()} and {@link #mgmtGroups()}) return an instance of a view class that only exposes methods for * working with users ({@link Users}) or methods for working with user mappings ({@link UserMappings}). This is only * for convenience (static checking), there's no change in functionality.

*/ public final class PropertiesFileAuth { private static final String APPLICATION_USERS = "application-users.properties"; private static final String APPLICATION_ROLES = "application-roles.properties"; private static final String MGMT_USERS = "mgmt-users.properties"; private static final String MGMT_GROUPS = "mgmt-groups.properties"; // exactly one is always null and the other is always non-null // see the method "thePropertiesFile" below private final String fileName; private final File file; /** * Creates a {@link PropertiesFileAuth.Users} object for the {@code application-users.properties} file * in the configuration directory of the {@code OfflineManagementClient}. */ public static PropertiesFileAuth.Users applicationUsers() { return new Users(inConfigurationDirectory(APPLICATION_USERS)); } /** * Creates a {@link PropertiesFileAuth.UserMappings} object for the {@code application-roles.properties} file * in the configuration directory of the {@code OfflineManagementClient}. */ public static PropertiesFileAuth.UserMappings applicationRoles() { return new UserMappings(inConfigurationDirectory(APPLICATION_ROLES)); } /** * Creates a {@link PropertiesFileAuth.Users} object for the {@code mgmt-users.properties} file * in the configuration directory of the {@code OfflineManagementClient}. */ public static PropertiesFileAuth.Users mgmtUsers() { return new Users(inConfigurationDirectory(MGMT_USERS)); } /** * Creates a {@link PropertiesFileAuth.UserMappings} object for the {@code mgmt-groups.properties} file * in the configuration directory of the {@code OfflineManagementClient}. */ public static PropertiesFileAuth.UserMappings mgmtGroups() { return new UserMappings(inConfigurationDirectory(MGMT_GROUPS)); } /** * Creates a {@code PropertiesFileAuth} object for the file named {@code fileName} that resides * in the configuration directory of the {@code OfflineManagementClient}. */ public static PropertiesFileAuth inConfigurationDirectory(String fileName) { return new PropertiesFileAuth(fileName, null); } /** Creates a {@code PropertiesFileAuth} object for given {@code file}. */ public static PropertiesFileAuth of(File file) { return new PropertiesFileAuth(null, file); } private PropertiesFileAuth(String fileName, File file) { this.fileName = fileName; this.file = file; } // --- private File thePropertiesFile(OfflineCommandContext ctx) { if (file != null) { return file; } return new File(ctx.options.configurationDirectory(), fileName); } private static final Pattern REALM = Pattern.compile("\\$REALM_NAME=(.*?)\\$"); private final class DefineUser implements OfflineCommand { private final String username; private final String password; DefineUser(String username, String password) { this.username = username; this.password = password; } @Override public void apply(OfflineCommandContext ctx) throws CommandFailedException, IOException { File file = thePropertiesFile(ctx); List lines = Files.readLines(file, Charsets.UTF_8); Optional realmLine = Iterables.tryFind(lines, Predicates.contains(REALM)); if (!realmLine.isPresent()) { throw new CommandFailedException("The $REALM_NAME=...$ directive is missing: " + file); } Matcher matcher = REALM.matcher(realmLine.get()); matcher.find(); String realm = matcher.group(1); Iterables.removeIf(lines, Predicates.containsPattern("^" + username + "=")); String authString = username + ":" + realm + ":" + password; String hashedAuthString = Hashing.md5().hashString(authString, Charsets.UTF_8).toString(); lines.add(username + "=" + hashedAuthString); Files.asCharSink(file, Charsets.UTF_8).writeLines(lines, "\n"); } @Override public String toString() { return "DefineUser " + username; } } private final class UndefineUser implements OfflineCommand { private final String username; UndefineUser(String username) { this.username = username; } @Override public void apply(OfflineCommandContext ctx) throws CommandFailedException, IOException { File file = thePropertiesFile(ctx); List lines = Files.readLines(file, Charsets.UTF_8); Iterables.removeIf(lines, Predicates.containsPattern("^" + Pattern.quote(username) + "=")); Files.asCharSink(file, Charsets.UTF_8).writeLines(lines, "\n"); } @Override public String toString() { return "UndefineUser " + username; } } private abstract class AbstractUserMapping implements OfflineCommand { private final String username; private final String roleOrGroup; private final boolean trueToAdd_falseToRemove; public AbstractUserMapping(String username, String roleOrGroup, boolean trueToAdd_falseToRemove) { this.username = username; this.roleOrGroup = roleOrGroup; this.trueToAdd_falseToRemove = trueToAdd_falseToRemove; } @Override public void apply(OfflineCommandContext ctx) throws CommandFailedException, IOException { File file = thePropertiesFile(ctx); List lines = Files.readLines(file, Charsets.UTF_8); Set allRolesOrGroupsForUser = Sets.newHashSet(); Iterable linesForUser = Iterables.filter(lines, Predicates.containsPattern("^" + Pattern.quote(username) + "=")); Splitter splitter = Splitter.on(',').omitEmptyStrings().trimResults(); for (String line : linesForUser) { String rolesOrGroups = line.replaceFirst("^" + Pattern.quote(username) + "=", ""); allRolesOrGroupsForUser.addAll(splitter.splitToList(rolesOrGroups)); } if (trueToAdd_falseToRemove) { allRolesOrGroupsForUser.add(roleOrGroup); } else { allRolesOrGroupsForUser.remove(roleOrGroup); } Iterables.removeIf(lines, Predicates.containsPattern("^" + Pattern.quote(username) + "=")); lines.add(username + "=" + Joiner.on(',').join(allRolesOrGroupsForUser)); Files.asCharSink(file, Charsets.UTF_8).writeLines(lines, "\n"); } @Override public String toString() { return this.getClass().getSimpleName() + " " + username + " -> " + roleOrGroup; } } private final class DefineUserMapping extends AbstractUserMapping { DefineUserMapping(String username, String roleOrGroup) { super(username, roleOrGroup, true); } } private final class UndefineUserMapping extends AbstractUserMapping { UndefineUserMapping(String username, String roleOrGroup) { super(username, roleOrGroup, false); } } /** * Ensures that the {@code .properties} file, which must be a {@code *-users.properties} file, contains * a definition of a user with given {@code username} and given {@code password}. */ public OfflineCommand defineUser(String username, String password) { return new DefineUser(username, password); } /** * Ensures that the {@code .properties} file, which must be a {@code *-users.properties} file, doesn't * contain a definition of a user with given {@code username}. */ public OfflineCommand undefineUser(String username) { return new UndefineUser(username); } /** * Ensures that the {@code .properties} file, which must be a {@code *-.properties} file, contains * a mapping of a user with given {@code username} to given role/group ({@code roleOrGroup}). */ public OfflineCommand defineUserMapping(String username, String roleOrGroup) { return new DefineUserMapping(username, roleOrGroup); } /** * Ensures that the {@code .properties} file, which must be a {@code *-.properties} file, * doesn't contain a mapping of a user with given {@code username} to given role/group ({@code roleOrGroup}). */ public OfflineCommand undefineUserMapping(String username, String roleOrGroup) { return new UndefineUserMapping(username, roleOrGroup); } // --- // following classes are only used when the kind of the .properties file is known /** * Convenience view on {@link PropertiesFileAuth} that only exposes methods for working with users. */ public static final class Users { private final PropertiesFileAuth delegate; private Users(PropertiesFileAuth delegate) { this.delegate = delegate; } /** * Ensures that the {@code *-users.properties} file contains a definition of a user * with given {@code username} and given {@code password}. */ public OfflineCommand defineUser(String username, String password) { return delegate.defineUser(username, password); } /** * Ensures that the {@code *-users.properties} file doesn't contain a definition of a user * with given {@code username}. */ public OfflineCommand undefineUser(String username) { return delegate.undefineUser(username); } } /** Convenience view on {@link PropertiesFileAuth} that only exposes methods for working with user mappings. */ public static final class UserMappings { private final PropertiesFileAuth delegate; private UserMappings(PropertiesFileAuth delegate) { this.delegate = delegate; } /** * Ensures that the {@code *-.properties} file contains a mapping of a user * with given {@code username} to given role/group ({@code roleOrGroup}). */ public OfflineCommand defineUserMapping(String username, String roleOrGroup) { return delegate.defineUserMapping(username, roleOrGroup); } /** * Ensures that the {@code *-.properties} file doesn't contain a mapping of a user * with given {@code username} to given role/group ({@code roleOrGroup}). */ public OfflineCommand undefineUserMapping(String username, String roleOrGroup) { return delegate.undefineUserMapping(username, roleOrGroup); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy