import-database-users-and-databases (#82)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/82 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@ -27,6 +27,7 @@ public final class HashGenerator {
|
||||
"abcdefghijklmnopqrstuvwxyz" +
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
"0123456789/.";
|
||||
private static boolean couldBeHashEnabled; // TODO.impl: remove after legacy data is migrated
|
||||
|
||||
public enum Algorithm {
|
||||
LINUX_SHA512(LinuxEtcShadowHashGenerator::hash, "6"),
|
||||
@ -59,6 +60,14 @@ public final class HashGenerator {
|
||||
this.algorithm = algorithm;
|
||||
}
|
||||
|
||||
public static void enableChouldBeHash(final boolean enable) {
|
||||
couldBeHashEnabled = enable;
|
||||
}
|
||||
|
||||
public boolean couldBeHash(final String value) {
|
||||
return couldBeHashEnabled && value.startsWith(algorithm.prefix);
|
||||
}
|
||||
|
||||
public String hash(final String plaintextPassword) {
|
||||
if (plaintextPassword == null) {
|
||||
throw new IllegalStateException("no password given");
|
||||
@ -67,6 +76,12 @@ public final class HashGenerator {
|
||||
return algorithm.implementation.apply(this, plaintextPassword);
|
||||
}
|
||||
|
||||
public String hashIfNotYetHashed(final String plaintextPasswordOrHash) {
|
||||
return couldBeHash(plaintextPasswordOrHash)
|
||||
? plaintextPasswordOrHash
|
||||
: hash(plaintextPasswordOrHash);
|
||||
}
|
||||
|
||||
public static void nextSalt(final String salt) {
|
||||
predefinedSalts.add(salt);
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ public enum HsHostingAssetType implements Node {
|
||||
inGroup("Webspace"),
|
||||
requiredParent(MANAGED_WEBSPACE)),
|
||||
|
||||
// TODO.spec: do we really want to keep email aliases or migrate to unix users with .forward?
|
||||
EMAIL_ALIAS( // named e.g. xyz00-abc
|
||||
inGroup("Webspace"),
|
||||
requiredParent(MANAGED_WEBSPACE)),
|
||||
|
@ -9,6 +9,8 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
|
||||
|
||||
class HsMariaDbDatabaseHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
final static String HEAD_REGEXP = "^MAD\\|";
|
||||
|
||||
public HsMariaDbDatabaseHostingAssetValidator() {
|
||||
super(
|
||||
MARIADB_DATABASE,
|
||||
@ -20,6 +22,6 @@ class HsMariaDbDatabaseHostingAssetValidator extends HostingAssetEntityValidator
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
|
||||
final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier();
|
||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
|
||||
return Pattern.compile(HEAD_REGEXP+webspaceIdentifier+"$|"+HEAD_REGEXP+webspaceIdentifier+"_[a-zA-Z0-9_]+$");
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,8 @@ import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordP
|
||||
|
||||
class HsMariaDbUserHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
final static String HEAD_REGEXP = "^MAU\\|";
|
||||
|
||||
public HsMariaDbUserHostingAssetValidator() {
|
||||
super(
|
||||
MARIADB_USER,
|
||||
@ -28,6 +30,6 @@ class HsMariaDbUserHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
|
||||
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
|
||||
return Pattern.compile(HEAD_REGEXP+webspaceIdentifier+"$|"+HEAD_REGEXP+webspaceIdentifier+"_[a-zA-Z0-9_]+$");
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,8 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
|
||||
|
||||
class HsPostgreSqlDatabaseHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
final static String HEAD_REGEXP = "^PGD\\|";
|
||||
|
||||
public HsPostgreSqlDatabaseHostingAssetValidator() {
|
||||
super(
|
||||
PGSQL_DATABASE,
|
||||
@ -23,6 +25,6 @@ class HsPostgreSqlDatabaseHostingAssetValidator extends HostingAssetEntityValida
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
|
||||
final var webspaceIdentifier = assetEntity.getParentAsset().getParentAsset().getIdentifier();
|
||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
|
||||
return Pattern.compile(HEAD_REGEXP+webspaceIdentifier+"$|"+HEAD_REGEXP+webspaceIdentifier+"_[a-zA-Z0-9_]+$");
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAsset;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static java.util.Optional.ofNullable;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_DATABASE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.PGSQL_INSTANCE;
|
||||
|
||||
class HsPostgreSqlDbInstanceHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
@ -13,7 +13,7 @@ class HsPostgreSqlDbInstanceHostingAssetValidator extends HostingAssetEntityVali
|
||||
|
||||
public HsPostgreSqlDbInstanceHostingAssetValidator() {
|
||||
super(
|
||||
PGSQL_DATABASE,
|
||||
PGSQL_INSTANCE,
|
||||
AlarmContact.isOptional(),
|
||||
|
||||
// TODO.spec: PostgreSQL extensions in database and here? also decide which. Free selection or booleans/checkboxes?
|
||||
|
@ -10,6 +10,8 @@ import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordP
|
||||
|
||||
class HsPostgreSqlUserHostingAssetValidator extends HostingAssetEntityValidator {
|
||||
|
||||
final static String HEAD_REGEXP = "^PGU\\|";
|
||||
|
||||
public HsPostgreSqlUserHostingAssetValidator() {
|
||||
super(
|
||||
PGSQL_USER,
|
||||
@ -28,6 +30,6 @@ class HsPostgreSqlUserHostingAssetValidator extends HostingAssetEntityValidator
|
||||
@Override
|
||||
protected Pattern identifierPattern(final HsHostingAsset assetEntity) {
|
||||
final var webspaceIdentifier = assetEntity.getParentAsset().getIdentifier();
|
||||
return Pattern.compile("^"+webspaceIdentifier+"$|^"+webspaceIdentifier+"_[a-z0-9_]+$");
|
||||
return Pattern.compile(HEAD_REGEXP+webspaceIdentifier+"$|"+HEAD_REGEXP+webspaceIdentifier+"_[a-zA-Z0-9_]+$");
|
||||
}
|
||||
}
|
||||
|
@ -31,6 +31,12 @@ public class PasswordProperty extends StringProperty<PasswordProperty> {
|
||||
|
||||
@Override
|
||||
protected void validate(final List<String> result, final String propValue, final PropertiesProvider propProvider) {
|
||||
// TODO.impl: remove after legacy data is migrated
|
||||
if (HashGenerator.using(hashedUsing).couldBeHash(propValue) && propValue.length() > this.maxLength()) {
|
||||
// already hashed => do not validate
|
||||
return;
|
||||
}
|
||||
|
||||
super.validate(result, propValue, propProvider);
|
||||
validatePassword(result, propValue);
|
||||
}
|
||||
@ -40,7 +46,7 @@ public class PasswordProperty extends StringProperty<PasswordProperty> {
|
||||
computedBy(
|
||||
ComputeMode.IN_PREP,
|
||||
(em, entity) -> ofNullable(entity.getDirectValue(propertyName, String.class))
|
||||
.map(password -> HashGenerator.using(algorithm).withRandomSalt().hash(password))
|
||||
.map(password -> HashGenerator.using(algorithm).withRandomSalt().hashIfNotYetHashed(password))
|
||||
.orElse(null));
|
||||
return self();
|
||||
}
|
||||
|
@ -41,11 +41,19 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
|
||||
return self();
|
||||
}
|
||||
|
||||
public Integer minLength() {
|
||||
return this.minLength;
|
||||
}
|
||||
|
||||
public P maxLength(final int maxLength) {
|
||||
this.maxLength = maxLength;
|
||||
return self();
|
||||
}
|
||||
|
||||
public Integer maxLength() {
|
||||
return this.maxLength;
|
||||
}
|
||||
|
||||
public P matchesRegEx(final String... regExPattern) {
|
||||
this.matchesRegEx = stream(regExPattern).map(Pattern::compile).toArray(Pattern[]::new);
|
||||
return self();
|
||||
|
Reference in New Issue
Block a user