unixuser+emailaliases import generally working with test data

This commit is contained in:
Michael Hoennig 2024-07-31 05:44:40 +02:00
parent 7193772f98
commit 6c49ba2478
13 changed files with 174 additions and 69 deletions

View File

@ -32,6 +32,7 @@ import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.PostLoad;
import jakarta.persistence.Table;
import jakarta.persistence.Transient;
import jakarta.persistence.Version;
@ -124,6 +125,14 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject<HsBookingI
@Transient
private PatchableMapWrapper<Object> resourcesWrapper;
@Transient
private boolean isLoaded;
@PostLoad
public void markAsLoaded() {
this.isLoaded = true;
}
public PatchableMapWrapper<Object> getResources() {
return PatchableMapWrapper.of(resourcesWrapper, (newWrapper) -> {resourcesWrapper = newWrapper; }, resources );
}

View File

@ -40,6 +40,17 @@ public class HostingAssetEntitySaveProcessor {
return this;
}
/// validates the entity itself including its properties, but ignoring some error messages for import of legacy data
public HostingAssetEntitySaveProcessor validateEntityIgnoring(final String ignoreRegExp) {
step("validateEntity", "prepareForSave");
MultiValidationException.throwIfNotEmpty(
validator.validateEntity(entity).stream()
.filter(errorMsg -> !errorMsg.matches(ignoreRegExp))
.toList()
);
return this;
}
/// hashing passwords etc.
@SuppressWarnings("unchecked")
public HostingAssetEntitySaveProcessor prepareForSave() {

View File

@ -18,7 +18,7 @@ import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringPrope
class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator {
// according to RFC 1035 (section 5) and RFC 1034
static final String RR_REGEX_NAME = "([a-z0-9\\._-]+|@)\\s+";
static final String RR_REGEX_NAME = "([a-z0-9\\.-]+|@)\\s+";
static final String RR_REGEX_TTL = "(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*";
static final String RR_REGEX_IN = "IN\\s+"; // record class IN for Internet
static final String RR_RECORD_TYPE = "[A-Z]+\\s+";

View File

@ -9,7 +9,6 @@ import jakarta.persistence.EntityManager;
import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
@ -24,16 +23,17 @@ class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator {
AlarmContact.isOptional(),
booleanProperty("locked").readOnly(),
integerProperty("userid").computedBy(HsUnixUserHostingAssetValidator::computeUserId),
integerProperty("userid").readOnly().initializedBy(HsUnixUserHostingAssetValidator::computeUserId),
integerProperty("SSD hard quota").unit("MB").maxFrom("SSD").withFactor(1024).optional(),
integerProperty("SSD soft quota").unit("MB").maxFrom("SSD hard quota").optional(),
integerProperty("HDD hard quota").unit("MB").maxFrom("HDD").withFactor(1024).optional(),
integerProperty("HDD soft quota").unit("MB").maxFrom("HDD hard quota").optional(),
stringProperty("shell")
// TODO.spec: do we want to change them all to /usr/bin/, also in import?
.provided("/bin/false", "/bin/bash", "/bin/csh", "/bin/dash", "/usr/bin/tcsh", "/usr/bin/zsh", "/usr/bin/passwd")
.withDefault("/bin/false"),
stringProperty("homedir").readOnly().computedBy(HsUnixUserHostingAssetValidator::computeHomedir),
stringProperty("homedir").readOnly().renderedBy(HsUnixUserHostingAssetValidator::computeHomedir),
stringProperty("totpKey").matchesRegEx("^0x([0-9A-Fa-f]{2})+$").minLength(20).maxLength(256).undisclosed().writeOnly().optional(),
passwordProperty("password").minLength(8).maxLength(40).hashedUsing(HashGenerator.Algorithm.LINUX_SHA512).writeOnly());
// TODO.spec: public SSH keys? (only if hsadmin-ng is only accessible with 2FA)

View File

@ -14,6 +14,9 @@ import java.util.stream.Collectors;
import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static net.hostsharing.hsadminng.hs.validation.ValidatableProperty.ComputeMode.IN_INIT;
import static net.hostsharing.hsadminng.hs.validation.ValidatableProperty.ComputeMode.IN_PREP;
import static net.hostsharing.hsadminng.hs.validation.ValidatableProperty.ComputeMode.IN_REVAMP;
// TODO.refa: rename to HsEntityProcessor, also subclasses
public abstract class HsEntityValidator<E extends PropertiesProvider> {
@ -109,7 +112,7 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
public void prepareProperties(final EntityManager em, final E entity) {
stream(propertyValidators).forEach(p -> {
if (!p.isReadOnly() && p.isComputed()) {
if (p.isComputed(IN_PREP) || p.isComputed(IN_INIT) && !entity.isLoaded() ) {
entity.directProps().put(p.propertyName, p.compute(em, entity));
}
});
@ -120,7 +123,7 @@ public abstract class HsEntityValidator<E extends PropertiesProvider> {
stream(propertyValidators).forEach(p -> {
if (p.isWriteOnly()) {
copy.remove(p.propertyName);
} else if (p.isReadOnly() && p.isComputed()) {
} else if (p.isComputed(IN_REVAMP)) {
copy.put(p.propertyName, p.compute(em, entity));
}
});

View File

@ -1,8 +1,8 @@
package net.hostsharing.hsadminng.hs.validation;
import lombok.Setter;
import net.hostsharing.hsadminng.hash.HashGenerator;
import net.hostsharing.hsadminng.hash.HashGenerator.Algorithm;
import lombok.Setter;
import java.util.List;
import java.util.stream.Stream;
@ -13,7 +13,10 @@ import static net.hostsharing.hsadminng.mapper.Array.insertNewEntriesAfterExisti
@Setter
public class PasswordProperty extends StringProperty<PasswordProperty> {
private static final String[] KEY_ORDER = insertNewEntriesAfterExistingEntry(StringProperty.KEY_ORDER, "computed", "hashedUsing");
private static final String[] KEY_ORDER = insertNewEntriesAfterExistingEntry(
StringProperty.KEY_ORDER,
"computed",
"hashedUsing");
private Algorithm hashedUsing;
@ -34,10 +37,11 @@ public class PasswordProperty extends StringProperty<PasswordProperty> {
public PasswordProperty hashedUsing(final Algorithm algorithm) {
this.hashedUsing = algorithm;
computedBy((em, entity)
-> ofNullable(entity.getDirectValue(propertyName, String.class))
.map(password -> HashGenerator.using(algorithm).withRandomSalt().hash(password))
.orElse(null));
computedBy(
ComputeMode.IN_PREP,
(em, entity) -> ofNullable(entity.getDirectValue(propertyName, String.class))
.map(password -> HashGenerator.using(algorithm).withRandomSalt().hash(password))
.orElse(null));
return self();
}
@ -69,9 +73,10 @@ public class PasswordProperty extends StringProperty<PasswordProperty> {
}
}
final long groupsCovered = Stream.of(hasLowerCase, hasUpperCase, hasDigit, hasSpecialChar).filter(v->v).count();
if ( groupsCovered < 3) {
result.add(propertyName + "' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters");
final long groupsCovered = Stream.of(hasLowerCase, hasUpperCase, hasDigit, hasSpecialChar).filter(v -> v).count();
if (groupsCovered < 3) {
result.add(propertyName
+ "' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters");
}
if (containsColon) {
result.add(propertyName + "' must not contain colon (':')");

View File

@ -4,6 +4,7 @@ import java.util.Map;
public interface PropertiesProvider {
boolean isLoaded();
Map<String, Object> directProps();
Object getContextValue(final String propName);
@ -11,6 +12,10 @@ public interface PropertiesProvider {
return cast(propName, directProps().get(propName), clazz, null);
}
default <T> T getDirectValue(final String propName, final Class<T> clazz, final T defaultValue) {
return cast(propName, directProps().get(propName), clazz, defaultValue);
}
default <T> T getContextValue(final String propName, final Class<T> clazz) {
return cast(propName, getContextValue(propName), clazz, null);
}

View File

@ -48,11 +48,17 @@ public abstract class ValidatableProperty<P extends ValidatableProperty<?, ?>, T
private Set<String> requiresAtMaxOneOf;
private T defaultValue;
protected enum ComputeMode {
IN_INIT,
IN_PREP,
IN_REVAMP
}
@JsonIgnore
private BiFunction<EntityManager, PropertiesProvider, T> computedBy;
@Accessors(makeFinal = true, chain = true, fluent = false)
private boolean computed; // used in descriptor, because computedBy cannot be rendered to a text string
private ComputeMode computed; // name 'computed' instead 'computeMode' for better readability in property description
@Accessors(makeFinal = true, chain = true, fluent = false)
private boolean readOnly;
@ -77,7 +83,7 @@ public abstract class ValidatableProperty<P extends ValidatableProperty<?, ?>, T
return null;
}
protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]> function) {
protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]> function) {
this.deferredInit = function;
}
@ -236,8 +242,8 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
protected abstract void validate(final List<String> result, final T propValue, final PropertiesProvider propProvider);
public void verifyConsistency(final Map.Entry<? extends Enum<?>, ?> typeDef) {
if (required == null && requiresAtLeastOneOf == null && requiresAtMaxOneOf == null && !readOnly && !computed) {
throw new IllegalStateException(typeDef.getKey() + "[" + propertyName + "] not fully initialized, please call either .computed(...), .readOnly(), .required(), .optional(), .withDefault(...), .requiresAtLeastOneOf(...) or .requiresAtMaxOneOf(...)" );
if (required == null && requiresAtLeastOneOf == null && requiresAtMaxOneOf == null && !readOnly && defaultValue == null) {
throw new IllegalStateException(typeDef.getKey() + "[" + propertyName + "] not fully initialized, please call either .readOnly(), .required(), .optional(), .withDefault(...), .requiresAtLeastOneOf(...) or .requiresAtMaxOneOf(...)" );
}
}
@ -302,12 +308,24 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
.toList();
}
public P computedBy(final BiFunction<EntityManager, PropertiesProvider, T> compute) {
public P initializedBy(final BiFunction<EntityManager, PropertiesProvider, T> compute) {
return computedBy(ComputeMode.IN_INIT, compute);
}
public P renderedBy(final BiFunction<EntityManager, PropertiesProvider, T> compute) {
return computedBy(ComputeMode.IN_REVAMP, compute);
}
protected P computedBy(final ComputeMode computeMode, final BiFunction<EntityManager, PropertiesProvider, T> compute) {
this.computedBy = compute;
this.computed = true;
this.computed = computeMode;
return self();
}
public boolean isComputed(final ComputeMode computeMode) {
return computed == computeMode;
}
public <E extends PropertiesProvider> T compute(final EntityManager em, final E entity) {
return computedBy.apply(em, entity);
}

View File

@ -26,6 +26,8 @@ import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
@ -230,7 +232,7 @@ public class CsvDataImport extends ContextBasedTest {
}
void logErrors() {
assumeThat(errors).isEmpty();
assertThat(errors).isEmpty();
}
}
@ -298,12 +300,17 @@ class Record {
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface ContinueOnFailure {
}
class OrderedDependedTestsExtension implements TestWatcher, BeforeEachCallback {
private static boolean previousTestsPassed = true;
public void testFailed(ExtensionContext context, Throwable cause) {
previousTestsPassed = false;
@Override
public void testFailed(final ExtensionContext context, final Throwable cause) {
previousTestsPassed = previousTestsPassed && context.getElement().map(e -> e.isAnnotationPresent(ContinueOnFailure.class)).orElse(false);
}
@Override

View File

@ -287,20 +287,20 @@ public class ImportHostingAssets extends ImportOfficeData {
// no contacts yet => mostly null values
assertThat(firstOfEachType(15, UNIX_USER)).isEqualToIgnoringWhitespace("""
{
4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102090}),
4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102091}),
4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102093}),
4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}),
4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}),
4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}),
4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102147}),
4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "shell": "/bin/bash", "userid": 102148}),
4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102160}),
4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102090}),
4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102091}),
4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 8, "SSD soft quota": 4, "locked": false, "shell": "/bin/bash", "userid": 102093}),
4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102094}),
4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/usr/bin/passwd", "userid": 102095}),
4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 1024, "SSD soft quota": 1024, "locked": false, "shell": "/usr/bin/passwd", "userid": 102106}),
4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102147}),
4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "shell": "/bin/bash", "userid": 102148}),
4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 102160}),
4100705=HsHostingAssetEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 10003}),
4100824=HsHostingAssetEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 10000}),
4167846=HsHostingAssetEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/false", "userid": 110568}),
4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110593}),
4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110594})
4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110593}),
4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "shell": "/bin/bash", "userid": 110594})
}
""");
}
@ -324,12 +324,16 @@ public class ImportHostingAssets extends ImportOfficeData {
// no contacts yet => mostly null values
assertThat(firstOfEachType(15, EMAIL_ALIAS)).isEqualToIgnoringWhitespace("""
{
4002403=HsHostingAssetEntity(EMAIL_ALIAS, lug00, lug00, MANAGED_WEBSPACE:lug00, { "target": "[michael.mellis@example.com]"}),
4002405=HsHostingAssetEntity(EMAIL_ALIAS, lug00-wla-listar, lug00-wla-listar, MANAGED_WEBSPACE:lug00, { "target": "[|/home/pacs/lug00/users/in/mailinglist/listar]"}),
4002429=HsHostingAssetEntity(EMAIL_ALIAS, mim00, mim00, MANAGED_WEBSPACE:mim00, { "target": "[mim12-mi@mim12.hostsharing.net]"}),
4002431=HsHostingAssetEntity(EMAIL_ALIAS, mim00-abruf, mim00-abruf, MANAGED_WEBSPACE:mim00, { "target": "[michael.mellis@hostsharing.net]"}),
4002449=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx, mim00-hhfx, MANAGED_WEBSPACE:mim00, { "target": "[mim00-hhfx, |/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l]"}),
4002451=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx-l, mim00-hhfx-l, MANAGED_WEBSPACE:mim00, { "target": "[:include:/home/pacs/mim00/etc/hhfx.list]"})
5002403=HsHostingAssetEntity(EMAIL_ALIAS, lug00, lug00, MANAGED_WEBSPACE:lug00, { "target": "[michael.mellis@example.com]"}),
5002405=HsHostingAssetEntity(EMAIL_ALIAS, lug00-wla-listar, lug00-wla-listar, MANAGED_WEBSPACE:lug00, { "target": "[|/home/pacs/lug00/users/in/mailinglist/listar]"}),
5002429=HsHostingAssetEntity(EMAIL_ALIAS, mim00, mim00, MANAGED_WEBSPACE:mim00, { "target": "[mim12-mi@mim12.hostsharing.net]"}),
5002431=HsHostingAssetEntity(EMAIL_ALIAS, mim00-abruf, mim00-abruf, MANAGED_WEBSPACE:mim00, { "target": "[michael.mellis@hostsharing.net]"}),
5002449=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx, mim00-hhfx, MANAGED_WEBSPACE:mim00, { "target": "[mim00-hhfx, |/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l]"}),
5002451=HsHostingAssetEntity(EMAIL_ALIAS, mim00-hhfx-l, mim00-hhfx-l, MANAGED_WEBSPACE:mim00, { "target": "[:include:/home/pacs/mim00/etc/hhfx.list]"}),
5002452=HsHostingAssetEntity(EMAIL_ALIAS, mim00-empty, mim00-empty, MANAGED_WEBSPACE:mim00, { "target": "[]"}),
5002453=HsHostingAssetEntity(EMAIL_ALIAS, mim00-0_entries, mim00-0_entries, MANAGED_WEBSPACE:mim00, { "target": "[]"}),
5002454=HsHostingAssetEntity(EMAIL_ALIAS, mim00-dev.null, mim00-dev.null, MANAGED_WEBSPACE:mim00, { "target": "[/dev/null]"}),
5002455=HsHostingAssetEntity(EMAIL_ALIAS, mim00-1_with_space, mim00-1_with_space, MANAGED_WEBSPACE:mim00, { "target": "[|/home/pacs/mim00/install/corpslistar/listar]"})
}
""");
}
@ -337,7 +341,7 @@ public class ImportHostingAssets extends ImportOfficeData {
// --------------------------------------------------------------------------------------------
@Test
@Order(11400)
@Order(18010)
void validateBookingItems() {
bookingItems.forEach((id, bi) -> {
try {
@ -349,19 +353,27 @@ public class ImportHostingAssets extends ImportOfficeData {
}
@Test
@Order(11410)
@Order(18020)
void validateHostingAssets() {
hostingAssets.forEach((id, ha) -> {
try {
new HostingAssetEntitySaveProcessor(em, ha)
.preprocessEntity()
.validateEntity();
.validateEntityIgnoring("'EMAIL_ALIAS:.*\\.config\\.target' .*")
.prepareForSave();
} catch (final Exception exc) {
errors.add("validation failed for id:" + id + "( " + ha + "): " + exc.getMessage());
}
});
}
@Test
@Order(18999)
@ContinueOnFailure
void logValidationErrors() {
super.logErrors();
}
// --------------------------------------------------------------------------------------------
@Test
@ -389,30 +401,28 @@ public class ImportHostingAssets extends ImportOfficeData {
persistHostingAssetsOfType(EMAIL_ALIAS);
}
@Test
@Order(19010)
void verifyPersistedUnixUsersWithUserId() {
assumeThatWeAreImportingControlledTestData();
// no contacts yet => mostly null value
// FIXME: keep original userids
assertThat(firstOfEachType(15, UNIX_USER)).isEqualToIgnoringWhitespace("""
{
4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000000}),
4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000001}),
4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000002}),
4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 100000003}),
4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 100000004}),
4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 100000005}),
4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000006}),
4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000007}),
4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000008}),
4100705=HsHostingAssetEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/false", "userid": 100000009}),
4100824=HsHostingAssetEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000010}),
4167846=HsHostingAssetEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/false", "userid": 100000011}),
4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000012}),
4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 100000013})
4005803=HsHostingAssetEntity(UNIX_USER, lug00, LUGs, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102090}),
4005805=HsHostingAssetEntity(UNIX_USER, lug00-wla.1, Paul Klemm, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102091}),
4005809=HsHostingAssetEntity(UNIX_USER, lug00-wla.2, Walter Müller, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 8, "SSD soft quota": 4, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102093}),
4005811=HsHostingAssetEntity(UNIX_USER, lug00-ola.a, LUG OLA - POP a, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 102094}),
4005813=HsHostingAssetEntity(UNIX_USER, lug00-ola.b, LUG OLA - POP b, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 102095}),
4005835=HsHostingAssetEntity(UNIX_USER, lug00-test, Test, MANAGED_WEBSPACE:lug00, { "SSD hard quota": 1024, "SSD soft quota": 1024, "locked": false, "password": null, "shell": "/usr/bin/passwd", "userid": 102106}),
4005964=HsHostingAssetEntity(UNIX_USER, mim00, Michael Mellis, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102147}),
4005966=HsHostingAssetEntity(UNIX_USER, mim00-1981, Jahrgangstreffen 1981, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 256, "SSD soft quota": 128, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102148}),
4005990=HsHostingAssetEntity(UNIX_USER, mim00-mail, Mailbox, MANAGED_WEBSPACE:mim00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 102160}),
4100705=HsHostingAssetEntity(UNIX_USER, hsh00-mim, Michael Mellis, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/false", "userid": 10003}),
4100824=HsHostingAssetEntity(UNIX_USER, hsh00, Hostsharing Paket, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 10000}),
4167846=HsHostingAssetEntity(UNIX_USER, hsh00-dph, hsh00-uph, MANAGED_WEBSPACE:hsh00, { "HDD hard quota": 0, "HDD soft quota": 0, "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/false", "userid": 110568}),
4169546=HsHostingAssetEntity(UNIX_USER, dph00, Reinhard Wiese, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 110593}),
4169596=HsHostingAssetEntity(UNIX_USER, dph00-uph, Domain admin, MANAGED_WEBSPACE:dph00, { "SSD hard quota": 0, "SSD soft quota": 0, "locked": false, "password": null, "shell": "/bin/bash", "userid": 110594})
}
""");
}
@ -436,12 +446,12 @@ public class ImportHostingAssets extends ImportOfficeData {
private void persistHostingAssetsOfType(final HsHostingAssetType hsHostingAssetType) {
jpaAttempt.transacted(() -> {
context(rbacSuperuser);
hostingAssets.forEach((key, ha) -> {
context(rbacSuperuser);
if (ha.getType() == hsHostingAssetType) {
new HostingAssetEntitySaveProcessor(em, ha)
.preprocessEntity()
.validateEntity()
.validateEntityIgnoring("'EMAIL_ALIAS:.*\\.config\\.target' .*")
.prepareForSave()
.saveUsing(entity -> persist(key, entity))
.validateContext();
@ -522,8 +532,8 @@ public class ImportHostingAssets extends ImportOfficeData {
.isTrue());
final var asset = HsHostingAssetEntity.builder()
.isLoaded(haType
== MANAGED_WEBSPACE) // this turns off identifier validation to accept former default prefixes
// this turns off identifier validation to accept former default prefixes
.isLoaded(haType == MANAGED_WEBSPACE)
.type(haType)
.identifier(packet_name)
.bookingItem(bookingItem)
@ -663,9 +673,10 @@ public class ImportHostingAssets extends ImportOfficeData {
final var packet_id = rec.getInteger("packet_id");
final var unixUserAsset = HsHostingAssetEntity.builder()
.type(UNIX_USER)
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET+packet_id))
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET + packet_id))
.identifier(rec.getString("name"))
.caption(rec.getString("comment"))
.isLoaded(true) // avoid overwriting imported userids with generated ids
.config(new HashMap<>(Map.ofEntries(
entry("shell", rec.getString("shell")),
// entry("homedir", rec.getString("homedir")), do not import, it's calculated
@ -677,6 +688,33 @@ public class ImportHostingAssets extends ImportOfficeData {
entry("HDD hard quota", rec.getInteger("storage_hardlimit"))
)))
.build();
// TODO.spec: crop SSD+HDD limits if > booked
if (unixUserAsset.getDirectValue("SSD hard quota", Integer.class, 0)
> 1024*unixUserAsset.getContextValue("SSD", Integer.class, 0)) {
unixUserAsset.getConfig().put("SSD hard quota", unixUserAsset.getContextValue("SSD", Integer.class, 0)*1024);
}
if (unixUserAsset.getDirectValue("HDD hard quota", Integer.class, 0)
> 1024*unixUserAsset.getContextValue("HDD", Integer.class, 0)) {
unixUserAsset.getConfig().put("HDD hard quota", unixUserAsset.getContextValue("HDD", Integer.class, 0)*1024);
}
// TODO.spec: does `softlimit<hardlimit?` even make sense? Fix it in this or the other direction?
if (unixUserAsset.getDirectValue("SSD soft quota", Integer.class, 0)
> unixUserAsset.getDirectValue("SSD hard quota", Integer.class, 0)) {
unixUserAsset.getConfig().put("SSD soft quota", unixUserAsset.getConfig().get("SSD hard quota"));
}
if (unixUserAsset.getDirectValue("HDD soft quota", Integer.class, 0)
> unixUserAsset.getDirectValue("HDD hard quota", Integer.class, 0)) {
unixUserAsset.getConfig().put("HDD soft quota", unixUserAsset.getConfig().get("HDD hard quota"));
}
// TODO.spec: remove HDD limits if no HDD storage is booked
if (unixUserAsset.getContextValue("HDD", Integer.class, 0) == 0) {
unixUserAsset.getConfig().remove("HDD hard quota");
unixUserAsset.getConfig().remove("HDD soft quota");
}
hostingAssets.put(UNIXUSER_ID_OFFSET + unixuser_id, unixUserAsset);
});
}
@ -692,7 +730,7 @@ public class ImportHostingAssets extends ImportOfficeData {
final var targets = parseCsvLine(rec.getString("target"));
final var unixUserAsset = HsHostingAssetEntity.builder()
.type(EMAIL_ALIAS)
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET+packet_id))
.parentAsset(hostingAssets.get(PACKET_ID_OFFSET + packet_id))
.identifier(rec.getString("name"))
.caption(rec.getString("name"))
.config(Map.ofEntries(

View File

@ -103,6 +103,11 @@ class PasswordPropertyUnitTest {
// when
final var result = passwordProp.compute(em, new PropertiesProvider() {
@Override
public boolean isLoaded() {
return false;
}
@Override
public Map<String, Object> directProps() {
return Map.ofEntries(

View File

@ -5,3 +5,7 @@ emailalias_id;pac_id;name;target
2431;1112;mim00-abruf;michael.mellis@hostsharing.net
2449;1112;mim00-hhfx;"mim00-hhfx,""|/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l"""
2451;1112;mim00-hhfx-l;:include:/home/pacs/mim00/etc/hhfx.list
2452;1112;mim00-empty;
2453;1112;mim00-0_entries;""
2454;1112;mim00-dev.null; /dev/null
2455;1112;mim00-1_with_space;" ""|/home/pacs/mim00/install/corpslistar/listar"""

1 emailalias_id pac_id name target
5 2431 1112 mim00-abruf michael.mellis@hostsharing.net
6 2449 1112 mim00-hhfx mim00-hhfx,"|/usr/bin/formail -I 'Reply-To: hamburger-fx@example.net' | /usr/lib/sendmail mim00-hhfx-l"
7 2451 1112 mim00-hhfx-l :include:/home/pacs/mim00/etc/hhfx.list
8 2452 1112 mim00-empty
9 2453 1112 mim00-0_entries
10 2454 1112 mim00-dev.null /dev/null
11 2455 1112 mim00-1_with_space "|/home/pacs/mim00/install/corpslistar/listar"

View File

@ -2,11 +2,11 @@ unixuser_id;name;comment;shell;homedir;locked;packet_id;userid;quota_softlimit;q
100824;hsh00;Hostsharing Paket;/bin/bash;/home/pacs/hsh00;0;630;10000;0;0;0;0
5803;lug00;LUGs;/bin/bash;/home/pacs/lug00;0;1094;102090;0;0;0;0
5805;lug00-wla.1;Paul Klemm;/bin/bash;/home/pacs/lug00/users/deaf;0;1094;102091;0;0;0;0
5809;lug00-wla.2;Walter Müller;/bin/bash;/home/pacs/lug00/users/marl;0;1094;102093;0;0;0;0
5805;lug00-wla.1;Paul Klemm;/bin/bash;/home/pacs/lug00/users/deaf;0;1094;102091;4;0;0;0
5809;lug00-wla.2;Walter Müller;/bin/bash;/home/pacs/lug00/users/marl;0;1094;102093;4;8;0;0
5811;lug00-ola.a;LUG OLA - POP a;/usr/bin/passwd;/home/pacs/lug00/users/marl.a;1;1094;102094;0;0;0;0
5813;lug00-ola.b;LUG OLA - POP b;/usr/bin/passwd;/home/pacs/lug00/users/marl.b;1;1094;102095;0;0;0;0
5835;lug00-test;Test;/usr/bin/passwd;/home/pacs/lug00/users/test;0;1094;102106;0;0;0;0
5835;lug00-test;Test;/usr/bin/passwd;/home/pacs/lug00/users/test;0;1094;102106;2000000;4000000;20;0
100705;hsh00-mim;Michael Mellis;/bin/false;/home/pacs/hsh00/users/mi;0;630;10003;0;0;0;0
5964;mim00;Michael Mellis;/bin/bash;/home/pacs/mim00;0;1112;102147;0;0;0;0

1 unixuser_id name comment shell homedir locked packet_id userid quota_softlimit quota_hardlimit storage_softlimit storage_hardlimit
2 100824 hsh00 Hostsharing Paket /bin/bash /home/pacs/hsh00 0 630 10000 0 0 0 0
3 5803 lug00 LUGs /bin/bash /home/pacs/lug00 0 1094 102090 0 0 0 0
4 5805 lug00-wla.1 Paul Klemm /bin/bash /home/pacs/lug00/users/deaf 0 1094 102091 0 4 0 0 0
5 5809 lug00-wla.2 Walter Müller /bin/bash /home/pacs/lug00/users/marl 0 1094 102093 0 4 0 8 0 0
6 5811 lug00-ola.a LUG OLA - POP a /usr/bin/passwd /home/pacs/lug00/users/marl.a 1 1094 102094 0 0 0 0
7 5813 lug00-ola.b LUG OLA - POP b /usr/bin/passwd /home/pacs/lug00/users/marl.b 1 1094 102095 0 0 0 0
8 5835 lug00-test Test /usr/bin/passwd /home/pacs/lug00/users/test 0 1094 102106 0 2000000 0 4000000 0 20 0
9 100705 hsh00-mim Michael Mellis /bin/false /home/pacs/hsh00/users/mi 0 630 10003 0 0 0 0
10 5964 mim00 Michael Mellis /bin/bash /home/pacs/mim00 0 1112 102147 0 0 0 0
11 5966 mim00-1981 Jahrgangstreffen 1981 /bin/bash /home/pacs/mim00/users/1981 0 1112 102148 128 256 0 0
12 5990 mim00-mail Mailbox /bin/bash /home/pacs/mim00/users/mail 0 1112 102160 0 0 0 0