diff --git a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd index 88598ba9e2c..8d60189ac1d 100644 --- a/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd +++ b/infra/schema/src/main/resources/xml/ns/public/common/common-core-3.xsd @@ -11585,6 +11585,16 @@ + + + Method used to store the values of this credential (encrypted, hashed, ...) + If storage method is not specified it defaults to encryption + (due to compatibility and convenience reasons). + + + 3.6 + + @@ -11655,6 +11665,18 @@ + + + + Method used to store historical values of the credential (encrypted, hashed, ...) + If storage type is not specified then it defaults to hashing. + + + 3.6 + + + + @@ -11839,6 +11861,13 @@ MidPoitn will only work with credential in the memory while it is needed to complete current operation. The credential will be discarded after the operation. + + THIS IS ONLY PARTIALLY SUPPORTED + + MidPoint should be able not to store the credentials when + this setting is used. But there may be side effects. + This is not entirelly tests and not supported. + Use at your own risk. diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java index 400419bee74..b44c51a093d 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/CredentialsProcessor.java @@ -40,6 +40,7 @@ import com.evolveum.midpoint.schema.constants.ExpressionConstants; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.schema.result.OperationResult; +import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.SchemaFailableProcessor; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; @@ -433,12 +434,8 @@ private void transformFocusExectionDeltaCredential(LensCo return; } CredentialPolicyType defaltCredPolicyType = credsType.getDefault(); - CredentialsStorageMethodType storageMethod = null; - if (credPolicyType != null && credPolicyType.getStorageMethod() != null) { - storageMethod = credPolicyType.getStorageMethod(); - } else if (defaltCredPolicyType != null && defaltCredPolicyType.getStorageMethod() != null) { - storageMethod = defaltCredPolicyType.getStorageMethod(); - } + CredentialsStorageMethodType storageMethod = + SecurityUtil.getCredPolicyItem(defaltCredPolicyType, credPolicyType, pol -> pol.getStorageMethod()); if (storageMethod == null) { return; } diff --git a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java index 5ce5c208083..79d2137035a 100644 --- a/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java +++ b/model/model-impl/src/main/java/com/evolveum/midpoint/model/impl/lens/projector/PasswordPolicyProcessor.java @@ -59,6 +59,7 @@ import com.evolveum.midpoint.schema.result.OperationResult; import com.evolveum.midpoint.schema.result.OperationResultStatus; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; +import com.evolveum.midpoint.security.api.SecurityUtil; import com.evolveum.midpoint.task.api.Task; import com.evolveum.midpoint.util.exception.ExpressionEvaluationException; import com.evolveum.midpoint.util.exception.ObjectNotFoundException; @@ -70,6 +71,8 @@ import com.evolveum.midpoint.xml.ns._public.common.common_3.CharacterClassType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CheckExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsPolicyType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageMethodType; +import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsStorageTypeType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CredentialsType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ExpressionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.FocusType; @@ -709,7 +712,6 @@ private String determinePasswordValue(ProtectedStringType passValue) { return passwordStr; } - public void processPasswordHistoryDeltas(LensFocusContext focusContext, LensContext context, SecurityPolicyType securityPolicy, XMLGregorianCalendar now, Task task, OperationResult result) throws SchemaException { @@ -729,7 +731,7 @@ public void processPasswordHistoryDeltas(LensFocusContext< List historyEntryValues = getSortedHistoryList(historyEntries, true); int newHistoryEntries = 0; if (maxPasswordsToSave > 0) { - newHistoryEntries = createAddHistoryDelta(context, password, now); + newHistoryEntries = createAddHistoryDelta(context, password, securityPolicy, now); } createDeleteHistoryDeltasIfNeeded(historyEntryValues, maxPasswordsToSave, newHistoryEntries, context, task, result); } @@ -794,9 +796,24 @@ private int getMaxPasswordsToSave(LensFocusContext focu private int createAddHistoryDelta(LensContext context, - PrismContainer password, XMLGregorianCalendar now) throws SchemaException { + PrismContainer password, SecurityPolicyType securityPolicy, XMLGregorianCalendar now) throws SchemaException { PrismContainerValue passwordValue = password.getValue(); - PasswordType passwordRealValue = passwordValue.asContainerable(); + PasswordType passwordType = passwordValue.asContainerable(); + if (passwordType == null || passwordType.getValue() == null) { + return 0; + } + ProtectedStringType passwordPsForStorage = passwordType.getValue().clone(); + + CredentialsStorageTypeType storageType = CredentialsStorageTypeType.HASHING; + CredentialsPolicyType creds = securityPolicy.getCredentials(); + if (creds != null) { + CredentialsStorageMethodType storageMethod = + SecurityUtil.getCredPolicyItem(creds.getDefault(), creds.getPassword(), pol -> pol.getStorageMethod()); + if (storageMethod != null && storageMethod.getStorageType() != null) { + storageType = storageMethod.getStorageType(); + } + } + prepareProtectedStringForStorage(passwordPsForStorage, storageType); PrismContainerDefinition historyEntryDefinition = password.getDefinition().findContainerDefinition(PasswordType.F_HISTORY_ENTRY); PrismContainer historyEntry = historyEntryDefinition.instantiate(); @@ -804,8 +821,8 @@ private int createAddHistoryDelta(LensContext context, PrismContainerValue hisotryEntryValue = historyEntry.createNewValue(); PasswordHistoryEntryType entryType = hisotryEntryValue.asContainerable(); - entryType.setValue(passwordRealValue.getValue()); - entryType.setMetadata(passwordRealValue.getMetadata()); + entryType.setValue(passwordPsForStorage); + entryType.setMetadata(passwordType.getMetadata()); entryType.setChangeTimestamp(now); ContainerDelta addHisotryDelta = ContainerDelta @@ -815,6 +832,37 @@ private int createAddHistoryDelta(LensContext context, return 1; } + + private void prepareProtectedStringForStorage(ProtectedStringType ps, CredentialsStorageTypeType storageType) throws SchemaException { + try { + switch (storageType) { + case ENCRYPTION: + if (ps.isEncrypted()) { + break; + } + if (ps.isHashed()) { + throw new SchemaException("Cannot store hashed value in an encrypted form"); + } + protector.encrypt(ps); + break; + + case HASHING: + if (ps.isHashed()) { + break; + } + protector.hash(ps); + break; + + case NONE: + throw new SchemaException("Cannot store value on NONE storage form"); + + default: + throw new SchemaException("Unknown storage type: "+storageType); + } + } catch (EncryptionException e) { + throw new SystemException(e.getMessage(), e); + } + } private void createDeleteHistoryDeltasIfNeeded( List historyEntryValues, int maxPasswordsToSave, int newHistoryEntries, LensContext context, Task task, diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java index da60d69e58c..1e5994d4b67 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/AbstractPasswordTest.java @@ -721,7 +721,10 @@ public void test202ReconcileUserJack() throws Exception { // GIVEN Task task = taskManager.createTaskInstance(AbstractPasswordTest.class.getName() + "." + TEST_NAME); OperationResult result = task.getResult(); - assumeAssignmentPolicy(AssignmentPolicyEnforcementType.FULL); + + PrismObject userBefore = getUser(USER_JACK_OID); + display("User before", userBefore); + assertLinks(userBefore, 4); // WHEN reconcileUser(USER_JACK_OID, task, result); @@ -730,27 +733,27 @@ public void test202ReconcileUserJack() throws Exception { result.computeStatus(); TestUtil.assertSuccess(result); - PrismObject userJack = getUser(USER_JACK_OID); - display("User after change execution", userJack); - assertLinks(userJack, 4); - accountYellowOid = getLinkRefOid(userJack, RESOURCE_DUMMY_YELLOW_OID); + PrismObject userAfter = getUser(USER_JACK_OID); + display("User after", userAfter); + assertLinks(userAfter, 4); + accountYellowOid = getLinkRefOid(userAfter, RESOURCE_DUMMY_YELLOW_OID); // Check account in dummy resource (yellow): password is too short for this, original password should remain there assertDummyAccount(RESOURCE_DUMMY_YELLOW_NAME, ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); - assertDummyPassword(RESOURCE_DUMMY_YELLOW_NAME, ACCOUNT_JACK_DUMMY_USERNAME, USER_PASSWORD_1_CLEAR); + assertDummyPasswordConditional(RESOURCE_DUMMY_YELLOW_NAME, ACCOUNT_JACK_DUMMY_USERNAME, USER_PASSWORD_1_CLEAR); // Check account in dummy resource (red) assertDummyAccount(RESOURCE_DUMMY_RED_NAME, ACCOUNT_JACK_DUMMY_USERNAME, ACCOUNT_JACK_DUMMY_FULLNAME, true); assertDummyPassword(RESOURCE_DUMMY_RED_NAME, ACCOUNT_JACK_DUMMY_USERNAME, USER_PASSWORD_A_CLEAR); // User and default dummy account should have unchanged passwords - assertUserPassword(userJack, USER_PASSWORD_A_CLEAR); + assertUserPassword(userAfter, USER_PASSWORD_A_CLEAR); assertDummyPassword(ACCOUNT_JACK_DUMMY_USERNAME, USER_PASSWORD_A_CLEAR); // this one is not changed assertDummyPassword(RESOURCE_DUMMY_UGLY_NAME, ACCOUNT_JACK_DUMMY_USERNAME, USER_JACK_EMPLOYEE_NUMBER_NEW_GOOD); - assertPasswordHistoryEntries(userJack); + assertPasswordHistoryEntries(userAfter); } /** diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordDefaultHashing.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordDefaultHashing.java index 79af8155586..e1d7993f8b8 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordDefaultHashing.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordDefaultHashing.java @@ -49,6 +49,6 @@ protected String getSecurityPolicyOid() { @Override protected CredentialsStorageTypeType getPasswordStorageType() { return CredentialsStorageTypeType.HASHING; - } + } } diff --git a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordNone.java b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordNone.java index 9263924396a..0173cf133ba 100644 --- a/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordNone.java +++ b/model/model-intest/src/test/java/com/evolveum/midpoint/model/intest/password/TestPasswordNone.java @@ -29,6 +29,12 @@ /** * Password test with NONE password storage (default storage for other types) * + * This test is only partially working. + * IT IS NOT PART OF THE TEST SUITE. It is NOT executed automatically. + * + * E.g. new password will be generated on every recompute because the + * weak inbound mapping is activated. + * * @author semancik * */ @@ -50,5 +56,4 @@ protected String getSecurityPolicyOid() { protected CredentialsStorageTypeType getPasswordStorageType() { return CredentialsStorageTypeType.NONE; } - } diff --git a/model/model-intest/src/test/resources/logback-test.xml b/model/model-intest/src/test/resources/logback-test.xml index 6e74a791037..13228f205c1 100644 --- a/model/model-intest/src/test/resources/logback-test.xml +++ b/model/model-intest/src/test/resources/logback-test.xml @@ -46,7 +46,7 @@ if any of the following is set to "TRACE" then it was changed by mistake and should be changed back --> - + diff --git a/model/model-intest/testng-integration.xml b/model/model-intest/testng-integration.xml index f733ac50372..f4545204b2c 100644 --- a/model/model-intest/testng-integration.xml +++ b/model/model-intest/testng-integration.xml @@ -95,7 +95,8 @@ - + +