diff --git a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/ElytronMessages.java b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/ElytronMessages.java index b6a4adc3b20..38fd26b646e 100644 --- a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/ElytronMessages.java +++ b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/ElytronMessages.java @@ -146,4 +146,13 @@ interface ElytronMessages extends BasicLogger { @LogMessage(level = Logger.Level.DEBUG) @Message(id = 13004, value = "JAAS logout failed for principal %s") void debugInfoJaasLogoutFailure(Principal principal, @Cause Throwable cause); + + @Message(id = 13005, value = "Filesystem-backed realm unable to decrypt identity") + RealmUnavailableException fileSystemRealmDecryptionFailed(@Cause Throwable cause); + + @Message(id = 13006, value = "Filesystem-backed realm unable to encrypt identity") + RealmUnavailableException fileSystemRealmEncryptionFailed(@Cause Throwable cause); + + @Message(id = 13007, value = "Filesystem-backed realm found an incompatible identity version. Requires at least version: %s") + RealmUnavailableException fileSystemRealmIncompatibleIdentityVersion(String expectedVersion); } diff --git a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealm.java b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealm.java index 55bf9464c8c..16e55db8ad7 100644 --- a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealm.java +++ b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealm.java @@ -48,6 +48,7 @@ import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.security.Provider; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -533,7 +534,7 @@ static class Identity implements ModifiableRealmIdentity { this.lock = lock; this.hashCharset = hashCharset; this.hashEncoding = hashEncoding; - this.providers = providers != null ? providers : INSTALLED_PROVIDERS; + this.providers = providers; this.secretKey = secretKey; } @@ -738,7 +739,7 @@ public void setCredentials(final Collection credentials) t throw ElytronMessages.log.fileSystemRealmNotFound(name); } - final LoadedIdentity newIdentity = new LoadedIdentity(name, new ArrayList<>(credentials), loadedIdentity.getAttributes(), hashEncoding, providers); + final LoadedIdentity newIdentity = new LoadedIdentity(name, new ArrayList<>(credentials), loadedIdentity.getAttributes(), hashEncoding); replaceIdentity(newIdentity); } @@ -748,7 +749,7 @@ public void setAttributes(final Attributes attributes) throws RealmUnavailableEx if (loadedIdentity == null) { throw ElytronMessages.log.fileSystemRealmNotFound(name); } - final LoadedIdentity newIdentity = new LoadedIdentity(name, loadedIdentity.getCredentials(), attributes, hashEncoding, providers); + final LoadedIdentity newIdentity = new LoadedIdentity(name, loadedIdentity.getCredentials(), attributes, hashEncoding); replaceIdentity(newIdentity); } @@ -784,8 +785,10 @@ private Void replaceIdentityPrivileged(final LoadedIdentity newIdentity) throws try (OutputStream outputStream = new BufferedOutputStream(Files.newOutputStream(tempPath, WRITE, CREATE_NEW, DSYNC))) { try (AutoCloseableXMLStreamWriterHolder holder = new AutoCloseableXMLStreamWriterHolder(xmlOutputFactory.createXMLStreamWriter(outputStream))) { writeIdentity(holder.getXmlStreamWriter(), newIdentity); - } catch (XMLStreamException | GeneralSecurityException e) { + } catch (XMLStreamException | InvalidKeySpecException | NoSuchAlgorithmException | CertificateEncodingException e) { throw ElytronMessages.log.fileSystemRealmFailedToWrite(tempPath, name, e); + } catch (GeneralSecurityException e) { + throw ElytronMessages.log.fileSystemRealmEncryptionFailed(e); } } catch (FileAlreadyExistsException ignored) { // try a new name @@ -837,7 +840,6 @@ private Version requiredVersion(final LoadedIdentity identityToWrite) { // if new functionality is used then use the required schema version otherwise fallback // to an older version. - // Do we require version 1.1? if (secretKey != null) { return Version.VERSION_1_1; } @@ -1001,7 +1003,7 @@ private LoadedIdentity parseIdentityContents(final XMLStreamReader streamReader, //modifiable version of Attributes; attributes = new MapAttributes(); } - return new LoadedIdentity(name, credentials, attributes, hashEncoding, providers); + return new LoadedIdentity(name, credentials, attributes, hashEncoding); } if (! version.getNamespace().equals(streamReader.getNamespaceURI())) { // Mixed versions unsupported. @@ -1041,7 +1043,7 @@ private List parseCredentials(final XMLStreamReader streamReader, fi throw ElytronMessages.log.fileSystemRealmInvalidContent(path, streamReader.getLocation().getLineNumber(), name); } if ("password".equals(streamReader.getLocalName())) { - parsePassword(credentials, streamReader); + parsePassword(credentials, streamReader, version); } else if ("public-key".equals(streamReader.getLocalName())) { parsePublicKey(credentials, streamReader); } else if ("certificate".equals(streamReader.getLocalName())) { @@ -1115,16 +1117,24 @@ private void parsePublicKey(final List credentials, final XMLStreamR }); } - private void parsePassword(final List credentials, final XMLStreamReader streamReader) throws XMLStreamException, RealmUnavailableException { + private void parsePassword(final List credentials, final XMLStreamReader streamReader, final Version version) throws XMLStreamException, RealmUnavailableException { parseCredential(streamReader, (algorithm, format, text) -> { try { if (ENCRYPTION_FORMAT.equals(format)) { + if (! version.isAtLeast(Version.VERSION_1_1)) { + throw ElytronMessages.log.fileSystemRealmInvalidContent(path, streamReader.getLocation().getLineNumber(), name); + } if (algorithm == null) { throw ElytronMessages.log.fileSystemRealmMissingAttribute("algorithm", path, streamReader.getLocation().getLineNumber(), name); } PasswordFactory passwordFactory = PasswordFactory.getInstance(algorithm, providers); byte[] encryptedPasswordBytes = CodePointIterator.ofChars(text.toCharArray()).base64Decode().drain(); - byte[] decryptedPasswordBytes = CipherUtil.decrypt(encryptedPasswordBytes, secretKey); + byte[] decryptedPasswordBytes; + try { + decryptedPasswordBytes = CipherUtil.decrypt(encryptedPasswordBytes, secretKey); + } catch (GeneralSecurityException e) { + throw ElytronMessages.log.fileSystemRealmDecryptionFailed(e); + } PasswordSpec passwordSpec = BasicPasswordSpecEncoding.decode(decryptedPasswordBytes); if (passwordSpec != null) { @@ -1155,7 +1165,7 @@ private void parsePassword(final List credentials, final XMLStreamRe } else { throw ElytronMessages.log.fileSystemRealmInvalidPasswordFormat(format, path, streamReader.getLocation().getLineNumber(), name); } - } catch (GeneralSecurityException e) { + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { throw ElytronMessages.log.fileSystemRealmInvalidContent(path, streamReader.getLocation().getLineNumber(), name); } }); @@ -1256,14 +1266,14 @@ private void parseAttribute(final XMLStreamReader streamReader, final Attributes if (value == null) { throw ElytronMessages.log.fileSystemRealmMissingAttribute("value", path, streamReader.getLocation().getLineNumber(), this.name); } - try { - if (secretKey != null) { + if (secretKey != null) { + try { attributes.addLast(CipherUtil.decrypt(name, secretKey), CipherUtil.decrypt(value, secretKey)); - } else { - attributes.addLast(name, value); + } catch (GeneralSecurityException e){ + throw ElytronMessages.log.fileSystemRealmDecryptionFailed(e); } - } catch (GeneralSecurityException e) { - throw ElytronMessages.log.fileSystemRealmInvalidContent(path, streamReader.getLocation().getLineNumber(), this.name); + } else { + attributes.addLast(name, value); } if (streamReader.nextTag() != END_ELEMENT) { throw ElytronMessages.log.fileSystemRealmInvalidContent(path, streamReader.getLocation().getLineNumber(), this.name); @@ -1291,14 +1301,12 @@ protected static final class LoadedIdentity { private final List credentials; private final Attributes attributes; private final Encoding hashEncoding; - private final Supplier providers; - LoadedIdentity(final String name, final List credentials, final Attributes attributes, final Encoding hashEncoding, final Supplier providers) { + LoadedIdentity(final String name, final List credentials, final Attributes attributes, final Encoding hashEncoding) { this.name = name; this.credentials = credentials; this.attributes = attributes; this.hashEncoding = hashEncoding; - this.providers = providers; } public String getName() { @@ -1317,10 +1325,6 @@ public Encoding getHashEncoding() { return hashEncoding; } - public Supplier getProviders() { - return providers; - } - } static class AutoCloseableXMLStreamReaderHolder implements AutoCloseable { diff --git a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealmBuilder.java b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealmBuilder.java index 87ef30ed326..b0839aad96e 100644 --- a/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealmBuilder.java +++ b/auth/realm/base/src/main/java/org/wildfly/security/auth/realm/FileSystemSecurityRealmBuilder.java @@ -80,6 +80,7 @@ public FileSystemSecurityRealmBuilder setNameRewriter(final NameRewriter nameRew * @return this builder. */ public FileSystemSecurityRealmBuilder setLevels(final int levels) { + Assert.checkMinimumParameter("levels", 0, levels); this.levels = levels; return this; } diff --git a/tests/base/src/test/java/org/wildfly/security/auth/FileSystemSecurityRealmTest.java b/tests/base/src/test/java/org/wildfly/security/auth/FileSystemSecurityRealmTest.java index 90678f264a4..067d3aeab7c 100644 --- a/tests/base/src/test/java/org/wildfly/security/auth/FileSystemSecurityRealmTest.java +++ b/tests/base/src/test/java/org/wildfly/security/auth/FileSystemSecurityRealmTest.java @@ -36,8 +36,6 @@ import java.nio.file.SimpleFileVisitor; import java.nio.file.attribute.BasicFileAttributes; import java.security.GeneralSecurityException; -import java.security.Provider; -import java.security.Security; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -45,9 +43,8 @@ import java.util.List; import java.util.concurrent.ThreadLocalRandom; import javax.crypto.SecretKey; -import org.junit.AfterClass; +import javax.crypto.spec.SecretKeySpec; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; import org.wildfly.common.iteration.CodePointIterator; import org.wildfly.security.auth.principal.NamePrincipal; @@ -55,7 +52,6 @@ import org.wildfly.security.auth.server.ModifiableRealmIdentity; import org.wildfly.security.auth.server.ModifiableRealmIdentityIterator; import org.wildfly.security.auth.server.NameRewriter; -import org.wildfly.security.auth.server.RealmUnavailableException; import org.wildfly.security.authz.Attributes; import org.wildfly.security.authz.AuthorizationIdentity; import org.wildfly.security.authz.MapAttributes; @@ -65,7 +61,6 @@ import org.wildfly.security.evidence.PasswordGuessEvidence; import org.wildfly.security.password.Password; import org.wildfly.security.password.PasswordFactory; -import org.wildfly.security.password.WildFlyElytronPasswordProvider; import org.wildfly.security.password.interfaces.BCryptPassword; import org.wildfly.security.password.interfaces.ClearPassword; import org.wildfly.security.password.interfaces.DigestPassword; @@ -80,6 +75,7 @@ import org.wildfly.security.password.spec.IteratedSaltedPasswordAlgorithmSpec; import org.wildfly.security.password.spec.OneTimePasswordSpec; import org.wildfly.security.password.spec.SaltedPasswordAlgorithmSpec; +import org.xipki.common.util.Base64; /** * @author Pedro Igor @@ -87,21 +83,12 @@ // has dependency on wildfly-elytron-realm, wildfly-elytron-auth-server, wildfly-elytron-credential public class FileSystemSecurityRealmTest { - private static final Provider provider = WildFlyElytronPasswordProvider.getInstance(); +// private static final Provider provider = WildFlyElytronPasswordProvider.getInstance(); public FileSystemSecurityRealmTest() throws GeneralSecurityException { } - @BeforeClass - public static void onBefore() throws Exception { - Security.addProvider(provider); - } - - @AfterClass - public static void onAfter() throws Exception { - Security.removeProvider(provider.getName()); - } - SecretKey key = SecretKeyUtil.generateSecretKey(128); + private final SecretKey key = SecretKeyUtil.generateSecretKey(128); @Test public void testCreateIdentityWithNoLevels() throws Exception { @@ -130,9 +117,10 @@ public void testCreateIdentityWithLevels() throws Exception { @Test public void testCreateIdentityWithLevelsEncryption() throws Exception { FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder() - .setRoot(getRootPath(false)) + .setRoot(getRootPath()) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity identity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertFalse(identity.exists()); @@ -161,6 +149,7 @@ public void testCreateAndLoadIdentityEncryption() throws Exception { .setRoot(getRootPath()) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -170,6 +159,7 @@ public void testCreateAndLoadIdentityEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertTrue(existingIdentity.exists()); @@ -191,7 +181,12 @@ public void testShortUsername() throws Exception { @Test public void testShortUsernameEncryption() throws Exception { - FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder().setRoot(getRootPath()).setLevels(3).setSecretKey(key).build(); + FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder() + .setRoot(getRootPath()) + .setLevels(3) + .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) + .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("p")); newIdentity.create(); @@ -233,6 +228,7 @@ public void testCaseSensitiveEncryption() throws Exception { .setRoot(getRootPath()) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -270,6 +266,7 @@ public void testCreateAndLoadAndDeleteIdentityEncryption() throws Exception { .setRoot(getRootPath()) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -279,6 +276,7 @@ public void testCreateAndLoadAndDeleteIdentityEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertTrue(existingIdentity.exists()); @@ -290,6 +288,7 @@ public void testCreateAndLoadAndDeleteIdentityEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(3) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertFalse(existingIdentity.exists()); @@ -329,6 +328,7 @@ public void testCreateIdentityWithAttributesEncryption() throws Exception { .setRoot(getRootPath()) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); @@ -346,6 +346,7 @@ public void testCreateIdentityWithAttributesEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); @@ -370,7 +371,7 @@ public void testCreateIdentityWithClearPassword() throws Exception { @Test public void testCreateIdentityWithClearPasswordEncryption() throws Exception { char[] actualPassword = "secretPassword".toCharArray(); - PasswordFactory factory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR); + PasswordFactory factory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR, ELYTRON_PASSWORD_PROVIDERS); ClearPassword clearPassword = (ClearPassword) factory.generatePassword(new ClearPasswordSpec(actualPassword)); assertCreateIdentityWithPassword(actualPassword, clearPassword, key); @@ -389,7 +390,7 @@ public void testCreateIdentityWithBcryptCredential() throws Exception { @Test public void testCreateIdentityWithBcryptCredentialEncryption() throws Exception { - PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT); + PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, ELYTRON_PASSWORD_PROVIDERS); char[] actualPassword = "secretPassword".toCharArray(); BCryptPassword bCryptPassword = (BCryptPassword) passwordFactory.generatePassword( new EncryptablePasswordSpec(actualPassword, new IteratedSaltedPasswordAlgorithmSpec(10, generateRandomSalt(BCRYPT_SALT_SIZE))) @@ -410,7 +411,7 @@ public void testCreateIdentityWithBcryptCredentialHexEncoded() throws Exception @Test public void testCreateIdentityWithBcryptCredentialHexEncodedEncryption() throws Exception { - PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT); + PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, ELYTRON_PASSWORD_PROVIDERS); char[] actualPassword = "secretPassword".toCharArray(); BCryptPassword bCryptPassword = (BCryptPassword) passwordFactory.generatePassword( new EncryptablePasswordSpec(actualPassword, new IteratedSaltedPasswordAlgorithmSpec(10, generateRandomSalt(BCRYPT_SALT_SIZE)))); @@ -431,7 +432,7 @@ public void testCreateIdentityWithBcryptCredentialBase64AndCharset() throws Exce @Test public void testCreateIdentityWithBcryptCredentialBase64AndCharsetEncryption() throws Exception { - PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT); + PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, ELYTRON_PASSWORD_PROVIDERS); char[] actualPassword = "password密码".toCharArray(); BCryptPassword bCryptPassword = (BCryptPassword) passwordFactory.generatePassword( new EncryptablePasswordSpec(actualPassword, new IteratedSaltedPasswordAlgorithmSpec(10, generateRandomSalt(BCRYPT_SALT_SIZE)), @@ -466,7 +467,7 @@ public void testCreateIdentityWithScramCredential() throws Exception { public void testCreateIdentityWithScramCredentialEncryption() throws Exception { char[] actualPassword = "secretPassword".toCharArray(); byte[] salt = generateRandomSalt(BCRYPT_SALT_SIZE); - PasswordFactory factory = PasswordFactory.getInstance(ScramDigestPassword.ALGORITHM_SCRAM_SHA_256); + PasswordFactory factory = PasswordFactory.getInstance(ScramDigestPassword.ALGORITHM_SCRAM_SHA_256, ELYTRON_PASSWORD_PROVIDERS); EncryptablePasswordSpec encSpec = new EncryptablePasswordSpec(actualPassword, new IteratedSaltedPasswordAlgorithmSpec(4096, salt)); ScramDigestPassword scramPassword = (ScramDigestPassword) factory.generatePassword(encSpec); @@ -510,7 +511,7 @@ public void testCreateIdentityWithDigest() throws Exception { @Test public void testCreateIdentityWithDigestEncryption() throws Exception { char[] actualPassword = "secretPassword".toCharArray(); - PasswordFactory factory = PasswordFactory.getInstance(DigestPassword.ALGORITHM_DIGEST_SHA_512); + PasswordFactory factory = PasswordFactory.getInstance(DigestPassword.ALGORITHM_DIGEST_SHA_512, ELYTRON_PASSWORD_PROVIDERS); DigestPasswordAlgorithmSpec dpas = new DigestPasswordAlgorithmSpec("jsmith", "elytron"); EncryptablePasswordSpec encryptableSpec = new EncryptablePasswordSpec(actualPassword, dpas); DigestPassword digestPassword = (DigestPassword) factory.generatePassword(encryptableSpec); @@ -543,7 +544,7 @@ public void testCreateIdentityWithDigestHexEncodedAndCharset() throws Exception @Test public void testCreateIdentityWithDigestHexEncodedAndCharsetEncryption() throws Exception { char[] actualPassword = "secretPassword".toCharArray(); - PasswordFactory factory = PasswordFactory.getInstance(DigestPassword.ALGORITHM_DIGEST_SHA_512); + PasswordFactory factory = PasswordFactory.getInstance(DigestPassword.ALGORITHM_DIGEST_SHA_512, ELYTRON_PASSWORD_PROVIDERS); DigestPasswordAlgorithmSpec dpas = new DigestPasswordAlgorithmSpec("jsmith", "elytron"); EncryptablePasswordSpec encryptableSpec = new EncryptablePasswordSpec(actualPassword, dpas); DigestPassword digestPassword = (DigestPassword) factory.generatePassword(encryptableSpec); @@ -623,7 +624,7 @@ public void testCreateIdentityWithSimpleSaltedDigestHexEncodedAndCharsetEncrypti byte[] salt = generateRandomSalt(BCRYPT_SALT_SIZE); SaltedPasswordAlgorithmSpec spac = new SaltedPasswordAlgorithmSpec(salt); EncryptablePasswordSpec eps = new EncryptablePasswordSpec(actualPassword, spac, Charset.forName("gb2312")); - PasswordFactory passwordFactory = PasswordFactory.getInstance(SaltedSimpleDigestPassword.ALGORITHM_PASSWORD_SALT_DIGEST_SHA_512); + PasswordFactory passwordFactory = PasswordFactory.getInstance(SaltedSimpleDigestPassword.ALGORITHM_PASSWORD_SALT_DIGEST_SHA_512, ELYTRON_PASSWORD_PROVIDERS); SaltedSimpleDigestPassword tsdp = (SaltedSimpleDigestPassword) passwordFactory.generatePassword(eps); assertCreateIdentityWithPassword(actualPassword, tsdp, Encoding.HEX, Charset.forName("gb2312"), key); @@ -686,12 +687,41 @@ public void testCreateIdentityWithEverything() throws Exception { assertTrue(newAttributes.get("roles").containsAll(existingAttributes.get("roles"))); } + @Test + public void testVerifyCredentialsPreExistingIdentity() throws Exception { + byte[] aesByte = Base64.decode("3fMEsUHKCn3GZQXcHCyuhQ=="); + SecretKey staticKey = new SecretKeySpec(aesByte, "AES"); + FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder() + .setRoot(Paths.get("./target/test-classes/filesystem-realm-exists/")) + .setLevels(1) + .setHashEncoding(Encoding.BASE64) + .setHashCharset(Charset.defaultCharset()) + .setSecretKey(staticKey) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) + .build(); + ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); + assertTrue(existingIdentity.exists()); + assertTrue(existingIdentity.verifyEvidence(new PasswordGuessEvidence("secretPassword".toCharArray()))); + + Attributes identityAttributes = existingIdentity.getAttributes(); + MapAttributes newAttributes = new MapAttributes(); + newAttributes.addFirst("firstName", "John"); + newAttributes.addFirst("lastName", "Smith"); + newAttributes.addAll("roles", Arrays.asList("Employee", "Manager", "Admin")); + assertEquals(newAttributes.size(), identityAttributes.size()); + assertTrue(newAttributes.get("firstName").containsAll(identityAttributes.get("firstName"))); + assertTrue(newAttributes.get("lastName").containsAll(identityAttributes.get("lastName"))); + assertTrue(newAttributes.get("roles").containsAll(identityAttributes.get("roles"))); + existingIdentity.dispose(); + } + @Test public void testCreateIdentityWithEverythingEncryption() throws Exception { FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder() .setRoot(getRootPath()) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); @@ -707,7 +737,7 @@ public void testCreateIdentityWithEverythingEncryption() throws Exception { List credentials = new ArrayList<>(); - PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT); + PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, ELYTRON_PASSWORD_PROVIDERS); BCryptPassword bCryptPassword = (BCryptPassword) passwordFactory.generatePassword( new EncryptablePasswordSpec("secretPassword".toCharArray(), new IteratedSaltedPasswordAlgorithmSpec(10, generateRandomSalt(BCRYPT_SALT_SIZE))) ); @@ -716,7 +746,7 @@ public void testCreateIdentityWithEverythingEncryption() throws Exception { byte[] hash = CodePointIterator.ofString("505d889f90085847").hexDecode().drain(); String seed = "ke1234"; - PasswordFactory otpFactory = PasswordFactory.getInstance(OneTimePassword.ALGORITHM_OTP_SHA1); + PasswordFactory otpFactory = PasswordFactory.getInstance(OneTimePassword.ALGORITHM_OTP_SHA1, ELYTRON_PASSWORD_PROVIDERS); OneTimePassword otpPassword = (OneTimePassword) otpFactory.generatePassword( new OneTimePasswordSpec(hash, seed, 500) ); @@ -729,6 +759,7 @@ public void testCreateIdentityWithEverythingEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertTrue(existingIdentity.exists()); @@ -791,13 +822,14 @@ public void testCredentialReplacingEncryption() throws Exception { .setRoot(getRootPath()) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity identity1 = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("testingUser")); identity1.create(); List credentials = new ArrayList<>(); - PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT); + PasswordFactory passwordFactory = PasswordFactory.getInstance(BCryptPassword.ALGORITHM_BCRYPT, ELYTRON_PASSWORD_PROVIDERS); BCryptPassword bCryptPassword = (BCryptPassword) passwordFactory.generatePassword( new EncryptablePasswordSpec("secretPassword".toCharArray(), new IteratedSaltedPasswordAlgorithmSpec(10, generateRandomSalt(BCRYPT_SALT_SIZE))) ); @@ -805,7 +837,7 @@ public void testCredentialReplacingEncryption() throws Exception { byte[] hash = CodePointIterator.ofString("505d889f90085847").hexDecode().drain(); String seed = "ke1234"; - PasswordFactory otpFactory = PasswordFactory.getInstance(OneTimePassword.ALGORITHM_OTP_SHA1); + PasswordFactory otpFactory = PasswordFactory.getInstance(OneTimePassword.ALGORITHM_OTP_SHA1, ELYTRON_PASSWORD_PROVIDERS); OneTimePassword otpPassword = (OneTimePassword) otpFactory.generatePassword( new OneTimePasswordSpec(hash, seed, 500) ); @@ -819,6 +851,7 @@ public void testCredentialReplacingEncryption() throws Exception { .setRoot(getRootPath(false)) .setLevels(1) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity identity3 = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("testingUser")); @@ -843,6 +876,7 @@ private FileSystemSecurityRealm createRealmWithTwoIdentities(SecretKey secretKey .setRoot(getRootPath()) .setLevels(1) .setSecretKey(secretKey) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity identity1 = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("firstUser")); identity1.create(); @@ -919,15 +953,16 @@ public void testPartialIteratingTryWithResource() throws Exception { getRootPath(); // will fail on windows if iterator not closed correctly } - @Test(expected = RealmUnavailableException.class) + @Test public void testMismatchSecretKey() throws Exception { char[] actualPassword = "secretPassword".toCharArray(); - PasswordFactory factory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR); + PasswordFactory factory = PasswordFactory.getInstance(ClearPassword.ALGORITHM_CLEAR, ELYTRON_PASSWORD_PROVIDERS); ClearPassword clearPassword = (ClearPassword) factory.generatePassword(new ClearPasswordSpec(actualPassword)); FileSystemSecurityRealm securityRealm = FileSystemSecurityRealm.builder() .setRoot(getRootPath()) .setLevels(2) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -936,9 +971,14 @@ public void testMismatchSecretKey() throws Exception { .setRoot(getRootPath(false)) .setLevels(2) .setSecretKey(SecretKeyUtil.generateSecretKey(192)) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); - existingIdentity.verifyEvidence(new PasswordGuessEvidence(actualPassword)); + try { + existingIdentity.verifyEvidence(new PasswordGuessEvidence(actualPassword)); + } catch (Exception e) { + assertTrue(e.getCause().getMessage().contains("unable to decrypt identity")); + } existingIdentity.dispose(); } @@ -949,6 +989,7 @@ public void encodedIfNotEncrypted() throws Exception { .setRoot(getRootPath()) .setLevels(0) .setEncoded(true) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -959,6 +1000,7 @@ public void encodedIfNotEncrypted() throws Exception { .setLevels(0) .setEncoded(true) .setSecretKey(key) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -994,6 +1036,7 @@ private void assertCreateIdentityWithPassword(char[] actualPassword, Password cr .setHashEncoding(hashEncoding) .setHashCharset(hashCharset) .setSecretKey(secretKey) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity newIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); newIdentity.create(); @@ -1006,6 +1049,7 @@ private void assertCreateIdentityWithPassword(char[] actualPassword, Password cr .setHashEncoding(hashEncoding) .setHashCharset(hashCharset) .setSecretKey(secretKey) + .setProviders(ELYTRON_PASSWORD_PROVIDERS) .build(); ModifiableRealmIdentity existingIdentity = securityRealm.getRealmIdentityForUpdate(new NamePrincipal("plainUser")); assertTrue(existingIdentity.exists()); diff --git a/tests/base/src/test/resources/filesystem-realm-exists/O/OBWGC2LOKVZWK4Q.xml b/tests/base/src/test/resources/filesystem-realm-exists/O/OBWGC2LOKVZWK4Q.xml new file mode 100644 index 00000000000..e090a21963c --- /dev/null +++ b/tests/base/src/test/resources/filesystem-realm-exists/O/OBWGC2LOKVZWK4Q.xml @@ -0,0 +1,13 @@ + + + + RUxZAUMQRPYts0Gi2Q6araZKf827kci9VHQGuFP9oKwFEWL8qZ6WuumKy22bUXuCkTk1yTs28FRS7LchPwVznTTmiCm6pg== + + + + + + + + + \ No newline at end of file