[KEYCLOAK-16232] Streamify the UserCredentialStore and UserCredentialManager interfaces
This commit is contained in:
parent
73d0bb34c4
commit
edef93cd49
43 changed files with 447 additions and 303 deletions
|
@ -75,7 +75,7 @@ public class SecretQuestionCredentialProvider implements CredentialProvider<Secr
|
||||||
@Override
|
@Override
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
||||||
if (!supportsCredentialType(credentialType)) return false;
|
if (!supportsCredentialType(credentialType)) return false;
|
||||||
return !getCredentialStore().getStoredCredentialsByType(realm, user, credentialType).isEmpty();
|
return getCredentialStore().getStoredCredentialsByTypeStream(realm, user, credentialType).count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.credential.CredentialAuthentication;
|
||||||
import org.keycloak.credential.CredentialInput;
|
import org.keycloak.credential.CredentialInput;
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
import org.keycloak.credential.CredentialInputUpdater;
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
import org.keycloak.credential.CredentialInputValidator;
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
import org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator;
|
||||||
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
|
import org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator;
|
||||||
import org.keycloak.models.CredentialValidationOutput;
|
import org.keycloak.models.CredentialValidationOutput;
|
||||||
|
@ -41,10 +40,9 @@ import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.user.ImportedUserValidation;
|
import org.keycloak.storage.user.ImportedUserValidation;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
|
@ -52,7 +50,7 @@ import java.util.Set;
|
||||||
public class KerberosFederationProvider implements UserStorageProvider,
|
public class KerberosFederationProvider implements UserStorageProvider,
|
||||||
UserLookupProvider,
|
UserLookupProvider,
|
||||||
CredentialInputValidator,
|
CredentialInputValidator,
|
||||||
CredentialInputUpdater,
|
CredentialInputUpdater.Streams,
|
||||||
CredentialAuthentication,
|
CredentialAuthentication,
|
||||||
ImportedUserValidation {
|
ImportedUserValidation {
|
||||||
|
|
||||||
|
@ -146,8 +144,8 @@ public class KerberosFederationProvider implements UserStorageProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
package org.keycloak.storage.ldap;
|
package org.keycloak.storage.ldap;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -88,7 +87,7 @@ import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
*/
|
*/
|
||||||
public class LDAPStorageProvider implements UserStorageProvider,
|
public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
CredentialInputValidator,
|
CredentialInputValidator,
|
||||||
CredentialInputUpdater,
|
CredentialInputUpdater.Streams,
|
||||||
CredentialAuthentication,
|
CredentialAuthentication,
|
||||||
UserLookupProvider,
|
UserLookupProvider,
|
||||||
UserRegistrationProvider,
|
UserRegistrationProvider,
|
||||||
|
@ -687,8 +686,8 @@ public class LDAPStorageProvider implements UserStorageProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getSupportedCredentialTypes() {
|
public Set<String> getSupportedCredentialTypes() {
|
||||||
|
|
|
@ -21,7 +21,6 @@ import org.jboss.logging.Logger;
|
||||||
import org.keycloak.credential.CredentialInput;
|
import org.keycloak.credential.CredentialInput;
|
||||||
import org.keycloak.credential.CredentialInputUpdater;
|
import org.keycloak.credential.CredentialInputUpdater;
|
||||||
import org.keycloak.credential.CredentialInputValidator;
|
import org.keycloak.credential.CredentialInputValidator;
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.federation.sssd.api.Sssd;
|
import org.keycloak.federation.sssd.api.Sssd;
|
||||||
import org.keycloak.federation.sssd.api.Sssd.User;
|
import org.keycloak.federation.sssd.api.Sssd.User;
|
||||||
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
|
import org.keycloak.federation.sssd.impl.PAMAuthenticator;
|
||||||
|
@ -32,11 +31,10 @@ import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.user.ImportedUserValidation;
|
import org.keycloak.storage.user.ImportedUserValidation;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import sun.security.util.Password;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SPI provider implementation to retrieve data from SSSD and authenticate
|
* SPI provider implementation to retrieve data from SSSD and authenticate
|
||||||
|
@ -47,7 +45,7 @@ import java.util.Set;
|
||||||
*/
|
*/
|
||||||
public class SSSDFederationProvider implements UserStorageProvider,
|
public class SSSDFederationProvider implements UserStorageProvider,
|
||||||
UserLookupProvider,
|
UserLookupProvider,
|
||||||
CredentialInputUpdater,
|
CredentialInputUpdater.Streams,
|
||||||
CredentialInputValidator,
|
CredentialInputValidator,
|
||||||
ImportedUserValidation {
|
ImportedUserValidation {
|
||||||
|
|
||||||
|
@ -205,7 +203,7 @@ public class SSSDFederationProvider implements UserStorageProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,16 +30,20 @@ import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class JpaUserCredentialStore implements UserCredentialStore {
|
public class JpaUserCredentialStore implements UserCredentialStore.Streams {
|
||||||
|
|
||||||
// Typical priority difference between 2 credentials
|
// Typical priority difference between 2 credentials
|
||||||
public static final int PRIORITY_DIFFERENCE = 10;
|
public static final int PRIORITY_DIFFERENCE = 10;
|
||||||
|
@ -106,31 +110,27 @@ public class JpaUserCredentialStore implements UserCredentialStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
|
public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||||
List<CredentialEntity> results = getStoredCredentialEntities(realm, user);
|
return this.getStoredCredentialEntities(realm, user).map(this::toModel);
|
||||||
|
|
||||||
// list is ordered correctly by priority (lowest priority value first)
|
|
||||||
return results.stream().map(this::toModel).collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CredentialEntity> getStoredCredentialEntities(RealmModel realm, UserModel user) {
|
private Stream<CredentialEntity> getStoredCredentialEntities(RealmModel realm, UserModel user) {
|
||||||
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
|
UserEntity userEntity = em.getReference(UserEntity.class, user.getId());
|
||||||
TypedQuery<CredentialEntity> query = em.createNamedQuery("credentialByUser", CredentialEntity.class)
|
TypedQuery<CredentialEntity> query = em.createNamedQuery("credentialByUser", CredentialEntity.class)
|
||||||
.setParameter("user", userEntity);
|
.setParameter("user", userEntity);
|
||||||
return query.getResultList();
|
return closing(query.getResultStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
|
public Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
|
||||||
return getStoredCredentials(realm, user).stream().filter(credential -> type.equals(credential.getType())).collect(Collectors.toList());
|
return getStoredCredentialsStream(realm, user).filter(credential -> Objects.equals(type, credential.getType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
|
public CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type) {
|
||||||
List<CredentialModel> results = getStoredCredentials(realm, user).stream().filter(credential ->
|
return getStoredCredentialsStream(realm, user).filter(credential ->
|
||||||
type.equals(credential.getType()) && name.equals(credential.getUserLabel())).collect(Collectors.toList());
|
Objects.equals(type, credential.getType()) && Objects.equals(name, credential.getUserLabel()))
|
||||||
if (results.isEmpty()) return null;
|
.findFirst().orElse(null);
|
||||||
return results.get(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -151,7 +151,7 @@ public class JpaUserCredentialStore implements UserCredentialStore {
|
||||||
entity.setUser(userRef);
|
entity.setUser(userRef);
|
||||||
|
|
||||||
//add in linkedlist to last position
|
//add in linkedlist to last position
|
||||||
List<CredentialEntity> credentials = getStoredCredentialEntities(realm, user);
|
List<CredentialEntity> credentials = getStoredCredentialEntities(realm, user).collect(Collectors.toList());
|
||||||
int priority = credentials.isEmpty() ? PRIORITY_DIFFERENCE : credentials.get(credentials.size() - 1).getPriority() + PRIORITY_DIFFERENCE;
|
int priority = credentials.isEmpty() ? PRIORITY_DIFFERENCE : credentials.get(credentials.size() - 1).getPriority() + PRIORITY_DIFFERENCE;
|
||||||
entity.setPriority(priority);
|
entity.setPriority(priority);
|
||||||
|
|
||||||
|
@ -165,14 +165,11 @@ public class JpaUserCredentialStore implements UserCredentialStore {
|
||||||
|
|
||||||
int currentPriority = entity.getPriority();
|
int currentPriority = entity.getPriority();
|
||||||
|
|
||||||
List<CredentialEntity> credentials = getStoredCredentialEntities(realm, user);
|
this.getStoredCredentialEntities(realm, user).forEach(cred -> {
|
||||||
|
|
||||||
// Decrease priority of all credentials after our
|
|
||||||
for (CredentialEntity cred : credentials) {
|
|
||||||
if (cred.getPriority() > currentPriority) {
|
if (cred.getPriority() > currentPriority) {
|
||||||
cred.setPriority(cred.getPriority() - PRIORITY_DIFFERENCE);
|
cred.setPriority(cred.getPriority() - PRIORITY_DIFFERENCE);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
em.remove(entity);
|
em.remove(entity);
|
||||||
em.flush();
|
em.flush();
|
||||||
|
@ -182,11 +179,9 @@ public class JpaUserCredentialStore implements UserCredentialStore {
|
||||||
////Operations to handle the linked list of credentials
|
////Operations to handle the linked list of credentials
|
||||||
@Override
|
@Override
|
||||||
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) {
|
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) {
|
||||||
List<CredentialEntity> sortedCreds = getStoredCredentialEntities(realm, user);
|
|
||||||
|
|
||||||
// 1 - Create new list and move everything to it.
|
// 1 - Create new list and move everything to it.
|
||||||
List<CredentialEntity> newList = new ArrayList<>();
|
List<CredentialEntity> newList = this.getStoredCredentialEntities(realm, user).collect(Collectors.toList());
|
||||||
newList.addAll(sortedCreds);
|
|
||||||
|
|
||||||
// 2 - Find indexes of our and newPrevious credential
|
// 2 - Find indexes of our and newPrevious credential
|
||||||
int ourCredentialIndex = -1;
|
int ourCredentialIndex = -1;
|
||||||
|
|
|
@ -64,12 +64,10 @@ import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.persistence.LockModeType;
|
import javax.persistence.LockModeType;
|
||||||
|
@ -82,7 +80,7 @@ import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("JpaQueryApiInspection")
|
@SuppressWarnings("JpaQueryApiInspection")
|
||||||
public class JpaUserProvider implements UserProvider.Streams, UserCredentialStore {
|
public class JpaUserProvider implements UserProvider.Streams, UserCredentialStore.Streams {
|
||||||
|
|
||||||
private static final String EMAIL = "email";
|
private static final String EMAIL = "email";
|
||||||
private static final String EMAIL_VERIFIED = "emailVerified";
|
private static final String EMAIL_VERIFIED = "emailVerified";
|
||||||
|
@ -1022,27 +1020,20 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
|
public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||||
return credentialStore.getStoredCredentials(realm, user);
|
return credentialStore.getStoredCredentialsStream(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
|
public Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
|
||||||
List<CredentialEntity> results;
|
|
||||||
UserEntity userEntity = userInEntityManagerContext(user.getId());
|
UserEntity userEntity = userInEntityManagerContext(user.getId());
|
||||||
if (userEntity != null) {
|
if (userEntity != null) {
|
||||||
|
|
||||||
// user already in persistence context, no need to execute a query
|
// user already in persistence context, no need to execute a query
|
||||||
results = userEntity.getCredentials().stream().filter(it -> type.equals(it.getType()))
|
return userEntity.getCredentials().stream().filter(it -> type.equals(it.getType()))
|
||||||
.sorted(Comparator.comparingInt(CredentialEntity::getPriority))
|
.sorted(Comparator.comparingInt(CredentialEntity::getPriority))
|
||||||
.collect(Collectors.toList());
|
.map(this::toModel);
|
||||||
List<CredentialModel> rtn = new LinkedList<>();
|
|
||||||
for (CredentialEntity entity : results) {
|
|
||||||
rtn.add(toModel(entity));
|
|
||||||
}
|
|
||||||
return rtn;
|
|
||||||
} else {
|
} else {
|
||||||
return credentialStore.getStoredCredentialsByType(realm, user, type);
|
return credentialStore.getStoredCredentialsByTypeStream(realm, user, type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ import static org.keycloak.utils.StreamsUtil.closing;
|
||||||
*/
|
*/
|
||||||
public class JpaUserFederatedStorageProvider implements
|
public class JpaUserFederatedStorageProvider implements
|
||||||
UserFederatedStorageProvider.Streams,
|
UserFederatedStorageProvider.Streams,
|
||||||
UserCredentialStore {
|
UserCredentialStore.Streams {
|
||||||
|
|
||||||
protected static final Logger logger = Logger.getLogger(JpaUserFederatedStorageProvider.class);
|
protected static final Logger logger = Logger.getLogger(JpaUserFederatedStorageProvider.class);
|
||||||
|
|
||||||
|
@ -690,13 +690,13 @@ public class JpaUserFederatedStorageProvider implements
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
|
public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||||
return getStoredCredentialsStream(realm, user.getId()).collect(Collectors.toList());
|
return getStoredCredentialsStream(realm, user.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
|
public Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
|
||||||
return getStoredCredentialsByTypeStream(realm, user.getId(), type).collect(Collectors.toList());
|
return getStoredCredentialsByTypeStream(realm, user.getId(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -7,11 +7,13 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public interface CredentialValidator<T extends CredentialProvider> {
|
public interface CredentialValidator<T extends CredentialProvider> {
|
||||||
T getCredentialProvider(KeycloakSession session);
|
T getCredentialProvider(KeycloakSession session);
|
||||||
default List<CredentialModel> getCredentials(KeycloakSession session, RealmModel realm, UserModel user) {
|
default List<CredentialModel> getCredentials(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||||
return session.userCredentialManager().getStoredCredentialsByType(realm, user, getCredentialProvider(session).getType());
|
return session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, getCredentialProvider(session).getType())
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
default String getType(KeycloakSession session) {
|
default String getType(KeycloakSession session) {
|
||||||
return getCredentialProvider(session).getType();
|
return getCredentialProvider(session).getType();
|
||||||
|
|
|
@ -188,7 +188,8 @@ public class ModelToRepresentation {
|
||||||
rep.setEnabled(user.isEnabled());
|
rep.setEnabled(user.isEnabled());
|
||||||
rep.setEmailVerified(user.isEmailVerified());
|
rep.setEmailVerified(user.isEmailVerified());
|
||||||
rep.setTotp(session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE));
|
rep.setTotp(session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE));
|
||||||
rep.setDisableableCredentialTypes(session.userCredentialManager().getDisableableCredentialTypes(realm, user));
|
rep.setDisableableCredentialTypes(session.userCredentialManager()
|
||||||
|
.getDisableableCredentialTypesStream(realm, user).collect(Collectors.toSet()));
|
||||||
rep.setFederationLink(user.getFederationLink());
|
rep.setFederationLink(user.getFederationLink());
|
||||||
rep.setNotBefore(session.users().getNotBeforeOfUser(realm, user));
|
rep.setNotBefore(session.users().getNotBeforeOfUser(realm, user));
|
||||||
rep.setRequiredActions(user.getRequiredActionsStream().collect(Collectors.toList()));
|
rep.setRequiredActions(user.getRequiredActionsStream().collect(Collectors.toList()));
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.keycloak.models.credential.PasswordCredentialModel;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
|
@ -53,37 +54,36 @@ public class HistoryPasswordPolicyProvider implements PasswordPolicyProvider {
|
||||||
PasswordPolicy policy = session.getContext().getRealm().getPasswordPolicy();
|
PasswordPolicy policy = session.getContext().getRealm().getPasswordPolicy();
|
||||||
int passwordHistoryPolicyValue = policy.getPolicyConfig(PasswordPolicy.PASSWORD_HISTORY_ID);
|
int passwordHistoryPolicyValue = policy.getPolicyConfig(PasswordPolicy.PASSWORD_HISTORY_ID);
|
||||||
if (passwordHistoryPolicyValue != -1) {
|
if (passwordHistoryPolicyValue != -1) {
|
||||||
List<CredentialModel> storedPasswords = session.userCredentialManager().getStoredCredentialsByType(realm, user, PasswordCredentialModel.TYPE);
|
if (session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, PasswordCredentialModel.TYPE)
|
||||||
for (CredentialModel cred : storedPasswords) {
|
.map(PasswordCredentialModel::createFromCredentialModel)
|
||||||
PasswordCredentialModel passwordCredential = PasswordCredentialModel.createFromCredentialModel(cred);
|
.anyMatch(passwordCredential -> {
|
||||||
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, passwordCredential.getPasswordCredentialData().getAlgorithm());
|
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class,
|
||||||
if (hash == null) continue;
|
passwordCredential.getPasswordCredentialData().getAlgorithm());
|
||||||
if (hash.verify(password, passwordCredential)) {
|
return hash != null && hash.verify(password, passwordCredential);
|
||||||
return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
|
})) {
|
||||||
}
|
return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (passwordHistoryPolicyValue > 0) {
|
if (passwordHistoryPolicyValue > 0) {
|
||||||
List<CredentialModel> passwordHistory = session.userCredentialManager().getStoredCredentialsByType(realm, user, PasswordCredentialModel.PASSWORD_HISTORY);
|
if (this.getRecent(session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, PasswordCredentialModel.PASSWORD_HISTORY),
|
||||||
List<CredentialModel> recentPasswordHistory = getRecent(passwordHistory, passwordHistoryPolicyValue - 1);
|
passwordHistoryPolicyValue - 1)
|
||||||
for (CredentialModel cred : recentPasswordHistory) {
|
.map(PasswordCredentialModel::createFromCredentialModel)
|
||||||
PasswordCredentialModel passwordCredential = PasswordCredentialModel.createFromCredentialModel(cred);
|
.anyMatch(passwordCredential -> {
|
||||||
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class, passwordCredential.getPasswordCredentialData().getAlgorithm());
|
PasswordHashProvider hash = session.getProvider(PasswordHashProvider.class,
|
||||||
if (hash.verify(password, passwordCredential)) {
|
passwordCredential.getPasswordCredentialData().getAlgorithm());
|
||||||
return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
|
return hash.verify(password, passwordCredential);
|
||||||
}
|
})) {
|
||||||
|
return new PolicyError(ERROR_MESSAGE, passwordHistoryPolicyValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<CredentialModel> getRecent(List<CredentialModel> passwordHistory, int limit) {
|
private Stream<CredentialModel> getRecent(Stream<CredentialModel> passwordHistory, int limit) {
|
||||||
return passwordHistory.stream()
|
return passwordHistory
|
||||||
.sorted(CredentialModel.comparingByStartDateDesc())
|
.sorted(CredentialModel.comparingByStartDateDesc())
|
||||||
.limit(limit)
|
.limit(limit);
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,8 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -37,6 +39,39 @@ public interface CredentialInputUpdater {
|
||||||
* @param realm
|
* @param realm
|
||||||
* @param user
|
* @param user
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated Use {@link #getDisableableCredentialTypesStream(RealmModel, UserModel) getDisableableCredentialTypesStream}
|
||||||
|
* instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user);
|
Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the set of credential types that can be disabled via {@link #disableCredentialType(RealmModel, UserModel, String)
|
||||||
|
* disableCredentialType}.
|
||||||
|
*
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user the user whose credentials are being searched.
|
||||||
|
* @return a non-null {@link Stream} of credential types.
|
||||||
|
*/
|
||||||
|
default Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
|
Set<String> result = this.getDisableableCredentialTypes(realm, user);
|
||||||
|
return result != null ? result.stream() : Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link CredentialInputUpdater.Streams} interface makes all collection-based methods in {@link CredentialInputUpdater}
|
||||||
|
* default by providing implementations that delegate to the {@link Stream}-based variants instead of the other way around.
|
||||||
|
* <p/>
|
||||||
|
* It allows for implementations to focus on the {@link Stream}-based approach for processing sets of data and benefit
|
||||||
|
* from the potential memory and performance optimizations of that approach.
|
||||||
|
*/
|
||||||
|
interface Streams extends CredentialInputUpdater {
|
||||||
|
@Override
|
||||||
|
default Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
||||||
|
return this.getDisableableCredentialTypesStream(realm, user).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
|
@ -43,11 +41,9 @@ public interface CredentialProvider<T extends CredentialModel> extends Provider
|
||||||
T getCredentialFromModel(CredentialModel model);
|
T getCredentialFromModel(CredentialModel model);
|
||||||
|
|
||||||
default T getDefaultCredential(KeycloakSession session, RealmModel realm, UserModel user) {
|
default T getDefaultCredential(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||||
List<CredentialModel> models = session.userCredentialManager().getStoredCredentialsByType(realm, user, getType());
|
CredentialModel model = session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, getType())
|
||||||
if (models.isEmpty()) {
|
.findFirst().orElse(null);
|
||||||
return null;
|
return model != null ? getCredentialFromModel(model) : null;
|
||||||
}
|
|
||||||
return getCredentialFromModel(models.get(0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CredentialTypeMetadata getCredentialTypeMetadata(CredentialTypeMetadataContext metadataContext);
|
CredentialTypeMetadata getCredentialTypeMetadata(CredentialTypeMetadataContext metadataContext);
|
||||||
|
|
|
@ -21,6 +21,8 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.provider.Provider;
|
import org.keycloak.provider.Provider;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -31,11 +33,72 @@ public interface UserCredentialStore extends Provider {
|
||||||
CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred);
|
CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred);
|
||||||
boolean removeStoredCredential(RealmModel realm, UserModel user, String id);
|
boolean removeStoredCredential(RealmModel realm, UserModel user, String id);
|
||||||
CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id);
|
CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #getStoredCredentialsStream(RealmModel, UserModel) getStoredCredentialsStream} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user);
|
List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the stored credentials associated with the specified user.
|
||||||
|
*
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user the user whose credentials are being searched.
|
||||||
|
* @return a non-null {@link Stream} of credentials.
|
||||||
|
*/
|
||||||
|
default Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||||
|
List<CredentialModel> result = this.getStoredCredentials(realm, user);
|
||||||
|
return result != null ? result.stream() : Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #getStoredCredentialsByTypeStream(RealmModel, UserModel, String) getStoredCredentialsByTypeStream}
|
||||||
|
* instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type);
|
List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the stored credentials associated with the specified user that match the specified type.
|
||||||
|
*
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user the user whose credentials are being searched.
|
||||||
|
* @param type the type of credentials being searched.
|
||||||
|
* @return a non-null {@link Stream} of credentials.
|
||||||
|
*/
|
||||||
|
default Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
|
||||||
|
List<CredentialModel> result = this.getStoredCredentialsByType(realm, user, type);
|
||||||
|
return result != null ? result.stream() : Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type);
|
CredentialModel getStoredCredentialByNameAndType(RealmModel realm, UserModel user, String name, String type);
|
||||||
|
|
||||||
//list operations
|
//list operations
|
||||||
boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId);
|
boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UserCredentialStore.Streams} interface makes all collection-based methods in {@link UserCredentialStore}
|
||||||
|
* default by providing implementations that delegate to the {@link Stream}-based variants instead of the other way around.
|
||||||
|
* <p/>
|
||||||
|
* It allows for implementations to focus on the {@link Stream}-based approach for processing sets of data and benefit
|
||||||
|
* from the potential memory and performance optimizations of that approach.
|
||||||
|
*/
|
||||||
|
interface Streams extends UserCredentialStore {
|
||||||
|
@Override
|
||||||
|
default List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
|
||||||
|
return this.getStoredCredentialsStream(realm, user).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
|
||||||
|
return this.getStoredCredentialsByTypeStream(realm, user, type).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@ import org.keycloak.credential.UserCredentialStore;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -95,9 +97,25 @@ public interface UserCredentialManager extends UserCredentialStore {
|
||||||
* @param realm
|
* @param realm
|
||||||
* @param user
|
* @param user
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated Use {@link #getDisableableCredentialTypesStream(RealmModel, UserModel) getDisableableCredentialTypesStream}
|
||||||
|
* instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user);
|
Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the credential types that can be disabled by means of the {@link #disableCredentialType(RealmModel, UserModel, String)}
|
||||||
|
* method.
|
||||||
|
*
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user the user whose credentials are being searched.
|
||||||
|
* @return a non-null {@link Stream} of credential types.
|
||||||
|
*/
|
||||||
|
default Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
|
Set<String> result = this.getDisableableCredentialTypes(realm, user);
|
||||||
|
return result != null ? result.stream() : Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks to see if user has credential type configured. Looks in UserStorageProvider or UserFederationProvider first,
|
* Checks to see if user has credential type configured. Looks in UserStorageProvider or UserFederationProvider first,
|
||||||
* then loops through each CredentialProvider.
|
* then loops through each CredentialProvider.
|
||||||
|
@ -139,6 +157,49 @@ public interface UserCredentialManager extends UserCredentialStore {
|
||||||
* This will always return empty list for "local" users, which are not backed by any user storage
|
* This will always return empty list for "local" users, which are not backed by any user storage
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
* @deprecated Use {@link #getConfiguredUserStorageCredentialTypesStream(RealmModel, UserModel) getConfiguredUserStorageCredentialTypesStream}
|
||||||
|
* instead.
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user);
|
List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains the credential types provided by the user storage where the specified user is stored. Examples of returned
|
||||||
|
* values are "password", "otp", etc.
|
||||||
|
* <p/>
|
||||||
|
* This method will always return an empty stream for "local" users - i.e. users that are not backed by any user storage.
|
||||||
|
*
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user a reference to the user.
|
||||||
|
* @return a non-null {@link Stream} of credential types.
|
||||||
|
*/
|
||||||
|
default Stream<String> getConfiguredUserStorageCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
|
List<String> result = this.getConfiguredUserStorageCredentialTypes(realm, user);
|
||||||
|
return result != null ? result.stream() : Stream.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The {@link UserCredentialManager.Streams} interface makes all collection-based methods in {@link UserCredentialManager}
|
||||||
|
* default by providing implementations that delegate to the {@link Stream}-based variants instead of the other way around.
|
||||||
|
* <p/>
|
||||||
|
* It allows for implementations to focus on the {@link Stream}-based approach for processing sets of data and benefit
|
||||||
|
* from the potential memory and performance optimizations of that approach.
|
||||||
|
*/
|
||||||
|
interface Streams extends UserCredentialManager, UserCredentialStore.Streams {
|
||||||
|
@Override
|
||||||
|
default Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
||||||
|
return this.getDisableableCredentialTypesStream(realm, user).collect(Collectors.toSet());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user);
|
||||||
|
|
||||||
|
@Override
|
||||||
|
default List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user) {
|
||||||
|
return this.getConfiguredUserStorageCredentialTypesStream(realm, user).collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
Stream<String> getConfiguredUserStorageCredentialTypesStream(RealmModel realm, UserModel user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,13 +76,9 @@ class AuthenticationSelectionResolver {
|
||||||
|
|
||||||
//add credential authenticators in order
|
//add credential authenticators in order
|
||||||
if (processor.getAuthenticationSession().getAuthenticatedUser() != null) {
|
if (processor.getAuthenticationSession().getAuthenticatedUser() != null) {
|
||||||
List<CredentialModel> credentials = processor.getSession().userCredentialManager()
|
authenticationSelectionList = processor.getSession().userCredentialManager()
|
||||||
.getStoredCredentials(processor.getRealm(), processor.getAuthenticationSession().getAuthenticatedUser())
|
.getStoredCredentialsStream(processor.getRealm(), processor.getAuthenticationSession().getAuthenticatedUser())
|
||||||
.stream()
|
|
||||||
.filter(credential -> typeAuthExecMap.containsKey(credential.getType()))
|
.filter(credential -> typeAuthExecMap.containsKey(credential.getType()))
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
authenticationSelectionList = credentials.stream()
|
|
||||||
.map(CredentialModel::getType)
|
.map(CredentialModel::getType)
|
||||||
.distinct()
|
.distinct()
|
||||||
.map(credentialType -> new AuthenticationSelectionOption(processor.getSession(), typeAuthExecMap.get(credentialType)))
|
.map(credentialType -> new AuthenticationSelectionOption(processor.getSession(), typeAuthExecMap.get(credentialType)))
|
||||||
|
|
|
@ -20,6 +20,7 @@ package org.keycloak.authentication.authenticators.x509;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ public abstract class UserIdentityToModelMapper {
|
||||||
for (int i = 1; i <_customAttributes.size(); ++i) {
|
for (int i = 1; i <_customAttributes.size(); ++i) {
|
||||||
String customAttribute = _customAttributes.get(i);
|
String customAttribute = _customAttributes.get(i);
|
||||||
String userIdentityValue = userIdentityValues.get(i);
|
String userIdentityValue = userIdentityValues.get(i);
|
||||||
usersStream = usersStream.filter(user -> user.getFirstAttribute(customAttribute).equals(userIdentityValue));
|
usersStream = usersStream.filter(user -> Objects.equals(user.getFirstAttribute(customAttribute), userIdentityValue));
|
||||||
}
|
}
|
||||||
List<UserModel> users = usersStream.collect(Collectors.toList());
|
List<UserModel> users = usersStream.collect(Collectors.toList());
|
||||||
if (users.size() > 1) {
|
if (users.size() > 1) {
|
||||||
|
|
|
@ -43,8 +43,7 @@ import org.keycloak.utils.CredentialHelper;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
import java.util.Collections;
|
import java.util.stream.Stream;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
|
@ -96,10 +95,10 @@ public class UpdateTotp implements RequiredActionProvider, RequiredActionFactory
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
OTPCredentialProvider otpCredentialProvider = (OTPCredentialProvider) context.getSession().getProvider(CredentialProvider.class, "keycloak-otp");
|
OTPCredentialProvider otpCredentialProvider = (OTPCredentialProvider) context.getSession().getProvider(CredentialProvider.class, "keycloak-otp");
|
||||||
final List<CredentialModel> otpCredentials = (otpCredentialProvider.isConfiguredFor(context.getRealm(), context.getUser()))
|
final Stream<CredentialModel> otpCredentials = (otpCredentialProvider.isConfiguredFor(context.getRealm(), context.getUser()))
|
||||||
? context.getSession().userCredentialManager().getStoredCredentialsByType(context.getRealm(), context.getUser(), OTPCredentialModel.TYPE)
|
? context.getSession().userCredentialManager().getStoredCredentialsByTypeStream(context.getRealm(), context.getUser(), OTPCredentialModel.TYPE)
|
||||||
: Collections.EMPTY_LIST;
|
: Stream.empty();
|
||||||
if (otpCredentials.size() >= 1 && Validation.isBlank(userLabel)) {
|
if (otpCredentials.count() >= 1 && Validation.isBlank(userLabel)) {
|
||||||
Response challenge = context.form()
|
Response challenge = context.form()
|
||||||
.setAttribute("mode", mode)
|
.setAttribute("mode", mode)
|
||||||
.addError(new FormMessage(Validation.FIELD_OTP_LABEL, Messages.MISSING_TOTP_DEVICE_NAME))
|
.addError(new FormMessage(Validation.FIELD_OTP_LABEL, Messages.MISSING_TOTP_DEVICE_NAME))
|
||||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Base64;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import javax.ws.rs.core.MultivaluedMap;
|
import javax.ws.rs.core.MultivaluedMap;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -47,7 +48,6 @@ import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.WebAuthnPolicy;
|
import org.keycloak.models.WebAuthnPolicy;
|
||||||
|
|
||||||
import com.webauthn4j.WebAuthnManager;
|
|
||||||
import com.webauthn4j.converter.util.ObjectConverter;
|
import com.webauthn4j.converter.util.ObjectConverter;
|
||||||
import com.webauthn4j.data.attestation.authenticator.AttestedCredentialData;
|
import com.webauthn4j.data.attestation.authenticator.AttestedCredentialData;
|
||||||
import com.webauthn4j.data.attestation.statement.AttestationStatement;
|
import com.webauthn4j.data.attestation.statement.AttestationStatement;
|
||||||
|
@ -125,15 +125,11 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
||||||
|
|
||||||
String excludeCredentialIds = "";
|
String excludeCredentialIds = "";
|
||||||
if (avoidSameAuthenticatorRegister) {
|
if (avoidSameAuthenticatorRegister) {
|
||||||
List<CredentialModel> webAuthnCredentials = session.userCredentialManager().getStoredCredentialsByType(context.getRealm(), userModel, getCredentialType());
|
excludeCredentialIds = session.userCredentialManager().getStoredCredentialsByTypeStream(context.getRealm(), userModel, getCredentialType())
|
||||||
List<String> webAuthnCredentialPubKeyIds = webAuthnCredentials.stream().map(credentialModel -> {
|
.map(credentialModel -> {
|
||||||
|
WebAuthnCredentialModel credModel = WebAuthnCredentialModel.createFromCredentialModel(credentialModel);
|
||||||
WebAuthnCredentialModel credModel = WebAuthnCredentialModel.createFromCredentialModel(credentialModel);
|
return Base64Url.encodeBase64ToBase64Url(credModel.getWebAuthnCredentialData().getCredentialId());
|
||||||
return Base64Url.encodeBase64ToBase64Url(credModel.getWebAuthnCredentialData().getCredentialId());
|
}).collect(Collectors.joining(","));
|
||||||
|
|
||||||
}).collect(Collectors.toList());
|
|
||||||
|
|
||||||
excludeCredentialIds = stringifyExcludeCredentialIds(webAuthnCredentialPubKeyIds);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String isSetRetry = context.getHttpRequest().getDecodedFormParameters().getFirst(WebAuthnConstants.IS_SET_RETRY);
|
String isSetRetry = context.getHttpRequest().getDecodedFormParameters().getFirst(WebAuthnConstants.IS_SET_RETRY);
|
||||||
|
@ -300,15 +296,6 @@ public class WebAuthnRegister implements RequiredActionProvider, CredentialRegis
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String stringifyExcludeCredentialIds(List<String> credentialIdsList) {
|
|
||||||
if (credentialIdsList == null || credentialIdsList.isEmpty()) return "";
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
for (String s : credentialIdsList)
|
|
||||||
if (s != null && !s.isEmpty()) sb.append(s).append(",");
|
|
||||||
if (sb.lastIndexOf(",") > -1) sb.deleteCharAt(sb.lastIndexOf(","));
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showInfoAfterWebAuthnApiCreate(RegistrationData response) {
|
private void showInfoAfterWebAuthnApiCreate(RegistrationData response) {
|
||||||
AttestedCredentialData attestedCredentialData = response.getAttestationObject().getAuthenticatorData().getAttestedCredentialData();
|
AttestedCredentialData attestedCredentialData = response.getAttestationObject().getAuthenticatorData().getAttestedCredentialData();
|
||||||
AttestationStatement attestationStatement = response.getAttestationObject().getAttestationStatement();
|
AttestationStatement attestationStatement = response.getAttestationObject().getAttestationStatement();
|
||||||
|
|
|
@ -92,7 +92,7 @@ public class OTPCredentialProvider implements CredentialProvider<OTPCredentialMo
|
||||||
@Override
|
@Override
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
||||||
if (!supportsCredentialType(credentialType)) return false;
|
if (!supportsCredentialType(credentialType)) return false;
|
||||||
return !getCredentialStore().getStoredCredentialsByType(realm, user, credentialType).isEmpty();
|
return getCredentialStore().getStoredCredentialsByTypeStream(realm, user, credentialType).count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user){
|
public boolean isConfiguredFor(RealmModel realm, UserModel user){
|
||||||
|
|
|
@ -32,15 +32,16 @@ import org.keycloak.models.cache.UserCache;
|
||||||
import org.keycloak.policy.PasswordPolicyManagerProvider;
|
import org.keycloak.policy.PasswordPolicyManagerProvider;
|
||||||
import org.keycloak.policy.PolicyError;
|
import org.keycloak.policy.PolicyError;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class PasswordCredentialProvider implements CredentialProvider<PasswordCredentialModel>, CredentialInputUpdater, CredentialInputValidator, OnUserCache {
|
public class PasswordCredentialProvider implements CredentialProvider<PasswordCredentialModel>, CredentialInputUpdater.Streams,
|
||||||
|
CredentialInputValidator, OnUserCache {
|
||||||
|
|
||||||
public static final String PASSWORD_CACHE_KEY = PasswordCredentialProvider.class.getName() + "." + PasswordCredentialModel.TYPE;
|
public static final String PASSWORD_CACHE_KEY = PasswordCredentialProvider.class.getName() + "." + PasswordCredentialModel.TYPE;
|
||||||
private static final Logger logger = Logger.getLogger(PasswordCredentialProvider.class);
|
private static final Logger logger = Logger.getLogger(PasswordCredentialProvider.class);
|
||||||
|
@ -64,7 +65,7 @@ public class PasswordCredentialProvider implements CredentialProvider<PasswordCr
|
||||||
}
|
}
|
||||||
// if the model was marked for eviction while passwords were initialized, override it from credentialStore
|
// if the model was marked for eviction while passwords were initialized, override it from credentialStore
|
||||||
if (!(user instanceof CachedUserModel) || ((CachedUserModel) user).isMarkedForEviction()) {
|
if (!(user instanceof CachedUserModel) || ((CachedUserModel) user).isMarkedForEviction()) {
|
||||||
passwords = getCredentialStore().getStoredCredentialsByType(realm, user, getType());
|
passwords = getCredentialStore().getStoredCredentialsByTypeStream(realm, user, getType()).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
if (passwords == null || passwords.isEmpty()) return null;
|
if (passwords == null || passwords.isEmpty()) return null;
|
||||||
|
|
||||||
|
@ -115,14 +116,12 @@ public class PasswordCredentialProvider implements CredentialProvider<PasswordCr
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3) remove old password history items
|
// 3) remove old password history items
|
||||||
List<CredentialModel> passwordHistoryList = getCredentialStore().getStoredCredentialsByType(realm, user, PasswordCredentialModel.PASSWORD_HISTORY);
|
|
||||||
final int passwordHistoryListMaxSize = Math.max(0, expiredPasswordsPolicyValue - 1);
|
final int passwordHistoryListMaxSize = Math.max(0, expiredPasswordsPolicyValue - 1);
|
||||||
if (passwordHistoryList.size() > passwordHistoryListMaxSize) {
|
getCredentialStore().getStoredCredentialsByTypeStream(realm, user, PasswordCredentialModel.PASSWORD_HISTORY)
|
||||||
passwordHistoryList.stream()
|
.sorted(CredentialModel.comparingByStartDateDesc())
|
||||||
.sorted(CredentialModel.comparingByStartDateDesc())
|
.skip(passwordHistoryListMaxSize)
|
||||||
.skip(passwordHistoryListMaxSize)
|
.collect(Collectors.toList())
|
||||||
.forEach(p -> getCredentialStore().removeStoredCredential(realm, user, p.getId()));
|
.forEach(p -> getCredentialStore().removeStoredCredential(realm, user, p.getId()));
|
||||||
}
|
|
||||||
|
|
||||||
UserCache userCache = session.userCache();
|
UserCache userCache = session.userCache();
|
||||||
if (userCache != null) {
|
if (userCache != null) {
|
||||||
|
@ -220,8 +219,8 @@ public class PasswordCredentialProvider implements CredentialProvider<PasswordCr
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return Collections.emptySet();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -282,11 +281,9 @@ public class PasswordCredentialProvider implements CredentialProvider<PasswordCr
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
|
public void onCache(RealmModel realm, CachedUserModel user, UserModel delegate) {
|
||||||
List<CredentialModel> passwords = getCredentialStore().getStoredCredentialsByType(realm, user, getType());
|
List<CredentialModel> passwords = getCredentialStore().getStoredCredentialsByTypeStream(realm, user, getType())
|
||||||
if (passwords != null) {
|
.collect(Collectors.toList());
|
||||||
user.getCachedWith().put(PASSWORD_CACHE_KEY, passwords);
|
user.getCachedWith().put(PASSWORD_CACHE_KEY, passwords);
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -25,7 +25,6 @@ import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.cache.CachedUserModel;
|
import org.keycloak.models.cache.CachedUserModel;
|
||||||
import org.keycloak.models.cache.OnUserCache;
|
import org.keycloak.models.cache.OnUserCache;
|
||||||
import org.keycloak.models.cache.UserCache;
|
import org.keycloak.models.cache.UserCache;
|
||||||
import org.keycloak.provider.ProviderFactory;
|
|
||||||
import org.keycloak.storage.AbstractStorageManager;
|
import org.keycloak.storage.AbstractStorageManager;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
|
@ -33,12 +32,8 @@ import org.keycloak.storage.UserStorageProviderFactory;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -46,7 +41,8 @@ import java.util.stream.Stream;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserCredentialStoreManager extends AbstractStorageManager<UserStorageProvider, UserStorageProviderModel> implements UserCredentialManager, OnUserCache {
|
public class UserCredentialStoreManager extends AbstractStorageManager<UserStorageProvider, UserStorageProviderModel>
|
||||||
|
implements UserCredentialManager.Streams, OnUserCache {
|
||||||
|
|
||||||
public UserCredentialStoreManager(KeycloakSession session) {
|
public UserCredentialStoreManager(KeycloakSession session) {
|
||||||
super(session, UserStorageProviderFactory.class, UserStorageProvider.class, UserStorageProviderModel::new, "user");
|
super(session, UserStorageProviderFactory.class, UserStorageProvider.class, UserStorageProviderModel::new, "user");
|
||||||
|
@ -89,13 +85,13 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentials(RealmModel realm, UserModel user) {
|
public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||||
return getStoreForUser(user).getStoredCredentials(realm, user);
|
return getStoreForUser(user).getStoredCredentialsStream(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CredentialModel> getStoredCredentialsByType(RealmModel realm, UserModel user, String type) {
|
public Stream<CredentialModel> getStoredCredentialsByTypeStream(RealmModel realm, UserModel user, String type) {
|
||||||
return getStoreForUser(user).getStoredCredentialsByType(realm, user, type);
|
return getStoreForUser(user).getStoredCredentialsByTypeStream(realm, user, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -218,23 +214,20 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
Set<String> types = new HashSet<>();
|
Stream<String> types = Stream.empty();
|
||||||
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
String providerId = StorageId.isLocalStorage(user) ? user.getFederationLink() : StorageId.resolveProviderId(user);
|
||||||
if (providerId != null) {
|
if (providerId != null) {
|
||||||
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
UserStorageProviderModel model = getStorageProviderModel(realm, providerId);
|
||||||
if (model == null || !model.isEnabled()) return Collections.EMPTY_SET;
|
if (model == null || !model.isEnabled()) return types;
|
||||||
|
|
||||||
CredentialInputUpdater updater = getStorageProviderInstance(model, CredentialInputUpdater.class);
|
CredentialInputUpdater updater = getStorageProviderInstance(model, CredentialInputUpdater.class);
|
||||||
if (updater != null) types.addAll(updater.getDisableableCredentialTypes(realm, user));
|
if (updater != null) types = updater.getDisableableCredentialTypesStream(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
types.addAll(getCredentialProviders(session, CredentialInputUpdater.class)
|
return Stream.concat(types, getCredentialProviders(session, CredentialInputUpdater.class)
|
||||||
.map(updater -> updater.getDisableableCredentialTypes(realm, user))
|
.flatMap(updater -> updater.getDisableableCredentialTypesStream(realm, user)))
|
||||||
.flatMap(Set::stream)
|
.distinct();
|
||||||
.collect(Collectors.toSet()));
|
|
||||||
|
|
||||||
return types;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -298,10 +291,9 @@ public class UserCredentialStoreManager extends AbstractStorageManager<UserStora
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getConfiguredUserStorageCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getConfiguredUserStorageCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return getCredentialProviders(session, CredentialProvider.class).map(CredentialProvider::getType)
|
return getCredentialProviders(session, CredentialProvider.class).map(CredentialProvider::getType)
|
||||||
.filter(credentialType -> UserStorageCredentialConfigured.CONFIGURED == isConfiguredThroughUserStorage(realm, user, credentialType))
|
.filter(credentialType -> UserStorageCredentialConfigured.CONFIGURED == isConfiguredThroughUserStorage(realm, user, credentialType));
|
||||||
.collect(Collectors.toList());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class WebAuthnCredentialProvider implements CredentialProvider<WebAuthnCr
|
||||||
@Override
|
@Override
|
||||||
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
public boolean isConfiguredFor(RealmModel realm, UserModel user, String credentialType) {
|
||||||
if (!supportsCredentialType(credentialType)) return false;
|
if (!supportsCredentialType(credentialType)) return false;
|
||||||
return !session.userCredentialManager().getStoredCredentialsByType(realm, user, credentialType).isEmpty();
|
return session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, credentialType).count() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -224,9 +224,7 @@ public class WebAuthnCredentialProvider implements CredentialProvider<WebAuthnCr
|
||||||
|
|
||||||
|
|
||||||
private List<WebAuthnCredentialModelInput> getWebAuthnCredentialModelList(RealmModel realm, UserModel user) {
|
private List<WebAuthnCredentialModelInput> getWebAuthnCredentialModelList(RealmModel realm, UserModel user) {
|
||||||
List<CredentialModel> credentialModels = session.userCredentialManager().getStoredCredentialsByType(realm, user, getType());
|
return session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, getType())
|
||||||
|
|
||||||
return credentialModels.stream()
|
|
||||||
.map(this::getCredentialInputFromCredentialModel)
|
.map(this::getCredentialInputFromCredentialModel)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
|
@ -495,12 +495,8 @@ public class ExportUtils {
|
||||||
|
|
||||||
// Credentials - extra security, do not export credentials if service accounts
|
// Credentials - extra security, do not export credentials if service accounts
|
||||||
if (internal) {
|
if (internal) {
|
||||||
List<CredentialModel> creds = session.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialRepresentation> credReps = session.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
List<CredentialRepresentation> credReps = new ArrayList<>();
|
.map(ExportUtils::exportCredential).collect(Collectors.toList());
|
||||||
for (CredentialModel cred : creds) {
|
|
||||||
CredentialRepresentation credRep = exportCredential(cred);
|
|
||||||
credReps.add(credRep);
|
|
||||||
}
|
|
||||||
userRep.setCredentials(credReps);
|
userRep.setCredentials(credReps);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,45 +54,7 @@ public class ApplicationsBean {
|
||||||
|
|
||||||
this.applications = this.getApplications(session, realm, user)
|
this.applications = this.getApplications(session, realm, user)
|
||||||
.filter(client -> !isAdminClient(client) || AdminPermissions.realms(session, realm, user).isAdmin())
|
.filter(client -> !isAdminClient(client) || AdminPermissions.realms(session, realm, user).isAdmin())
|
||||||
.map(client -> {
|
.map(client -> toApplicationEntry(session, realm, user, client, offlineClients))
|
||||||
|
|
||||||
// Construct scope parameter with all optional scopes to see all potentially available roles
|
|
||||||
Stream<ClientScopeModel> allClientScopes = Stream.concat(
|
|
||||||
client.getClientScopes(true, true).values().stream(),
|
|
||||||
client.getClientScopes(false, true).values().stream());
|
|
||||||
allClientScopes = Stream.concat(allClientScopes, Stream.of(client)).distinct();
|
|
||||||
|
|
||||||
Set<RoleModel> availableRoles = TokenManager.getAccess(user, client, allClientScopes);
|
|
||||||
|
|
||||||
// Don't show applications, which user doesn't have access into (any available roles)
|
|
||||||
// unless this is can be changed by approving/revoking consent
|
|
||||||
if (! isAdminClient(client) && availableRoles.isEmpty() && ! client.isConsentRequired()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<RoleModel> realmRolesAvailable = new LinkedList<>();
|
|
||||||
MultivaluedHashMap<String, ClientRoleEntry> resourceRolesAvailable = new MultivaluedHashMap<>();
|
|
||||||
processRoles(availableRoles, realmRolesAvailable, resourceRolesAvailable);
|
|
||||||
|
|
||||||
List<ClientScopeModel> orderedScopes = new LinkedList<>();
|
|
||||||
if (client.isConsentRequired()) {
|
|
||||||
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
|
|
||||||
|
|
||||||
if (consent != null) {
|
|
||||||
orderedScopes.addAll(consent.getGrantedClientScopes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<String> clientScopesGranted = orderedScopes.stream()
|
|
||||||
.sorted(OrderedModel.OrderedModelComparator.getInstance())
|
|
||||||
.map(ClientScopeModel::getConsentScreenText)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
|
|
||||||
List<String> additionalGrants = new ArrayList<>();
|
|
||||||
if (offlineClients.contains(client)) {
|
|
||||||
additionalGrants.add("${offlineToken}");
|
|
||||||
}
|
|
||||||
return new ApplicationEntry(session, realmRolesAvailable, resourceRolesAvailable, client, clientScopesGranted, additionalGrants);
|
|
||||||
})
|
|
||||||
.filter(Objects::nonNull)
|
.filter(Objects::nonNull)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
@ -204,4 +166,56 @@ public class ApplicationsBean {
|
||||||
return roleDescription;
|
return roleDescription;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a {@link ApplicationEntry} from the specified parameters.
|
||||||
|
*
|
||||||
|
* @param session a reference to the {@code Keycloak} session.
|
||||||
|
* @param realm a reference to the realm.
|
||||||
|
* @param user a reference to the user.
|
||||||
|
* @param client a reference to the client that contains the applications.
|
||||||
|
* @param offlineClients a {@link Set} containing the offline clients.
|
||||||
|
* @return the constructed {@link ApplicationEntry} instance or {@code null} if the user can't access the applications
|
||||||
|
* in the specified client.
|
||||||
|
*/
|
||||||
|
private ApplicationEntry toApplicationEntry(final KeycloakSession session, final RealmModel realm, final UserModel user,
|
||||||
|
final ClientModel client, final Set<ClientModel> offlineClients) {
|
||||||
|
|
||||||
|
// Construct scope parameter with all optional scopes to see all potentially available roles
|
||||||
|
Stream<ClientScopeModel> allClientScopes = Stream.concat(
|
||||||
|
client.getClientScopes(true, true).values().stream(),
|
||||||
|
client.getClientScopes(false, true).values().stream());
|
||||||
|
allClientScopes = Stream.concat(allClientScopes, Stream.of(client)).distinct();
|
||||||
|
|
||||||
|
Set<RoleModel> availableRoles = TokenManager.getAccess(user, client, allClientScopes);
|
||||||
|
|
||||||
|
// Don't show applications, which user doesn't have access into (any available roles)
|
||||||
|
// unless this is can be changed by approving/revoking consent
|
||||||
|
if (! isAdminClient(client) && availableRoles.isEmpty() && ! client.isConsentRequired()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<RoleModel> realmRolesAvailable = new LinkedList<>();
|
||||||
|
MultivaluedHashMap<String, ClientRoleEntry> resourceRolesAvailable = new MultivaluedHashMap<>();
|
||||||
|
processRoles(availableRoles, realmRolesAvailable, resourceRolesAvailable);
|
||||||
|
|
||||||
|
List<ClientScopeModel> orderedScopes = new LinkedList<>();
|
||||||
|
if (client.isConsentRequired()) {
|
||||||
|
UserConsentModel consent = session.users().getConsentByClient(realm, user.getId(), client.getId());
|
||||||
|
|
||||||
|
if (consent != null) {
|
||||||
|
orderedScopes.addAll(consent.getGrantedClientScopes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> clientScopesGranted = orderedScopes.stream()
|
||||||
|
.sorted(OrderedModel.OrderedModelComparator.getInstance())
|
||||||
|
.map(ClientScopeModel::getConsentScreenText)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
List<String> additionalGrants = new ArrayList<>();
|
||||||
|
if (offlineClients.contains(client)) {
|
||||||
|
additionalGrants.add("${offlineToken}");
|
||||||
|
}
|
||||||
|
return new ApplicationEntry(session, realmRolesAvailable, resourceRolesAvailable, client, clientScopesGranted, additionalGrants);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
package org.keycloak.forms.account.freemarker.model;
|
package org.keycloak.forms.account.freemarker.model;
|
||||||
|
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.credential.CredentialProvider;
|
|
||||||
import org.keycloak.credential.OTPCredentialProvider;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.OTPPolicy;
|
import org.keycloak.models.OTPPolicy;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -33,6 +31,7 @@ import org.keycloak.utils.TotpUtils;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.utils.CredentialHelper.createUserStorageCredentialRepresentation;
|
import static org.keycloak.utils.CredentialHelper.createUserStorageCredentialRepresentation;
|
||||||
|
|
||||||
|
@ -54,7 +53,8 @@ public class TotpBean {
|
||||||
this.uriBuilder = uriBuilder;
|
this.uriBuilder = uriBuilder;
|
||||||
this.enabled = session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE);
|
this.enabled = session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
List<CredentialModel> otpCredentials = session.userCredentialManager().getStoredCredentialsByType(realm, user, OTPCredentialModel.TYPE);
|
List<CredentialModel> otpCredentials = session.userCredentialManager()
|
||||||
|
.getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE).collect(Collectors.toList());
|
||||||
|
|
||||||
if (otpCredentials.isEmpty()) {
|
if (otpCredentials.isEmpty()) {
|
||||||
// Credential is configured on userStorage side. Create the "fake" credential similar like we do for the new account console
|
// Credential is configured on userStorage side. Create the "fake" credential similar like we do for the new account console
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.keycloak.utils.TotpUtils;
|
||||||
import javax.ws.rs.core.UriBuilder;
|
import javax.ws.rs.core.UriBuilder;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used for UpdateTotp required action
|
* Used for UpdateTotp required action
|
||||||
|
@ -49,7 +50,8 @@ public class TotpBean {
|
||||||
this.uriBuilder = uriBuilder;
|
this.uriBuilder = uriBuilder;
|
||||||
this.enabled = session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE);
|
this.enabled = session.userCredentialManager().isConfiguredFor(realm, user, OTPCredentialModel.TYPE);
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
otpCredentials = session.userCredentialManager().getStoredCredentialsByType(realm, user, OTPCredentialModel.TYPE);
|
otpCredentials = session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE)
|
||||||
|
.collect(Collectors.toList());
|
||||||
} else {
|
} else {
|
||||||
otpCredentials = Collections.EMPTY_LIST;
|
otpCredentials = Collections.EMPTY_LIST;
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,8 @@ public class TotpLoginBean {
|
||||||
private final List<OTPCredential> userOtpCredentials;
|
private final List<OTPCredential> userOtpCredentials;
|
||||||
|
|
||||||
public TotpLoginBean(KeycloakSession session, RealmModel realm, UserModel user, String selectedCredentialId) {
|
public TotpLoginBean(KeycloakSession session, RealmModel realm, UserModel user, String selectedCredentialId) {
|
||||||
List<CredentialModel> userOtpCredentials = session.userCredentialManager()
|
|
||||||
.getStoredCredentialsByType(realm, user, OTPCredentialModel.TYPE);
|
|
||||||
|
|
||||||
this.userOtpCredentials = userOtpCredentials.stream()
|
this.userOtpCredentials = session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE)
|
||||||
.map(OTPCredential::new)
|
.map(OTPCredential::new)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
|
|
@ -17,9 +17,9 @@ package org.keycloak.forms.login.freemarker.model;
|
||||||
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.keycloak.common.util.Base64Url;
|
import org.keycloak.common.util.Base64Url;
|
||||||
import org.keycloak.credential.CredentialModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -30,13 +30,13 @@ public class WebAuthnAuthenticatorsBean {
|
||||||
|
|
||||||
public WebAuthnAuthenticatorsBean(KeycloakSession session, RealmModel realm, UserModel user, String credentialType) {
|
public WebAuthnAuthenticatorsBean(KeycloakSession session, RealmModel realm, UserModel user, String credentialType) {
|
||||||
// should consider multiple credentials in the future, but only single credential supported now.
|
// should consider multiple credentials in the future, but only single credential supported now.
|
||||||
for (CredentialModel credential : session.userCredentialManager().getStoredCredentialsByType(realm, user, credentialType)) {
|
this.authenticators = session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, credentialType)
|
||||||
WebAuthnCredentialModel webAuthnCredential = WebAuthnCredentialModel.createFromCredentialModel(credential);
|
.map(WebAuthnCredentialModel::createFromCredentialModel)
|
||||||
|
.map(webAuthnCredential -> {
|
||||||
String credentialId = Base64Url.encodeBase64ToBase64Url(webAuthnCredential.getWebAuthnCredentialData().getCredentialId());
|
String credentialId = Base64Url.encodeBase64ToBase64Url(webAuthnCredential.getWebAuthnCredentialData().getCredentialId());
|
||||||
String label = (webAuthnCredential.getUserLabel()==null || webAuthnCredential.getUserLabel().isEmpty()) ? "label missing" : webAuthnCredential.getUserLabel();
|
String label = (webAuthnCredential.getUserLabel()==null || webAuthnCredential.getUserLabel().isEmpty()) ? "label missing" : webAuthnCredential.getUserLabel();
|
||||||
authenticators.add(new WebAuthnAuthenticatorBean(credentialId, label));
|
return new WebAuthnAuthenticatorBean(credentialId, label);
|
||||||
}
|
}).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<WebAuthnAuthenticatorBean> getAuthenticators() {
|
public List<WebAuthnAuthenticatorBean> getAuthenticators() {
|
||||||
|
|
|
@ -170,14 +170,9 @@ public class AccountCredentialResource {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
Set<String> enabledCredentialTypes = getEnabledCredentialTypes(credentialProviders);
|
Set<String> enabledCredentialTypes = getEnabledCredentialTypes(credentialProviders);
|
||||||
|
|
||||||
List<CredentialModel> models = includeUserCredentials ? session.userCredentialManager().getStoredCredentials(realm, user) : null;
|
Stream<CredentialModel> modelsStream = includeUserCredentials ? session.userCredentialManager().getStoredCredentialsStream(realm, user) : Stream.empty();
|
||||||
|
|
||||||
// Don't return secrets from REST endpoint
|
// Don't return secrets from REST endpoint
|
||||||
if (models != null) {
|
List<CredentialModel> models = modelsStream.peek(model -> model.setSecretData(null)).collect(Collectors.toList());
|
||||||
for (CredentialModel credential : models) {
|
|
||||||
credential.setSecretData(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Function<CredentialProvider, CredentialContainer> toCredentialContainer = (credentialProvider) -> {
|
Function<CredentialProvider, CredentialContainer> toCredentialContainer = (credentialProvider) -> {
|
||||||
CredentialTypeMetadataContext ctx = CredentialTypeMetadataContext.builder()
|
CredentialTypeMetadataContext ctx = CredentialTypeMetadataContext.builder()
|
||||||
|
|
|
@ -19,7 +19,13 @@ package org.keycloak.services.resources.account;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.security.MessageDigest;
|
import java.security.MessageDigest;
|
||||||
import java.util.*;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
|
|
@ -600,7 +600,7 @@ public class UserResource {
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public Stream<CredentialRepresentation> credentials(){
|
public Stream<CredentialRepresentation> credentials(){
|
||||||
auth.users().requireManage(user);
|
auth.users().requireManage(user);
|
||||||
return session.userCredentialManager().getStoredCredentials(realm, user).stream()
|
return session.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
.peek(model -> model.setSecretData(null))
|
.peek(model -> model.setSecretData(null))
|
||||||
.map(ModelToRepresentation::toRepresentation);
|
.map(ModelToRepresentation::toRepresentation);
|
||||||
}
|
}
|
||||||
|
@ -616,11 +616,11 @@ public class UserResource {
|
||||||
@Path("configured-user-storage-credential-types")
|
@Path("configured-user-storage-credential-types")
|
||||||
@NoCache
|
@NoCache
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
public List<String> getConfiguredUserStorageCredentialTypes() {
|
public Stream<String> getConfiguredUserStorageCredentialTypes() {
|
||||||
// This has "requireManage" due the compatibility with "credentials()" endpoint. Strictly said, it is reading endpoint, not writing,
|
// This has "requireManage" due the compatibility with "credentials()" endpoint. Strictly said, it is reading endpoint, not writing,
|
||||||
// so may be revisited if to rather use "requireView" here in the future.
|
// so may be revisited if to rather use "requireView" here in the future.
|
||||||
auth.users().requireManage(user);
|
auth.users().requireManage(user);
|
||||||
return session.userCredentialManager().getConfiguredUserStorageCredentialTypes(realm, user);
|
return session.userCredentialManager().getConfiguredUserStorageCredentialTypesStream(realm, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,13 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.federation;
|
package org.keycloak.testsuite.federation;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
import org.keycloak.common.util.Time;
|
import org.keycloak.common.util.Time;
|
||||||
|
@ -57,7 +60,7 @@ import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
|
||||||
*/
|
*/
|
||||||
public class BackwardsCompatibilityUserStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider,
|
public class BackwardsCompatibilityUserStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider,
|
||||||
CredentialInputUpdater, CredentialInputValidator, UserQueryProvider.Streams {
|
CredentialInputUpdater, CredentialInputValidator, UserQueryProvider {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(BackwardsCompatibilityUserStorage.class);
|
private static final Logger log = Logger.getLogger(BackwardsCompatibilityUserStorage.class);
|
||||||
|
|
||||||
|
@ -82,7 +85,7 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserModel createUser(RealmModel realm, String username) {
|
private UserModel createUser(RealmModel realm, String username) {
|
||||||
return new AbstractUserAdapterFederatedStorage.Streams(session, realm, model) {
|
return new AbstractUserAdapterFederatedStorage(session, realm, model) {
|
||||||
@Override
|
@Override
|
||||||
public String getUsername() {
|
public String getUsername() {
|
||||||
return username;
|
return username;
|
||||||
|
@ -316,57 +319,58 @@ public class BackwardsCompatibilityUserStorage implements UserLookupProvider, Us
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> getUsersStream(RealmModel realm) {
|
public List<UserModel> getUsers(RealmModel realm) {
|
||||||
return getUsersStream(realm, -1, -1);
|
return getUsers(realm, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> getUsersStream(RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> getUsers(RealmModel realm, int firstResult, int maxResults) {
|
||||||
return users.values()
|
return users.values()
|
||||||
.stream()
|
.stream()
|
||||||
.skip(firstResult).limit(maxResults)
|
.skip(firstResult).limit(maxResults)
|
||||||
.map(myUser -> createUser(realm, myUser.username));
|
.map(myUser -> createUser(realm, myUser.username))
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> searchForUserStream(String search, RealmModel realm) {
|
public List<UserModel> searchForUser(String search, RealmModel realm) {
|
||||||
return searchForUserStream(search, realm, -1, -1);
|
return searchForUser(search, realm, -1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> searchForUserStream(String search, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(String search, RealmModel realm, int firstResult, int maxResults) {
|
||||||
UserModel user = getUserByUsername(search, realm);
|
UserModel user = getUserByUsername(search, realm);
|
||||||
return user == null ? Stream.empty() : Stream.of(user);
|
return user == null ? Collections.emptyList() : Arrays.asList(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm) {
|
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm) {
|
||||||
// Assume that this is not supported
|
// Assume that this is not supported
|
||||||
return Stream.empty();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> searchForUserStream(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
public List<UserModel> searchForUser(Map<String, String> params, RealmModel realm, int firstResult, int maxResults) {
|
||||||
// Assume that this is not supported
|
// Assume that this is not supported
|
||||||
return Stream.empty();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group, int firstResult, int maxResults) {
|
||||||
// Assume that this is not supported
|
// Assume that this is not supported
|
||||||
return Stream.empty();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> getGroupMembersStream(RealmModel realm, GroupModel group) {
|
public List<UserModel> getGroupMembers(RealmModel realm, GroupModel group) {
|
||||||
// Assume that this is not supported
|
// Assume that this is not supported
|
||||||
return Stream.empty();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<UserModel> searchForUserByUserAttributeStream(String attrName, String attrValue, RealmModel realm) {
|
public List<UserModel> searchForUserByUserAttribute(String attrName, String attrValue, RealmModel realm) {
|
||||||
// Assume that this is not supported
|
// Assume that this is not supported
|
||||||
return Stream.empty();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,10 +33,8 @@ import org.keycloak.storage.user.ImportedUserValidation;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import org.keycloak.storage.user.UserQueryProvider;
|
import org.keycloak.storage.user.UserQueryProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -44,7 +42,7 @@ import java.util.stream.Stream;
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider, UserQueryProvider.Streams,
|
public class FailableHardcodedStorageProvider implements UserStorageProvider, UserLookupProvider, UserQueryProvider.Streams,
|
||||||
ImportedUserValidation, CredentialInputUpdater, CredentialInputValidator {
|
ImportedUserValidation, CredentialInputUpdater.Streams, CredentialInputValidator {
|
||||||
|
|
||||||
public static String username = "billb";
|
public static String username = "billb";
|
||||||
public static String password = "password";
|
public static String password = "password";
|
||||||
|
@ -97,9 +95,9 @@ public class FailableHardcodedStorageProvider implements UserStorageProvider, Us
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
checkForceFail();
|
checkForceFail();
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -23,7 +23,6 @@ import org.keycloak.credential.CredentialInputValidator;
|
||||||
import org.keycloak.credential.CredentialModel;
|
import org.keycloak.credential.CredentialModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserCredentialModel;
|
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.models.credential.PasswordCredentialModel;
|
import org.keycloak.models.credential.PasswordCredentialModel;
|
||||||
import org.keycloak.storage.StorageId;
|
import org.keycloak.storage.StorageId;
|
||||||
|
@ -32,10 +31,10 @@ import org.keycloak.storage.adapter.AbstractUserAdapterFederatedStorage;
|
||||||
import org.keycloak.storage.user.UserLookupProvider;
|
import org.keycloak.storage.user.UserLookupProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -83,12 +82,9 @@ public class PassThroughFederatedUserStorageProvider implements
|
||||||
if (INITIAL_PASSWORD.equals(input.getChallengeResponse())) {
|
if (INITIAL_PASSWORD.equals(input.getChallengeResponse())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
Optional<CredentialModel> existing = session.userFederatedStorage()
|
return session.userFederatedStorage().getStoredCredentialsByTypeStream(realm, user.getId(), "CLEAR_TEXT_PASSWORD")
|
||||||
.getStoredCredentialsByTypeStream(realm, user.getId(), "CLEAR_TEXT_PASSWORD")
|
.map(credentialModel -> credentialModel.getSecretData())
|
||||||
.findFirst();
|
.anyMatch(Predicate.isEqual("{\"value\":\"" + input.getChallengeResponse() + "\"}"));
|
||||||
if (existing.isPresent())
|
|
||||||
return existing.get().getSecretData().equals("{\"value\":\"" + input.getChallengeResponse() + "\"}");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ import org.keycloak.storage.user.UserLookupProvider;
|
||||||
import org.keycloak.storage.user.UserQueryProvider;
|
import org.keycloak.storage.user.UserQueryProvider;
|
||||||
import org.keycloak.storage.user.UserRegistrationProvider;
|
import org.keycloak.storage.user.UserRegistrationProvider;
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -54,7 +53,7 @@ import static org.keycloak.storage.UserStorageProviderModel.IMPORT_ENABLED;
|
||||||
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
|
||||||
* @version $Revision: 1 $
|
* @version $Revision: 1 $
|
||||||
*/
|
*/
|
||||||
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater,
|
public class UserMapStorage implements UserLookupProvider, UserStorageProvider, UserRegistrationProvider, CredentialInputUpdater.Streams,
|
||||||
CredentialInputValidator, UserGroupMembershipFederatedStorage.Streams, UserQueryProvider.Streams, ImportedUserValidation {
|
CredentialInputValidator, UserGroupMembershipFederatedStorage.Streams, UserQueryProvider.Streams, ImportedUserValidation {
|
||||||
|
|
||||||
private static final Logger log = Logger.getLogger(UserMapStorage.class);
|
private static final Logger log = Logger.getLogger(UserMapStorage.class);
|
||||||
|
@ -174,8 +173,8 @@ public class UserMapStorage implements UserLookupProvider, UserStorageProvider,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getDisableableCredentialTypes(RealmModel realm, UserModel user) {
|
public Stream<String> getDisableableCredentialTypesStream(RealmModel realm, UserModel user) {
|
||||||
return Collections.EMPTY_SET;
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.keycloak.representations.idm.CredentialRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by st on 26.01.17.
|
* Created by st on 26.01.17.
|
||||||
|
@ -55,7 +56,9 @@ public class RunHelpers {
|
||||||
return (FetchOnServer) session -> {
|
return (FetchOnServer) session -> {
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
UserModel user = session.users().getUserByUsername(username, realm);
|
UserModel user = session.users().getUserByUsername(username, realm);
|
||||||
List<CredentialModel> storedCredentialsByType = session.userCredentialManager().getStoredCredentialsByType(realm, user, CredentialRepresentation.PASSWORD);
|
List<CredentialModel> storedCredentialsByType = session.userCredentialManager()
|
||||||
|
.getStoredCredentialsByTypeStream(realm, user, CredentialRepresentation.PASSWORD)
|
||||||
|
.collect(Collectors.toList());
|
||||||
System.out.println(storedCredentialsByType.size());
|
System.out.println(storedCredentialsByType.size());
|
||||||
return storedCredentialsByType.get(0);
|
return storedCredentialsByType.get(0);
|
||||||
};
|
};
|
||||||
|
|
|
@ -79,6 +79,7 @@ import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
|
@ -482,7 +483,8 @@ public class AccountFormServiceTest extends AbstractTestRealmKeycloakTest {
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
UserModel user = session.users().getUserById(uId, realm);
|
UserModel user = session.users().getUserById(uId, realm);
|
||||||
assertThat(user, Matchers.notNullValue());
|
assertThat(user, Matchers.notNullValue());
|
||||||
List<CredentialModel> storedCredentials = session.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> storedCredentials = session.userCredentialManager()
|
||||||
|
.getStoredCredentialsStream(realm, user).collect(Collectors.toList());
|
||||||
assertThat(storedCredentials, Matchers.hasSize(expectedNumberOfStoredCredentials));
|
assertThat(storedCredentials, Matchers.hasSize(expectedNumberOfStoredCredentials));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,8 @@ import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.junit.Assume;
|
import org.junit.Assume;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
||||||
|
@ -630,9 +632,9 @@ public class KcinitTest extends AbstractTestRealmKeycloakTest {
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm = session.realms().getRealmByName("test");
|
RealmModel realm = session.realms().getRealmByName("test");
|
||||||
UserModel user = session.users().getUserByUsername("wburke", realm);
|
UserModel user = session.users().getUserByUsername("wburke", realm);
|
||||||
for (CredentialModel c: session.userCredentialManager().getStoredCredentialsByType(realm, user, OTPCredentialModel.TYPE)){
|
session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, OTPCredentialModel.TYPE)
|
||||||
session.userCredentialManager().removeStoredCredential(realm, user, c.getId());
|
.collect(Collectors.toList())
|
||||||
}
|
.forEach(model -> session.userCredentialManager().removeStoredCredential(realm, user, model.getId()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -892,7 +892,10 @@ public class LDAPProvidersIntegrationTest extends AbstractLDAPTest {
|
||||||
|
|
||||||
UserCredentialModel cred = UserCredentialModel.password("Candycand1", true);
|
UserCredentialModel cred = UserCredentialModel.password("Candycand1", true);
|
||||||
session.userCredentialManager().updateCredential(appRealm, user, cred);
|
session.userCredentialManager().updateCredential(appRealm, user, cred);
|
||||||
CredentialModel userCredentialValueModel = session.userCredentialManager().getStoredCredentialsByType(appRealm, user, PasswordCredentialModel.TYPE).get(0);
|
CredentialModel userCredentialValueModel = session.userCredentialManager()
|
||||||
|
.getStoredCredentialsByTypeStream(appRealm, user, PasswordCredentialModel.TYPE)
|
||||||
|
.findFirst().orElse(null);
|
||||||
|
Assert.assertNotNull(userCredentialValueModel);
|
||||||
Assert.assertEquals(PasswordCredentialModel.TYPE, userCredentialValueModel.getType());
|
Assert.assertEquals(PasswordCredentialModel.TYPE, userCredentialValueModel.getType());
|
||||||
Assert.assertTrue(session.userCredentialManager().isValid(appRealm, user, cred));
|
Assert.assertTrue(session.userCredentialManager().isValid(appRealm, user, cred));
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.net.URISyntaxException;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
@ -292,8 +293,8 @@ public class BackwardsCompatibilityUserStorageTest extends AbstractAuthTest {
|
||||||
testingClient.server().run(session -> {
|
testingClient.server().run(session -> {
|
||||||
RealmModel realm1 = session.realms().getRealmByName("test");
|
RealmModel realm1 = session.realms().getRealmByName("test");
|
||||||
UserModel user1 = session.users().getUserByUsername("otp1", realm1);
|
UserModel user1 = session.users().getUserByUsername("otp1", realm1);
|
||||||
List<CredentialModel> keycloakDBCredentials = session.userCredentialManager().getStoredCredentials(realm1, user1);
|
Assert.assertEquals(0, session.userCredentialManager()
|
||||||
Assert.assertTrue(keycloakDBCredentials.isEmpty());
|
.getStoredCredentialsStream(realm1, user1).count());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static java.util.Calendar.DAY_OF_WEEK;
|
import static java.util.Calendar.DAY_OF_WEEK;
|
||||||
import static java.util.Calendar.HOUR_OF_DAY;
|
import static java.util.Calendar.HOUR_OF_DAY;
|
||||||
|
@ -879,8 +880,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
Assert.assertFalse(StorageId.isLocalStorage(user));
|
Assert.assertFalse(StorageId.isLocalStorage(user));
|
||||||
|
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
Stream<CredentialModel> credentials = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user);
|
||||||
org.keycloak.testsuite.Assert.assertEquals(0, list.size());
|
org.keycloak.testsuite.Assert.assertEquals(0, credentials.count());
|
||||||
|
|
||||||
// Create password
|
// Create password
|
||||||
CredentialModel passwordCred = PasswordCredentialModel.createFromValues("my-algorithm", "theSalt".getBytes(), 22, "ABC");
|
CredentialModel passwordCred = PasswordCredentialModel.createFromValues("my-algorithm", "theSalt".getBytes(), 22, "ABC");
|
||||||
|
@ -902,7 +903,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: password, otp1, otp2
|
// Assert priorities: password, otp1, otp2
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, passwordId.get(), otp1Id.get(), otp2Id.get());
|
assertOrder(list, passwordId.get(), otp1Id.get(), otp2Id.get());
|
||||||
|
|
||||||
// Assert can't move password when newPreviousCredential not found
|
// Assert can't move password when newPreviousCredential not found
|
||||||
|
@ -920,7 +922,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: password, otp2, otp1
|
// Assert priorities: password, otp2, otp1
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, passwordId.get(), otp2Id.get(), otp1Id.get());
|
assertOrder(list, passwordId.get(), otp2Id.get(), otp1Id.get());
|
||||||
|
|
||||||
// Move otp2 to the top
|
// Move otp2 to the top
|
||||||
|
@ -932,7 +935,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, password, otp1
|
// Assert priorities: otp2, password, otp1
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp2Id.get(), passwordId.get(), otp1Id.get());
|
assertOrder(list, otp2Id.get(), passwordId.get(), otp1Id.get());
|
||||||
|
|
||||||
// Move password down
|
// Move password down
|
||||||
|
@ -944,7 +948,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, otp1, password
|
// Assert priorities: otp2, otp1, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp2Id.get(), otp1Id.get(), passwordId.get());
|
assertOrder(list, otp2Id.get(), otp1Id.get(), passwordId.get());
|
||||||
|
|
||||||
// Remove otp2 down two positions
|
// Remove otp2 down two positions
|
||||||
|
@ -956,7 +961,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, otp1, password
|
// Assert priorities: otp2, otp1, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp1Id.get(), passwordId.get(), otp2Id.get());
|
assertOrder(list, otp1Id.get(), passwordId.get(), otp2Id.get());
|
||||||
|
|
||||||
// Remove password
|
// Remove password
|
||||||
|
@ -968,7 +974,8 @@ public class UserStorageTest extends AbstractAuthTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
UserModel user = currentSession.users().getUserByUsername("thor", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, password
|
// Assert priorities: otp2, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp1Id.get(), otp2Id.get());
|
assertOrder(list, otp1Id.get(), otp2Id.get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -242,7 +242,8 @@ public class PasswordHashingTest extends AbstractTestRealmKeycloakTest {
|
||||||
return testingClient.server("test").fetch(session -> {
|
return testingClient.server("test").fetch(session -> {
|
||||||
RealmModel realm = session.getContext().getRealm();
|
RealmModel realm = session.getContext().getRealm();
|
||||||
UserModel user = session.users().getUserByUsername(username, realm);
|
UserModel user = session.users().getUserByUsername(username, realm);
|
||||||
return session.userCredentialManager().getStoredCredentialsByType(realm, user, CredentialRepresentation.PASSWORD).get(0);
|
return session.userCredentialManager().getStoredCredentialsByTypeStream(realm, user, CredentialRepresentation.PASSWORD)
|
||||||
|
.findFirst().orElse(null);
|
||||||
}, CredentialModel.class);
|
}, CredentialModel.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.keycloak.testsuite.arquillian.annotation.ModelTest;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
import static org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer.REMOTE;
|
||||||
|
|
||||||
|
@ -41,7 +42,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
RealmModel realm = currentSession.realms().getRealmByName("test");
|
RealmModel realm = currentSession.realms().getRealmByName("test");
|
||||||
|
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
Assert.assertEquals(1, list.size());
|
Assert.assertEquals(1, list.size());
|
||||||
passwordId.set(list.get(0).getId());
|
passwordId.set(list.get(0).getId());
|
||||||
|
|
||||||
|
@ -60,7 +62,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: password, otp1, otp2
|
// Assert priorities: password, otp1, otp2
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, passwordId.get(), otp1Id.get(), otp2Id.get());
|
assertOrder(list, passwordId.get(), otp1Id.get(), otp2Id.get());
|
||||||
|
|
||||||
// Assert can't move password when newPreviousCredential not found
|
// Assert can't move password when newPreviousCredential not found
|
||||||
|
@ -78,7 +81,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: password, otp2, otp1
|
// Assert priorities: password, otp2, otp1
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, passwordId.get(), otp2Id.get(), otp1Id.get());
|
assertOrder(list, passwordId.get(), otp2Id.get(), otp1Id.get());
|
||||||
|
|
||||||
// Move otp2 to the top
|
// Move otp2 to the top
|
||||||
|
@ -90,7 +94,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, password, otp1
|
// Assert priorities: otp2, password, otp1
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp2Id.get(), passwordId.get(), otp1Id.get());
|
assertOrder(list, otp2Id.get(), passwordId.get(), otp1Id.get());
|
||||||
|
|
||||||
// Move password down
|
// Move password down
|
||||||
|
@ -102,7 +107,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, otp1, password
|
// Assert priorities: otp2, otp1, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp2Id.get(), otp1Id.get(), passwordId.get());
|
assertOrder(list, otp2Id.get(), otp1Id.get(), passwordId.get());
|
||||||
|
|
||||||
// Remove otp2 down two positions
|
// Remove otp2 down two positions
|
||||||
|
@ -114,7 +120,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, otp1, password
|
// Assert priorities: otp2, otp1, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp1Id.get(), passwordId.get(), otp2Id.get());
|
assertOrder(list, otp1Id.get(), passwordId.get(), otp2Id.get());
|
||||||
|
|
||||||
// Remove password
|
// Remove password
|
||||||
|
@ -126,7 +133,8 @@ public class CredentialModelTest extends AbstractTestRealmKeycloakTest {
|
||||||
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
UserModel user = currentSession.users().getUserByUsername("test-user@localhost", realm);
|
||||||
|
|
||||||
// Assert priorities: otp2, password
|
// Assert priorities: otp2, password
|
||||||
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentials(realm, user);
|
List<CredentialModel> list = currentSession.userCredentialManager().getStoredCredentialsStream(realm, user)
|
||||||
|
.collect(Collectors.toList());
|
||||||
assertOrder(list, otp1Id.get(), otp2Id.get());
|
assertOrder(list, otp1Id.get(), otp2Id.get());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue