Convert MapUserEntity to interface
This commit is contained in:
parent
9b18688ce2
commit
9849df3757
14 changed files with 512 additions and 811 deletions
|
@ -44,6 +44,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.models.map.storage.MapStorageProvider;
|
||||
import org.keycloak.models.map.storage.MapStorageProviderFactory;
|
||||
import org.keycloak.models.map.user.MapUserConsentEntity;
|
||||
import org.keycloak.models.map.user.MapUserConsentEntityImpl;
|
||||
import org.keycloak.models.map.user.MapUserCredentialEntity;
|
||||
import org.keycloak.models.map.user.MapUserCredentialEntityImpl;
|
||||
import org.keycloak.models.map.user.MapUserEntityImpl;
|
||||
import org.keycloak.models.map.user.MapUserFederatedIdentityEntity;
|
||||
import org.keycloak.models.map.user.MapUserFederatedIdentityEntityImpl;
|
||||
import org.keycloak.models.map.storage.ModelEntityUtil;
|
||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
@ -84,6 +91,10 @@ public class ConcurrentHashMapStorageProviderFactory implements AmphibianProvide
|
|||
.constructor(MapProtocolMapperEntity.class, MapProtocolMapperEntityImpl::new)
|
||||
.constructor(MapGroupEntityImpl.class, MapGroupEntityImpl::new)
|
||||
.constructor(MapRoleEntityImpl.class, MapRoleEntityImpl::new)
|
||||
.constructor(MapUserEntityImpl.class, MapUserEntityImpl::new)
|
||||
.constructor(MapUserCredentialEntityImpl.class, MapUserCredentialEntityImpl::new)
|
||||
.constructor(MapUserFederatedIdentityEntityImpl.class, MapUserFederatedIdentityEntityImpl::new)
|
||||
.constructor(MapUserConsentEntityImpl.class, MapUserConsentEntityImpl::new)
|
||||
.build();
|
||||
|
||||
private static final Map<String, StringKeyConvertor> KEY_CONVERTORS = new HashMap<>();
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.keycloak.models.map.loginFailure.MapUserLoginFailureEntity;
|
|||
import org.keycloak.models.map.realm.MapRealmEntity;
|
||||
import org.keycloak.models.map.role.MapRoleEntity;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.user.MapUserConsentEntity;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
@ -52,7 +53,6 @@ import java.util.Map;
|
|||
import org.keycloak.models.map.storage.chm.MapModelCriteriaBuilder.UpdatePredicatesFunc;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.user.MapUserEntity;
|
||||
import org.keycloak.models.map.user.UserConsentEntity;
|
||||
import org.keycloak.models.map.userSession.MapAuthenticatedClientSessionEntity;
|
||||
import org.keycloak.models.map.userSession.MapUserSessionEntity;
|
||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||
|
@ -279,7 +279,7 @@ public class MapFieldPredicates {
|
|||
String providerId = ensureEqSingleValue(UserModel.SearchableFields.CONSENT_CLIENT_FEDERATION_LINK, "provider_id", op, values);
|
||||
String providerIdS = new StorageId((String) providerId, "").getId();
|
||||
Function<MapUserEntity, ?> getter;
|
||||
getter = ue -> ue.getUserConsents().map(UserConsentEntity::getClientId).anyMatch(v -> v != null && v.startsWith(providerIdS));
|
||||
getter = ue -> Optional.ofNullable(ue.getUserConsents()).orElseGet(Collections::emptyMap).values().stream().map(MapUserConsentEntity::getClientId).anyMatch(v -> v != null && v.startsWith(providerIdS));
|
||||
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
}
|
||||
|
@ -330,7 +330,7 @@ public class MapFieldPredicates {
|
|||
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkGrantedUserRole(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
|
||||
String roleIdS = ensureEqSingleValue(UserModel.SearchableFields.ASSIGNED_ROLE, "role_id", op, values);
|
||||
Function<MapUserEntity, ?> getter;
|
||||
getter = ue -> ue.getRolesMembership().contains(roleIdS);
|
||||
getter = ue -> Optional.ofNullable(ue.getRolesMembership()).orElseGet(Collections::emptySet).contains(roleIdS);
|
||||
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
}
|
||||
|
@ -433,10 +433,10 @@ public class MapFieldPredicates {
|
|||
Function<MapUserEntity, ?> getter;
|
||||
if (op == Operator.IN && values != null && values.length == 1 && (values[0] instanceof Collection)) {
|
||||
Collection<?> c = (Collection<?>) values[0];
|
||||
getter = ue -> ue.getGroupsMembership().stream().anyMatch(c::contains);
|
||||
getter = ue -> Optional.ofNullable(ue.getGroupsMembership()).orElseGet(Collections::emptySet).stream().anyMatch(c::contains);
|
||||
} else {
|
||||
String groupIdS = ensureEqSingleValue(UserModel.SearchableFields.ASSIGNED_GROUP, "group_id", op, values);
|
||||
getter = ue -> ue.getGroupsMembership().contains(groupIdS);
|
||||
getter = ue -> Optional.ofNullable(ue.getGroupsMembership()).orElseGet(Collections::emptySet).contains(groupIdS);
|
||||
}
|
||||
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
|
@ -453,7 +453,7 @@ public class MapFieldPredicates {
|
|||
private static MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> checkUserConsentsWithClientScope(MapModelCriteriaBuilder<Object, MapUserEntity, UserModel> mcb, Operator op, Object[] values) {
|
||||
String clientScopeIdS = ensureEqSingleValue(UserModel.SearchableFields.CONSENT_FOR_CLIENT, "client_scope_id", op, values);
|
||||
Function<MapUserEntity, ?> getter;
|
||||
getter = ue -> ue.getUserConsents().anyMatch(consent -> consent.getGrantedClientScopesIds().contains(clientScopeIdS));
|
||||
getter = ue -> Optional.ofNullable(ue.getUserConsents()).orElseGet(Collections::emptyMap).values().stream().anyMatch(consent -> Optional.ofNullable(consent.getGrantedClientScopesIds()).orElseGet(Collections::emptySet).contains(clientScopeIdS));
|
||||
|
||||
return mcb.fieldCompare(Boolean.TRUE::equals, getter);
|
||||
}
|
||||
|
@ -469,15 +469,15 @@ public class MapFieldPredicates {
|
|||
final Object idpAlias = values[0];
|
||||
Function<MapUserEntity, ?> getter;
|
||||
if (values.length == 1) {
|
||||
getter = ue -> ue.getFederatedIdentities()
|
||||
getter = ue -> Optional.ofNullable(ue.getFederatedIdentities()).orElseGet(Collections::emptyMap).values().stream()
|
||||
.anyMatch(aue -> Objects.equals(idpAlias, aue.getIdentityProvider()));
|
||||
} else if (idpAlias == null) {
|
||||
final Object idpUserId = values[1];
|
||||
getter = ue -> ue.getFederatedIdentities()
|
||||
getter = ue -> Optional.ofNullable(ue.getFederatedIdentities()).orElseGet(Collections::emptyMap).values().stream()
|
||||
.anyMatch(aue -> Objects.equals(idpUserId, aue.getUserId()));
|
||||
} else {
|
||||
final Object idpUserId = values[1];
|
||||
getter = ue -> ue.getFederatedIdentities()
|
||||
getter = ue -> Optional.ofNullable(ue.getFederatedIdentities()).orElseGet(Collections::emptyMap).values().stream()
|
||||
.anyMatch(aue -> Objects.equals(idpAlias, aue.getIdentityProvider()) && Objects.equals(idpUserId, aue.getUserId()));
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
|
@ -76,7 +77,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return entity.isEnabled();
|
||||
Boolean enabled = entity.isEnabled();
|
||||
return enabled != null && enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,19 +149,20 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
@Override
|
||||
public String getFirstAttribute(String name) {
|
||||
return getSpecialAttributeValue(name)
|
||||
.orElseGet(() -> entity.getAttribute(name).stream().findFirst()
|
||||
.orElseGet(() -> Optional.ofNullable(entity.getAttribute(name)).orElseGet(Collections::emptyList).stream().findFirst()
|
||||
.orElse(null));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> getAttributeStream(String name) {
|
||||
return getSpecialAttributeValue(name).map(Collections::singletonList)
|
||||
.orElseGet(() -> entity.getAttribute(name)).stream();
|
||||
.orElseGet(() -> Optional.ofNullable(entity.getAttribute(name)).orElseGet(Collections::emptyList)).stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
MultivaluedHashMap<String, String> result = new MultivaluedHashMap<>(entity.getAttributes());
|
||||
Map<String, List<String>> attributes = entity.getAttributes();
|
||||
MultivaluedHashMap<String, String> result = attributes == null ? new MultivaluedHashMap<>() : new MultivaluedHashMap<>(attributes);
|
||||
result.add(UserModel.FIRST_NAME, entity.getFirstName());
|
||||
result.add(UserModel.LAST_NAME, entity.getLastName());
|
||||
result.add(UserModel.EMAIL, entity.getEmail());
|
||||
|
@ -170,7 +173,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public Stream<String> getRequiredActionsStream() {
|
||||
return entity.getRequiredActions().stream();
|
||||
Set<String> requiredActions = entity.getRequiredActions();
|
||||
return requiredActions == null ? Stream.empty() : requiredActions.stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -233,7 +237,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public boolean isEmailVerified() {
|
||||
return entity.isEmailVerified();
|
||||
Boolean emailVerified = entity.isEmailVerified();
|
||||
return emailVerified != null && emailVerified;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -243,7 +248,9 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public Stream<GroupModel> getGroupsStream() {
|
||||
return session.groups().getGroupsStream(realm, entity.getGroupsMembership().stream());
|
||||
Set<String> groups = entity.getGroupsMembership();
|
||||
if (groups == null || groups.isEmpty()) return Stream.empty();
|
||||
return session.groups().getGroupsStream(realm, groups.stream());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -258,7 +265,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public boolean isMemberOf(GroupModel group) {
|
||||
return entity.getGroupsMembership().contains(group.getId());
|
||||
Set<String> groups = entity.getGroupsMembership();
|
||||
return groups != null && groups.contains(group.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -294,7 +302,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public boolean hasDirectRole(RoleModel role) {
|
||||
return entity.getRolesMembership().contains(role.getId());
|
||||
Set<String> roles = entity.getRolesMembership();
|
||||
return roles != null && entity.getRolesMembership().contains(role.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -309,6 +318,8 @@ public abstract class MapUserAdapter extends AbstractUserModel<MapUserEntity> {
|
|||
|
||||
@Override
|
||||
public Stream<RoleModel> getRoleMappingsStream() {
|
||||
Set<String> roles = entity.getRolesMembership();
|
||||
if (roles == null || roles.isEmpty()) return Stream.empty();
|
||||
return entity.getRolesMembership().stream().map(realm::getRoleById);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@GenerateEntityImplementations
|
||||
@DeepCloner.Root
|
||||
public interface MapUserConsentEntity extends UpdatableEntity {
|
||||
|
||||
public static MapUserConsentEntity fromModel(UserConsentModel model) {
|
||||
long currentTime = Time.currentTimeMillis();
|
||||
|
||||
MapUserConsentEntity consentEntity = new MapUserConsentEntityImpl();
|
||||
consentEntity.setClientId(model.getClient().getId());
|
||||
consentEntity.setCreatedDate(currentTime);
|
||||
consentEntity.setLastUpdatedDate(currentTime);
|
||||
|
||||
model.getGrantedClientScopes()
|
||||
.stream()
|
||||
.map(ClientScopeModel::getId)
|
||||
.forEach(consentEntity::addGrantedClientScopesId);
|
||||
|
||||
return consentEntity;
|
||||
}
|
||||
|
||||
public static UserConsentModel toModel(RealmModel realm, MapUserConsentEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientById(entity.getClientId());
|
||||
if (client == null) {
|
||||
throw new ModelException("Client with id " + entity.getClientId() + " is not available");
|
||||
}
|
||||
UserConsentModel model = new UserConsentModel(client);
|
||||
model.setCreatedDate(entity.getCreatedDate());
|
||||
model.setLastUpdatedDate(entity.getLastUpdatedDate());
|
||||
|
||||
|
||||
Set<String> grantedClientScopesIds = entity.getGrantedClientScopesIds();
|
||||
|
||||
if (grantedClientScopesIds != null && !grantedClientScopesIds.isEmpty()) {
|
||||
grantedClientScopesIds.stream()
|
||||
.map(scopeId -> KeycloakModelUtils.findClientScopeById(realm, client, scopeId))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(model::addGrantedClientScope);
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
String getClientId();
|
||||
void setClientId(String clientId);
|
||||
|
||||
Set<String> getGrantedClientScopesIds();
|
||||
void addGrantedClientScopesId(String scope);
|
||||
void setGrantedClientScopesIds(Set<String> scopesIds);
|
||||
void removeGrantedClientScopesId(String scopesId);
|
||||
|
||||
Long getCreatedDate();
|
||||
void setCreatedDate(Long createdDate);
|
||||
|
||||
Long getLastUpdatedDate();
|
||||
void setLastUpdatedDate(Long lastUpdatedDate);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
@GenerateEntityImplementations
|
||||
@DeepCloner.Root
|
||||
public interface MapUserCredentialEntity extends UpdatableEntity {
|
||||
|
||||
Comparator<MapUserCredentialEntity> ORDER_BY_PRIORITY = Comparator.comparing(MapUserCredentialEntity::getPriority);
|
||||
|
||||
public static MapUserCredentialEntity fromModel(CredentialModel model) {
|
||||
MapUserCredentialEntity credentialEntity = new MapUserCredentialEntityImpl();
|
||||
String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
|
||||
credentialEntity.setId(id);
|
||||
credentialEntity.setCreatedDate(model.getCreatedDate());
|
||||
credentialEntity.setUserLabel(model.getUserLabel());
|
||||
credentialEntity.setType(model.getType());
|
||||
credentialEntity.setSecretData(model.getSecretData());
|
||||
credentialEntity.setCredentialData(model.getCredentialData());
|
||||
|
||||
return credentialEntity;
|
||||
}
|
||||
|
||||
public static CredentialModel toModel(MapUserCredentialEntity entity) {
|
||||
CredentialModel model = new CredentialModel();
|
||||
model.setId(entity.getId());
|
||||
model.setType(entity.getType());
|
||||
model.setCreatedDate(entity.getCreatedDate());
|
||||
model.setUserLabel(entity.getUserLabel());
|
||||
model.setSecretData(entity.getSecretData());
|
||||
model.setCredentialData(entity.getCredentialData());
|
||||
return model;
|
||||
}
|
||||
|
||||
String getId();
|
||||
void setId(String id);
|
||||
|
||||
String getType();
|
||||
void setType(String type);
|
||||
|
||||
String getUserLabel();
|
||||
void setUserLabel(String userLabel);
|
||||
|
||||
Long getCreatedDate();
|
||||
void setCreatedDate(Long createdDate);
|
||||
|
||||
String getSecretData();
|
||||
void setSecretData(String secretData);
|
||||
|
||||
String getCredentialData();
|
||||
void setCredentialData(String credentialData);
|
||||
|
||||
Integer getPriority();
|
||||
void setPriority(Integer priority);
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
@ -17,64 +17,47 @@
|
|||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.models.ModelDuplicateException;
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
import org.keycloak.models.map.annotations.IgnoreForEntityImplementationGenerator;
|
||||
import org.keycloak.models.map.common.AbstractEntity;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.EntityWithAttributes;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mhajas
|
||||
*/
|
||||
public class MapUserEntity extends UpdatableEntity.Impl implements AbstractEntity, EntityWithAttributes {
|
||||
@GenerateEntityImplementations(
|
||||
inherits = "org.keycloak.models.map.user.MapUserEntity.AbstractUserEntity"
|
||||
)
|
||||
@DeepCloner.Root
|
||||
public interface MapUserEntity extends UpdatableEntity, AbstractEntity, EntityWithAttributes {
|
||||
|
||||
public abstract class AbstractUserEntity extends UpdatableEntity.Impl implements MapUserEntity {
|
||||
|
||||
private String id;
|
||||
private String realmId;
|
||||
|
||||
private String username;
|
||||
private String firstName;
|
||||
private Long createdTimestamp;
|
||||
private String lastName;
|
||||
private String email;
|
||||
private boolean enabled;
|
||||
private boolean emailVerified;
|
||||
// This is necessary to be able to dynamically switch unique email constraints on and off in the realm settings
|
||||
private String emailConstraint = KeycloakModelUtils.generateId();
|
||||
private Map<String, List<String>> attributes = new HashMap<>();
|
||||
private Set<String> requiredActions = new HashSet<>();
|
||||
private final Map<String, UserCredentialEntity> credentials = new HashMap<>();
|
||||
private final List<String> credentialsOrder = new LinkedList<>();
|
||||
private final Map<String, UserFederatedIdentityEntity> federatedIdentities = new HashMap<>();
|
||||
private final Map<String, UserConsentEntity> userConsents = new HashMap<>();
|
||||
private Set<String> groupsMembership = new HashSet<>();
|
||||
private Set<String> rolesMembership = new HashSet<>();
|
||||
private String federationLink;
|
||||
private String serviceAccountClientLink;
|
||||
private int notBefore;
|
||||
@Override
|
||||
public boolean isUpdated() {
|
||||
return this.updated
|
||||
|| Optional.ofNullable(getUserConsents()).orElseGet(Collections::emptyMap).values().stream().anyMatch(MapUserConsentEntity::isUpdated)
|
||||
|| Optional.ofNullable(getCredentials()).orElseGet(Collections::emptyMap).values().stream().anyMatch(MapUserCredentialEntity::isUpdated)
|
||||
|| Optional.ofNullable(getFederatedIdentities()).orElseGet(Collections::emptyMap).values().stream().anyMatch(MapUserFederatedIdentityEntity::isUpdated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag signalizing that any of the setters has been meaningfully used.
|
||||
*/
|
||||
@Override
|
||||
public void clearUpdatedFlag() {
|
||||
this.updated = false;
|
||||
Optional.ofNullable(getUserConsents()).orElseGet(Collections::emptyMap).values().forEach(UpdatableEntity::clearUpdatedFlag);
|
||||
Optional.ofNullable(getCredentials()).orElseGet(Collections::emptyMap).values().forEach(UpdatableEntity::clearUpdatedFlag);
|
||||
Optional.ofNullable(getFederatedIdentities()).orElseGet(Collections::emptyMap).values().forEach(UpdatableEntity::clearUpdatedFlag);
|
||||
|
||||
public MapUserEntity() {}
|
||||
|
||||
public MapUserEntity(String id, String realmId) {
|
||||
this.id = id;
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -90,290 +73,84 @@ public class MapUserEntity extends UpdatableEntity.Impl implements AbstractEntit
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isUpdated() {
|
||||
return this.updated
|
||||
|| userConsents.values().stream().anyMatch(UserConsentEntity::isUpdated)
|
||||
|| credentials.values().stream().anyMatch(UserCredentialEntity::isUpdated)
|
||||
|| federatedIdentities.values().stream().anyMatch(UserFederatedIdentityEntity::isUpdated);
|
||||
}
|
||||
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.updated |= !Objects.equals(this.realmId, realmId);
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.updated |= !Objects.equals(this.username, username);
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.updated |= !Objects.equals(this.firstName, firstName);
|
||||
this.firstName = firstName;
|
||||
}
|
||||
|
||||
public Long getCreatedTimestamp() {
|
||||
return createdTimestamp;
|
||||
}
|
||||
|
||||
public void setCreatedTimestamp(Long createdTimestamp) {
|
||||
this.updated |= !Objects.equals(this.createdTimestamp, createdTimestamp);
|
||||
this.createdTimestamp = createdTimestamp;
|
||||
}
|
||||
|
||||
public String getLastName() {
|
||||
return lastName;
|
||||
}
|
||||
|
||||
public void setLastName(String lastName) {
|
||||
this.updated |= !Objects.equals(this.lastName, lastName);
|
||||
this.lastName = lastName;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email, boolean duplicateEmailsAllowed) {
|
||||
this.updated |= !Objects.equals(this.email, email);
|
||||
this.email = email;
|
||||
this.emailConstraint = email == null || duplicateEmailsAllowed ? KeycloakModelUtils.generateId() : email;
|
||||
this.setEmail(email);
|
||||
this.setEmailConstraint(email == null || duplicateEmailsAllowed ? KeycloakModelUtils.generateId() : email);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
String getRealmId();
|
||||
void setRealmId(String realmId);
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.updated |= !Objects.equals(this.enabled, enabled);
|
||||
this.enabled = enabled;
|
||||
}
|
||||
String getUsername();
|
||||
void setUsername(String username);
|
||||
|
||||
public boolean isEmailVerified() {
|
||||
return emailVerified;
|
||||
}
|
||||
String getFirstName();
|
||||
void setFirstName(String firstName);
|
||||
|
||||
public void setEmailVerified(boolean emailVerified) {
|
||||
this.updated |= !Objects.equals(this.emailVerified, emailVerified);
|
||||
this.emailVerified = emailVerified;
|
||||
}
|
||||
Long getCreatedTimestamp();
|
||||
void setCreatedTimestamp(Long createdTimestamp);
|
||||
|
||||
public String getEmailConstraint() {
|
||||
return emailConstraint;
|
||||
}
|
||||
String getLastName();
|
||||
void setLastName(String lastName);
|
||||
|
||||
public void setEmailConstraint(String emailConstraint) {
|
||||
this.updated |= !Objects.equals(this.emailConstraint, emailConstraint);
|
||||
this.emailConstraint = emailConstraint;
|
||||
}
|
||||
String getEmail();
|
||||
void setEmail(String email);
|
||||
@IgnoreForEntityImplementationGenerator
|
||||
void setEmail(String email, boolean duplicateEmailsAllowed);
|
||||
|
||||
public Map<String, List<String>> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
Boolean isEnabled();
|
||||
void setEnabled(Boolean enabled);
|
||||
|
||||
@Override
|
||||
public List<String> getAttribute(String name) {
|
||||
return attributes.getOrDefault(name, Collections.emptyList());
|
||||
}
|
||||
Boolean isEmailVerified();
|
||||
void setEmailVerified(Boolean emailVerified);
|
||||
|
||||
@Override
|
||||
public void setAttributes(Map<String, List<String>> attributes) {
|
||||
this.updated |= !Objects.equals(this.attributes, attributes);
|
||||
this.attributes = attributes;
|
||||
}
|
||||
String getEmailConstraint();
|
||||
void setEmailConstraint(String emailConstraint);
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, List<String> value) {
|
||||
this.updated |= !Objects.equals(this.attributes.put(name, value), value);
|
||||
}
|
||||
Map<String, List<String>> getAttributes();
|
||||
List<String> getAttribute(String name);
|
||||
void setAttributes(Map<String, List<String>> attributes);
|
||||
void setAttribute(String name, List<String> value);
|
||||
void removeAttribute(String name);
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name) {
|
||||
this.updated |= this.attributes.remove(name) != null;
|
||||
}
|
||||
Set<String> getRequiredActions();
|
||||
void setRequiredActions(Set<String> requiredActions);
|
||||
void addRequiredAction(String requiredAction);
|
||||
void removeRequiredAction(String requiredAction);
|
||||
|
||||
public Set<String> getRequiredActions() {
|
||||
return requiredActions;
|
||||
}
|
||||
Map<String, MapUserCredentialEntity> getCredentials();
|
||||
void setCredential(String id, MapUserCredentialEntity credentialEntity);
|
||||
Boolean removeCredential(String credentialId);
|
||||
MapUserCredentialEntity getCredential(String id);
|
||||
|
||||
public void setRequiredActions(Set<String> requiredActions) {
|
||||
this.updated |= !Objects.equals(this.requiredActions, requiredActions);
|
||||
this.requiredActions = requiredActions;
|
||||
}
|
||||
Map<String, MapUserFederatedIdentityEntity> getFederatedIdentities();
|
||||
void setFederatedIdentities(Map<String, MapUserFederatedIdentityEntity> federatedIdentities);
|
||||
void setFederatedIdentity(String id, MapUserFederatedIdentityEntity federatedIdentity);
|
||||
MapUserFederatedIdentityEntity getFederatedIdentity(String federatedIdentity);
|
||||
Boolean removeFederatedIdentity(String providerId);
|
||||
|
||||
public void addRequiredAction(String requiredAction) {
|
||||
this.updated |= this.requiredActions.add(requiredAction);
|
||||
}
|
||||
Map<String, MapUserConsentEntity> getUserConsents();
|
||||
MapUserConsentEntity getUserConsent(String clientId);
|
||||
void setUserConsent(String id, MapUserConsentEntity userConsentEntity);
|
||||
Boolean removeUserConsent(String clientId);
|
||||
|
||||
public void removeRequiredAction(String requiredAction) {
|
||||
this.updated |= this.requiredActions.remove(requiredAction);
|
||||
}
|
||||
Set<String> getGroupsMembership();
|
||||
void setGroupsMembership(Set<String> groupsMembership);
|
||||
void addGroupsMembership(String groupId);
|
||||
void removeGroupsMembership(String groupId);
|
||||
|
||||
public void updateCredential(UserCredentialEntity credentialEntity) {
|
||||
this.updated |= credentials.replace(credentialEntity.getId(), credentialEntity) != null;
|
||||
}
|
||||
Set<String> getRolesMembership();
|
||||
void setRolesMembership(Set<String> rolesMembership);
|
||||
void addRolesMembership(String roleId);
|
||||
void removeRolesMembership(String roleId);
|
||||
|
||||
public void addCredential(UserCredentialEntity credentialEntity) {
|
||||
if (credentials.containsKey(credentialEntity.getId())) {
|
||||
throw new ModelDuplicateException("A CredentialModel with given id already exists");
|
||||
}
|
||||
String getFederationLink();
|
||||
void setFederationLink(String federationLink);
|
||||
|
||||
this.updated = true;
|
||||
credentials.put(credentialEntity.getId(), credentialEntity);
|
||||
credentialsOrder.add(credentialEntity.getId());
|
||||
}
|
||||
|
||||
public boolean removeCredential(String credentialId) {
|
||||
if (!credentials.containsKey(credentialId)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.updated = true;
|
||||
this.credentials.remove(credentialId);
|
||||
this.credentialsOrder.remove(credentialId);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public UserCredentialEntity getCredential(String id) {
|
||||
return credentials.get(id);
|
||||
}
|
||||
|
||||
public Stream<UserCredentialEntity> getCredentials() {
|
||||
return credentialsOrder.stream()
|
||||
.map(credentials::get);
|
||||
}
|
||||
|
||||
public int getCredentialIndex(String credentialId) {
|
||||
return credentialsOrder.indexOf(credentialId);
|
||||
}
|
||||
|
||||
public void moveCredential(int currentPosition, int newPosition) {
|
||||
this.updated |= currentPosition != newPosition;
|
||||
credentialsOrder.add(newPosition, credentialsOrder.remove(currentPosition));
|
||||
}
|
||||
|
||||
public Stream<UserFederatedIdentityEntity> getFederatedIdentities() {
|
||||
return federatedIdentities.values().stream();
|
||||
}
|
||||
|
||||
public void setFederatedIdentities(Collection<UserFederatedIdentityEntity> federatedIdentities) {
|
||||
this.updated = true;
|
||||
this.federatedIdentities.clear();
|
||||
this.federatedIdentities.putAll(federatedIdentities.stream()
|
||||
.collect(Collectors.toMap(UserFederatedIdentityEntity::getIdentityProvider, Function.identity())));
|
||||
}
|
||||
|
||||
public void addFederatedIdentity(UserFederatedIdentityEntity federatedIdentity) {
|
||||
String idpId = federatedIdentity.getIdentityProvider();
|
||||
this.updated |= !Objects.equals(this.federatedIdentities.put(idpId, federatedIdentity), federatedIdentity);
|
||||
}
|
||||
|
||||
public UserFederatedIdentityEntity getFederatedIdentity(String federatedIdentity) {
|
||||
return this.federatedIdentities.get(federatedIdentity);
|
||||
}
|
||||
|
||||
public boolean removeFederatedIdentity(String providerId) {
|
||||
boolean removed = federatedIdentities.remove(providerId) != null;
|
||||
this.updated |= removed;
|
||||
return removed;
|
||||
}
|
||||
|
||||
public void updateFederatedIdentity(UserFederatedIdentityEntity federatedIdentityModel) {
|
||||
this.updated |= federatedIdentities.replace(federatedIdentityModel.getIdentityProvider(), federatedIdentityModel) != null;
|
||||
}
|
||||
|
||||
public Stream<UserConsentEntity> getUserConsents() {
|
||||
return userConsents.values().stream();
|
||||
}
|
||||
|
||||
public UserConsentEntity getUserConsent(String clientId) {
|
||||
return this.userConsents.get(clientId);
|
||||
}
|
||||
|
||||
|
||||
public void addUserConsent(UserConsentEntity userConsentEntity) {
|
||||
String clientId = userConsentEntity.getClientId();
|
||||
this.updated |= !Objects.equals(this.userConsents.put(clientId, userConsentEntity), userConsentEntity);
|
||||
}
|
||||
|
||||
public boolean removeUserConsent(String clientId) {
|
||||
boolean removed = userConsents.remove(clientId) != null;
|
||||
this.updated |= removed;
|
||||
return removed;
|
||||
}
|
||||
|
||||
public Set<String> getGroupsMembership() {
|
||||
return groupsMembership;
|
||||
}
|
||||
|
||||
public void setGroupsMembership(Set<String> groupsMembership) {
|
||||
this.updated |= Objects.equals(groupsMembership, this.groupsMembership);
|
||||
this.groupsMembership = groupsMembership;
|
||||
}
|
||||
|
||||
public void addGroupsMembership(String groupId) {
|
||||
this.updated |= this.groupsMembership.add(groupId);
|
||||
}
|
||||
|
||||
public void removeGroupsMembership(String groupId) {
|
||||
this.updated |= this.groupsMembership.remove(groupId);
|
||||
}
|
||||
|
||||
public Set<String> getRolesMembership() {
|
||||
return rolesMembership;
|
||||
}
|
||||
|
||||
public void setRolesMembership(Set<String> rolesMembership) {
|
||||
this.updated |= Objects.equals(rolesMembership, this.rolesMembership);
|
||||
this.rolesMembership = rolesMembership;
|
||||
}
|
||||
|
||||
public void addRolesMembership(String roleId) {
|
||||
this.updated |= this.rolesMembership.add(roleId);
|
||||
}
|
||||
|
||||
public void removeRolesMembership(String roleId) {
|
||||
this.updated |= this.rolesMembership.remove(roleId);
|
||||
}
|
||||
|
||||
public String getFederationLink() {
|
||||
return federationLink;
|
||||
}
|
||||
|
||||
public void setFederationLink(String federationLink) {
|
||||
this.updated |= !Objects.equals(this.federationLink, federationLink);
|
||||
this.federationLink = federationLink;
|
||||
}
|
||||
|
||||
public String getServiceAccountClientLink() {
|
||||
return serviceAccountClientLink;
|
||||
}
|
||||
|
||||
public void setServiceAccountClientLink(String serviceAccountClientLink) {
|
||||
this.updated |= !Objects.equals(this.serviceAccountClientLink, serviceAccountClientLink);
|
||||
this.serviceAccountClientLink = serviceAccountClientLink;
|
||||
}
|
||||
|
||||
public int getNotBefore() {
|
||||
return notBefore;
|
||||
}
|
||||
|
||||
public void setNotBefore(int notBefore) {
|
||||
this.updated |= !Objects.equals(this.notBefore, notBefore);
|
||||
this.notBefore = notBefore;
|
||||
}
|
||||
String getServiceAccountClientLink();
|
||||
void setServiceAccountClientLink(String serviceAccountClientLink);
|
||||
|
||||
Integer getNotBefore();
|
||||
void setNotBefore(Integer notBefore);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2021 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.map.annotations.GenerateEntityImplementations;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
|
||||
@GenerateEntityImplementations
|
||||
@DeepCloner.Root
|
||||
public interface MapUserFederatedIdentityEntity extends UpdatableEntity {
|
||||
|
||||
public static MapUserFederatedIdentityEntity fromModel(FederatedIdentityModel model) {
|
||||
if (model == null) return null;
|
||||
MapUserFederatedIdentityEntity entity = new MapUserFederatedIdentityEntityImpl();
|
||||
entity.setIdentityProvider(model.getIdentityProvider());
|
||||
entity.setUserId(model.getUserId());
|
||||
entity.setUserName(model.getUserName().toLowerCase());
|
||||
entity.setToken(model.getToken());
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static FederatedIdentityModel toModel(MapUserFederatedIdentityEntity entity) {
|
||||
if (entity == null) return null;
|
||||
return new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken());
|
||||
}
|
||||
|
||||
String getToken();
|
||||
void setToken(String token);
|
||||
|
||||
String getUserId();
|
||||
void setUserId(String userId);
|
||||
|
||||
String getIdentityProvider();
|
||||
void setIdentityProvider(String identityProvider);
|
||||
|
||||
String getUserName();
|
||||
void setUserName(String userName);
|
||||
}
|
|
@ -45,13 +45,17 @@ import org.keycloak.models.map.storage.MapKeycloakTransaction;
|
|||
import org.keycloak.models.map.storage.MapStorage;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder.Operator;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.storage.StorageId;
|
||||
import org.keycloak.storage.UserStorageProvider;
|
||||
import org.keycloak.storage.client.ClientStorageProvider;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -75,6 +79,8 @@ import static org.keycloak.models.map.storage.criteria.DefaultModelCriteria.crit
|
|||
|
||||
public class MapUserProvider implements UserProvider.Streams, UserCredentialStore.Streams {
|
||||
|
||||
// Typical priority difference between 2 credentials
|
||||
public static final int PRIORITY_DIFFERENCE = 10;
|
||||
private static final Logger LOG = Logger.getLogger(MapUserProvider.class);
|
||||
private final KeycloakSession session;
|
||||
final MapKeycloakTransaction<MapUserEntity, UserModel> tx;
|
||||
|
@ -139,15 +145,18 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
|
||||
getEntityById(realm, user.getId())
|
||||
.ifPresent(userEntity ->
|
||||
userEntity.addFederatedIdentity(UserFederatedIdentityEntity.fromModel(socialLink)));
|
||||
userEntity.setFederatedIdentity(socialLink.getIdentityProvider(), MapUserFederatedIdentityEntity.fromModel(socialLink)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider) {
|
||||
LOG.tracef("removeFederatedIdentity(%s, %s, %s)%s", realm, user.getId(), socialProvider, getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(entity -> entity.removeFederatedIdentity(socialProvider))
|
||||
.orElse(false);
|
||||
|
||||
Optional<MapUserEntity> entityById = getEntityById(realm, user.getId());
|
||||
if (!entityById.isPresent()) return false;
|
||||
|
||||
Boolean result = entityById.get().removeFederatedIdentity(socialProvider);
|
||||
return result == null ? true : result; // TODO: make removeFederatedIdentity return Boolean so the caller can correctly handle "I don't know" null answer
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -166,15 +175,18 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
|
||||
LOG.tracef("updateFederatedIdentity(%s, %s, %s)%s", realm, federatedUser.getId(), federatedIdentityModel.getIdentityProvider(), getShortStackTrace());
|
||||
getEntityById(realm, federatedUser.getId())
|
||||
.ifPresent(entity -> entity.updateFederatedIdentity(UserFederatedIdentityEntity.fromModel(federatedIdentityModel)));
|
||||
.ifPresent(entity -> entity.setFederatedIdentity(federatedIdentityModel.getIdentityProvider(), MapUserFederatedIdentityEntity.fromModel(federatedIdentityModel)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<FederatedIdentityModel> getFederatedIdentitiesStream(RealmModel realm, UserModel user) {
|
||||
LOG.tracef("getFederatedIdentitiesStream(%s, %s)%s", realm, user.getId(), getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(MapUserEntity::getFederatedIdentities).orElseGet(Stream::empty)
|
||||
.map(UserFederatedIdentityEntity::toModel);
|
||||
.map(MapUserEntity::getFederatedIdentities)
|
||||
.map(Map::values)
|
||||
.map(Collection::stream)
|
||||
.orElseGet(Stream::empty)
|
||||
.map(MapUserFederatedIdentityEntity::toModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -182,7 +194,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("getFederatedIdentity(%s, %s, %s)%s", realm, user.getId(), socialProvider, getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(userEntity -> userEntity.getFederatedIdentity(socialProvider))
|
||||
.map(UserFederatedIdentityEntity::toModel)
|
||||
.map(MapUserFederatedIdentityEntity::toModel)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -213,7 +225,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("addConsent(%s, %s, %s)%s", realm, userId, consent, getShortStackTrace());
|
||||
|
||||
getEntityByIdOrThrow(realm, userId)
|
||||
.addUserConsent(UserConsentEntity.fromModel(consent));
|
||||
.setUserConsent(consent.getClient().getId(), MapUserConsentEntity.fromModel(consent));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -221,7 +233,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("getConsentByClient(%s, %s, %s)%s", realm, userId, clientInternalId, getShortStackTrace());
|
||||
return getEntityById(realm, userId)
|
||||
.map(userEntity -> userEntity.getUserConsent(clientInternalId))
|
||||
.map(consent -> UserConsentEntity.toModel(realm, consent))
|
||||
.map(consent -> MapUserConsentEntity.toModel(realm, consent))
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
|
@ -230,8 +242,10 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("getConsentByClientStream(%s, %s)%s", realm, userId, getShortStackTrace());
|
||||
return getEntityById(realm, userId)
|
||||
.map(MapUserEntity::getUserConsents)
|
||||
.map(Map::values)
|
||||
.map(Collection::stream)
|
||||
.orElse(Stream.empty())
|
||||
.map(consent -> UserConsentEntity.toModel(realm, consent));
|
||||
.map(consent -> MapUserConsentEntity.toModel(realm, consent));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -239,7 +253,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("updateConsent(%s, %s, %s)%s", realm, userId, consent, getShortStackTrace());
|
||||
|
||||
MapUserEntity user = getEntityByIdOrThrow(realm, userId);
|
||||
UserConsentEntity userConsentEntity = user.getUserConsent(consent.getClient().getId());
|
||||
MapUserConsentEntity userConsentEntity = user.getUserConsent(consent.getClient().getId());
|
||||
if (userConsentEntity == null) {
|
||||
throw new ModelException("Consent not found for client [" + consent.getClient().getId() + "] and user [" + userId + "]");
|
||||
}
|
||||
|
@ -256,9 +270,12 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
@Override
|
||||
public boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId) {
|
||||
LOG.tracef("revokeConsentForClient(%s, %s, %s)%s", realm, userId, clientInternalId, getShortStackTrace());
|
||||
return getEntityById(realm, userId)
|
||||
.map(userEntity -> userEntity.removeUserConsent(clientInternalId))
|
||||
.orElse(false);
|
||||
|
||||
Optional<MapUserEntity> entityById = getEntityById(realm, userId);
|
||||
if (!entityById.isPresent()) return false;
|
||||
|
||||
Boolean result = entityById.get().removeUserConsent(clientInternalId);
|
||||
return result == null ? true : result; // TODO: make revokeConsentForClient return Boolean so the caller can correctly handle "I don't know" null answer
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -270,9 +287,11 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
@Override
|
||||
public int getNotBeforeOfUser(RealmModel realm, UserModel user) {
|
||||
LOG.tracef("getNotBeforeOfUser(%s, %s)%s", realm, user.getId(), getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
Integer notBefore = getEntityById(realm, user.getId())
|
||||
.orElseThrow(this::userDoesntExistException)
|
||||
.getNotBefore();
|
||||
|
||||
return notBefore == null ? 0 : notBefore;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -313,7 +332,10 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
throw new ModelDuplicateException("User exists: " + id);
|
||||
}
|
||||
|
||||
MapUserEntity entity = new MapUserEntity(id, realm.getId());
|
||||
MapUserEntity entity = new MapUserEntityImpl();
|
||||
entity.setId(id);
|
||||
entity.setRealmId(realm.getId());
|
||||
entity.setEmailConstraint(KeycloakModelUtils.generateId());
|
||||
entity.setUsername(username.toLowerCase());
|
||||
entity.setCreatedTimestamp(Time.currentTimeMillis());
|
||||
|
||||
|
@ -423,8 +445,11 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
.compare(SearchableFields.CONSENT_WITH_CLIENT_SCOPE, Operator.EQ, clientScopeId);
|
||||
|
||||
try (Stream<MapUserEntity> s = tx.read(withCriteria(mcb))) {
|
||||
s.flatMap(MapUserEntity::getUserConsents)
|
||||
.forEach(consent -> consent.removeGrantedClientScopesIds(clientScopeId));
|
||||
s.map(MapUserEntity::getUserConsents)
|
||||
.filter(Objects::nonNull)
|
||||
.map(Map::values)
|
||||
.flatMap(Collection::stream)
|
||||
.forEach(consent -> consent.removeGrantedClientScopesId(clientScopeId));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -449,8 +474,10 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
|
||||
private Consumer<MapUserEntity> removeConsentsForExternalClient(String idPrefix) {
|
||||
return userEntity -> {
|
||||
List<String> consentClientIds = userEntity.getUserConsents()
|
||||
.map(UserConsentEntity::getClientId)
|
||||
Map<String, MapUserConsentEntity> userConsents = userEntity.getUserConsents();
|
||||
if (userConsents == null || userConsents.isEmpty()) return;
|
||||
List<String> consentClientIds = userConsents.values().stream()
|
||||
.map(MapUserConsentEntity::getClientId)
|
||||
.filter(clientId -> clientId != null && clientId.startsWith(idPrefix))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
|
@ -730,7 +757,7 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
|
||||
private Consumer<MapUserEntity> updateCredential(CredentialModel credentialModel) {
|
||||
return user -> {
|
||||
UserCredentialEntity credentialEntity = user.getCredential(credentialModel.getId());
|
||||
MapUserCredentialEntity credentialEntity = user.getCredential(credentialModel.getId());
|
||||
if (credentialEntity == null) return;
|
||||
|
||||
credentialEntity.setCreatedDate(credentialModel.getCreatedDate());
|
||||
|
@ -744,20 +771,35 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
@Override
|
||||
public CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred) {
|
||||
LOG.tracef("createCredential(%s, %s, %s)%s", realm, user.getId(), cred.getId(), getShortStackTrace());
|
||||
UserCredentialEntity credentialEntity = UserCredentialEntity.fromModel(cred);
|
||||
MapUserEntity userEntity = getEntityByIdOrThrow(realm, user.getId());
|
||||
MapUserCredentialEntity credentialEntity = MapUserCredentialEntity.fromModel(cred);
|
||||
|
||||
getEntityByIdOrThrow(realm, user.getId())
|
||||
.addCredential(credentialEntity);
|
||||
if (userEntity.getCredential(cred.getId()) != null) {
|
||||
throw new ModelDuplicateException("A CredentialModel with given id already exists");
|
||||
}
|
||||
|
||||
return UserCredentialEntity.toModel(credentialEntity);
|
||||
Map<String, MapUserCredentialEntity> credentials = userEntity.getCredentials();
|
||||
int priority = PRIORITY_DIFFERENCE;
|
||||
|
||||
if (credentials != null && !credentials.isEmpty()) {
|
||||
priority = credentials.values().stream().max(MapUserCredentialEntity.ORDER_BY_PRIORITY).map(MapUserCredentialEntity::getPriority).orElse(0) + PRIORITY_DIFFERENCE;
|
||||
}
|
||||
|
||||
credentialEntity.setPriority(priority);
|
||||
userEntity.setCredential(credentialEntity.getId(), credentialEntity);
|
||||
|
||||
return MapUserCredentialEntity.toModel(credentialEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeStoredCredential(RealmModel realm, UserModel user, String id) {
|
||||
LOG.tracef("removeStoredCredential(%s, %s, %s)%s", realm, user.getId(), id, getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(mapUserEntity -> mapUserEntity.removeCredential(id))
|
||||
.orElse(false);
|
||||
|
||||
Optional<MapUserEntity> entityById = getEntityById(realm, user.getId());
|
||||
if (!entityById.isPresent()) return false;
|
||||
|
||||
Boolean result = entityById.get().removeCredential(id);
|
||||
return result == null ? true : result; // TODO: make removeStoredCredential return Boolean so the caller can correctly handle "I don't know" null answer
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -765,17 +807,21 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
LOG.tracef("getStoredCredentialById(%s, %s, %s)%s", realm, user.getId(), id, getShortStackTrace());
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(mapUserEntity -> mapUserEntity.getCredential(id))
|
||||
.map(UserCredentialEntity::toModel)
|
||||
.map(MapUserCredentialEntity::toModel)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<CredentialModel> getStoredCredentialsStream(RealmModel realm, UserModel user) {
|
||||
LOG.tracef("getStoredCredentialsStream(%s, %s)%s", realm, user.getId(), getShortStackTrace());
|
||||
|
||||
return getEntityById(realm, user.getId())
|
||||
.map(MapUserEntity::getCredentials)
|
||||
.map(Map::values)
|
||||
.map(Collection::stream)
|
||||
.orElseGet(Stream::empty)
|
||||
.map(UserCredentialEntity::toModel);
|
||||
.sorted(MapUserCredentialEntity.ORDER_BY_PRIORITY)
|
||||
.map(MapUserCredentialEntity::toModel);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -795,38 +841,59 @@ public class MapUserProvider implements UserProvider.Streams, UserCredentialStor
|
|||
|
||||
@Override
|
||||
public boolean moveCredentialTo(RealmModel realm, UserModel user, String id, String newPreviousCredentialId) {
|
||||
LOG.tracef("moveCredentialTo(%s, %s, %s, %s)%s", realm, user.getId(), id, newPreviousCredentialId, getShortStackTrace());
|
||||
String userId = user.getId();
|
||||
MapUserEntity userEntity = getEntityById(realm, userId).orElse(null);
|
||||
if (userEntity == null) {
|
||||
LOG.warnf("User with id: [%s] not found", userId);
|
||||
|
||||
MapUserEntity userEntity = getEntityByIdOrThrow(realm, user.getId());
|
||||
|
||||
// 1 - Create new list and move everything to it.
|
||||
Map<String, MapUserCredentialEntity> credentialEntityMap = userEntity.getCredentials();
|
||||
List<MapUserCredentialEntity> newList = credentialEntityMap == null ? new LinkedList<>()
|
||||
: credentialEntityMap.values().stream()
|
||||
.sorted(MapUserCredentialEntity.ORDER_BY_PRIORITY)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 2 - Find indexes of our and newPrevious credential
|
||||
int ourCredentialIndex = -1;
|
||||
int newPreviousCredentialIndex = -1;
|
||||
MapUserCredentialEntity ourCredential = null;
|
||||
int i = 0;
|
||||
for (MapUserCredentialEntity credential : newList) {
|
||||
if (id.equals(credential.getId())) {
|
||||
ourCredentialIndex = i;
|
||||
ourCredential = credential;
|
||||
} else if(newPreviousCredentialId != null && newPreviousCredentialId.equals(credential.getId())) {
|
||||
newPreviousCredentialIndex = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (ourCredentialIndex == -1) {
|
||||
LOG.warnf("Not found credential with id [%s] of user [%s]", id, user.getUsername());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find index of credential which should be before id in the list
|
||||
int newPreviousCredentialIdIndex = -1; // If newPreviousCredentialId == null we need to put id credential to index 0
|
||||
if (newPreviousCredentialId != null) {
|
||||
newPreviousCredentialIdIndex = userEntity.getCredentialIndex(newPreviousCredentialId);
|
||||
if (newPreviousCredentialIdIndex == -1) { // If not null previous credential not found, print warning and return false
|
||||
LOG.warnf("Credential with id: [%s] for user: [%s] not found", newPreviousCredentialId, userId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Find current index of credential (id) which will be moved
|
||||
int currentPositionOfId = userEntity.getCredentialIndex(id);
|
||||
if (currentPositionOfId == -1) {
|
||||
LOG.warnf("Credential with id: [%s] for user: [%s] not found", id, userId);
|
||||
if (newPreviousCredentialId != null && newPreviousCredentialIndex == -1) {
|
||||
LOG.warnf("Can't move up credential with id [%s] of user [%s]", id, user.getUsername());
|
||||
return false;
|
||||
}
|
||||
|
||||
// If id is before newPreviousCredentialId in priority list, it will be moved to position -1
|
||||
if (currentPositionOfId < newPreviousCredentialIdIndex) {
|
||||
newPreviousCredentialIdIndex -= 1;
|
||||
}
|
||||
// 3 - Compute index where we move our credential
|
||||
int toMoveIndex = newPreviousCredentialId==null ? 0 : newPreviousCredentialIndex + 1;
|
||||
|
||||
// Move credential to desired index
|
||||
userEntity.moveCredential(currentPositionOfId, newPreviousCredentialIdIndex + 1);
|
||||
// 4 - Insert our credential to new position, remove it from the old position
|
||||
newList.add(toMoveIndex, ourCredential);
|
||||
int indexToRemove = toMoveIndex < ourCredentialIndex ? ourCredentialIndex + 1 : ourCredentialIndex;
|
||||
newList.remove(indexToRemove);
|
||||
|
||||
// 5 - newList contains credentials in requested order now. Iterate through whole list and change priorities accordingly.
|
||||
int expectedPriority = 0;
|
||||
for (MapUserCredentialEntity credential : newList) {
|
||||
expectedPriority += PRIORITY_DIFFERENCE;
|
||||
if (credential.getPriority() != expectedPriority) {
|
||||
credential.setPriority(expectedPriority);
|
||||
|
||||
LOG.tracef("Priority of credential [%s] of user [%s] changed to [%d]", credential.getId(), user.getUsername(), expectedPriority);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,124 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.ModelException;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserConsentModel;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
|
||||
public class UserConsentEntity extends UpdatableEntity.Impl {
|
||||
|
||||
private String clientId;
|
||||
private final Set<String> grantedClientScopesIds = new HashSet<>();
|
||||
private Long createdDate;
|
||||
private Long lastUpdatedDate;
|
||||
|
||||
private UserConsentEntity() {}
|
||||
|
||||
public static UserConsentEntity fromModel(UserConsentModel model) {
|
||||
long currentTime = Time.currentTimeMillis();
|
||||
|
||||
UserConsentEntity consentEntity = new UserConsentEntity();
|
||||
consentEntity.setClientId(model.getClient().getId());
|
||||
consentEntity.setCreatedDate(currentTime);
|
||||
consentEntity.setLastUpdatedDate(currentTime);
|
||||
|
||||
model.getGrantedClientScopes()
|
||||
.stream()
|
||||
.map(ClientScopeModel::getId)
|
||||
.forEach(consentEntity::addGrantedClientScopeId);
|
||||
|
||||
return consentEntity;
|
||||
}
|
||||
|
||||
public static UserConsentModel toModel(RealmModel realm, UserConsentEntity entity) {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ClientModel client = realm.getClientById(entity.getClientId());
|
||||
if (client == null) {
|
||||
throw new ModelException("Client with id " + entity.getClientId() + " is not available");
|
||||
}
|
||||
UserConsentModel model = new UserConsentModel(client);
|
||||
model.setCreatedDate(entity.getCreatedDate());
|
||||
model.setLastUpdatedDate(entity.getLastUpdatedDate());
|
||||
|
||||
entity.getGrantedClientScopesIds().stream()
|
||||
.map(scopeId -> KeycloakModelUtils.findClientScopeById(realm, client, scopeId))
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(model::addGrantedClientScope);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.updated = !Objects.equals(this.clientId, clientId);
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public Set<String> getGrantedClientScopesIds() {
|
||||
return grantedClientScopesIds;
|
||||
}
|
||||
|
||||
public void addGrantedClientScopeId(String scope) {
|
||||
this.updated |= grantedClientScopesIds.add(scope);
|
||||
}
|
||||
|
||||
public void setGrantedClientScopesIds(Set<String> scopesIds) {
|
||||
this.updated |= !Objects.equals(grantedClientScopesIds, scopesIds);
|
||||
this.grantedClientScopesIds.clear();
|
||||
this.grantedClientScopesIds.addAll(scopesIds);
|
||||
}
|
||||
|
||||
public void removeGrantedClientScopesIds(String scopesId) {
|
||||
this.updated |= this.grantedClientScopesIds.remove(scopesId);
|
||||
}
|
||||
|
||||
public Long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(Long createdDate) {
|
||||
this.updated |= !Objects.equals(this.createdDate, createdDate);
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public Long getLastUpdatedDate() {
|
||||
return lastUpdatedDate;
|
||||
}
|
||||
|
||||
public void setLastUpdatedDate(Long lastUpdatedDate) {
|
||||
this.updated |= !Objects.equals(this.lastUpdatedDate, lastUpdatedDate);
|
||||
this.lastUpdatedDate = lastUpdatedDate;
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class UserCredentialEntity extends UpdatableEntity.Impl {
|
||||
|
||||
private String id;
|
||||
private String type;
|
||||
private String userLabel;
|
||||
private Long createdDate;
|
||||
private String secretData;
|
||||
private String credentialData;
|
||||
|
||||
UserCredentialEntity() {}
|
||||
|
||||
public static UserCredentialEntity fromModel(CredentialModel model) {
|
||||
UserCredentialEntity credentialEntity = new UserCredentialEntity();
|
||||
String id = model.getId() == null ? KeycloakModelUtils.generateId() : model.getId();
|
||||
credentialEntity.setId(id);
|
||||
credentialEntity.setCreatedDate(model.getCreatedDate());
|
||||
credentialEntity.setUserLabel(model.getUserLabel());
|
||||
credentialEntity.setType(model.getType());
|
||||
credentialEntity.setSecretData(model.getSecretData());
|
||||
credentialEntity.setCredentialData(model.getCredentialData());
|
||||
|
||||
return credentialEntity;
|
||||
}
|
||||
|
||||
public static CredentialModel toModel(UserCredentialEntity entity) {
|
||||
CredentialModel model = new CredentialModel();
|
||||
model.setId(entity.getId());
|
||||
model.setType(entity.getType());
|
||||
model.setCreatedDate(entity.getCreatedDate());
|
||||
model.setUserLabel(entity.getUserLabel());
|
||||
model.setSecretData(entity.getSecretData());
|
||||
model.setCredentialData(entity.getCredentialData());
|
||||
return model;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.updated |= !Objects.equals(this.id, id);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.updated |= !Objects.equals(this.type, type);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getUserLabel() {
|
||||
return userLabel;
|
||||
}
|
||||
|
||||
public void setUserLabel(String userLabel) {
|
||||
this.updated |= !Objects.equals(this.userLabel, userLabel);
|
||||
this.userLabel = userLabel;
|
||||
}
|
||||
|
||||
public Long getCreatedDate() {
|
||||
return createdDate;
|
||||
}
|
||||
|
||||
public void setCreatedDate(Long createdDate) {
|
||||
this.updated |= !Objects.equals(this.createdDate, createdDate);
|
||||
this.createdDate = createdDate;
|
||||
}
|
||||
|
||||
public String getSecretData() {
|
||||
return secretData;
|
||||
}
|
||||
|
||||
public void setSecretData(String secretData) {
|
||||
this.updated |= !Objects.equals(this.secretData, secretData);
|
||||
this.secretData = secretData;
|
||||
}
|
||||
|
||||
public String getCredentialData() {
|
||||
return credentialData;
|
||||
}
|
||||
|
||||
public void setCredentialData(String credentialData) {
|
||||
this.updated |= !Objects.equals(this.credentialData, credentialData);
|
||||
this.credentialData = credentialData;
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.keycloak.models.FederatedIdentityModel;
|
||||
import org.keycloak.models.map.common.UpdatableEntity;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class UserFederatedIdentityEntity extends UpdatableEntity.Impl {
|
||||
private String token;
|
||||
private String userId;
|
||||
private String identityProvider;
|
||||
private String userName;
|
||||
|
||||
private UserFederatedIdentityEntity() {}
|
||||
|
||||
public static UserFederatedIdentityEntity fromModel(FederatedIdentityModel model) {
|
||||
if (model == null) return null;
|
||||
UserFederatedIdentityEntity entity = new UserFederatedIdentityEntity();
|
||||
entity.setIdentityProvider(model.getIdentityProvider());
|
||||
entity.setUserId(model.getUserId());
|
||||
entity.setUserName(model.getUserName().toLowerCase());
|
||||
entity.setToken(model.getToken());
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
public static FederatedIdentityModel toModel(UserFederatedIdentityEntity entity) {
|
||||
if (entity == null) return null;
|
||||
return new FederatedIdentityModel(entity.getIdentityProvider(), entity.getUserId(), entity.getUserName(), entity.getToken());
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.updated |= !Objects.equals(this.token, token);
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.updated |= !Objects.equals(this.userId, userId);
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getIdentityProvider() {
|
||||
return identityProvider;
|
||||
}
|
||||
|
||||
public void setIdentityProvider(String identityProvider) {
|
||||
this.updated |= !Objects.equals(this.identityProvider, identityProvider);
|
||||
this.identityProvider = identityProvider;
|
||||
}
|
||||
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
public void setUserName(String userName) {
|
||||
this.updated |= !Objects.equals(this.userName, userName);
|
||||
this.userName = userName;
|
||||
}
|
||||
}
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright 2020 Red Hat, Inc. and/or its affiliates
|
||||
* and other contributors as indicated by the @author tags.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.keycloak.models.map.user;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.hamcrest.Matchers;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import org.keycloak.credential.CredentialModel;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AbstractUserEntityCredentialsOrderTest {
|
||||
|
||||
private MapUserEntity user;
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
user = new MapUserEntity("1", "realmId");
|
||||
|
||||
for (int i = 1; i <= 5; i++) {
|
||||
UserCredentialEntity credentialModel = new UserCredentialEntity();
|
||||
credentialModel.setId(Integer.toString(i));
|
||||
|
||||
user.addCredential(credentialModel);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertOrder(Integer... ids) {
|
||||
List<Integer> currentList = user.getCredentials().map(entity -> Integer.valueOf(entity.getId())).collect(Collectors.toList());
|
||||
assertThat(currentList, Matchers.contains(ids));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCorrectOrder() {
|
||||
assertOrder(1, 2, 3, 4, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveToZero() {
|
||||
user.moveCredential(2, 0);
|
||||
assertOrder(3, 1, 2, 4, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBack() {
|
||||
user.moveCredential(3, 1);
|
||||
assertOrder(1, 4, 2, 3, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveForward() {
|
||||
user.moveCredential(1, 3);
|
||||
assertOrder(1, 3, 4, 2, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSamePosition() {
|
||||
user.moveCredential(1, 1);
|
||||
assertOrder(1, 2, 3, 4, 5);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSamePositionZero() {
|
||||
user.moveCredential(0, 0);
|
||||
assertOrder(1, 2, 3, 4, 5);
|
||||
}
|
||||
|
||||
}
|
|
@ -31,6 +31,17 @@ import java.util.stream.Stream;
|
|||
public interface UserCredentialStore extends Provider {
|
||||
void updateCredential(RealmModel realm, UserModel user, CredentialModel cred);
|
||||
CredentialModel createCredential(RealmModel realm, UserModel user, CredentialModel cred);
|
||||
|
||||
/**
|
||||
* Removes credential with the {@code id} for the {@code user}.
|
||||
*
|
||||
* @param realm realm.
|
||||
* @param user user
|
||||
* @param id id
|
||||
* @return {@code true} if the credential was removed, {@code false} otherwise
|
||||
*
|
||||
* TODO: Make this method return Boolean so that store can return "I don't know" answer, this can be used for example in async stores
|
||||
*/
|
||||
boolean removeStoredCredential(RealmModel realm, UserModel user, String id);
|
||||
CredentialModel getStoredCredentialById(RealmModel realm, UserModel user, String id);
|
||||
|
||||
|
|
|
@ -202,6 +202,8 @@ public interface UserProvider extends Provider,
|
|||
* @param userId id of the user
|
||||
* @param clientInternalId id of the client
|
||||
* @return {@code true} if the consent was removed, {@code false} otherwise
|
||||
*
|
||||
* TODO: Make this method return Boolean so that store can return "I don't know" answer, this can be used for example in async stores
|
||||
*/
|
||||
boolean revokeConsentForClient(RealmModel realm, String userId, String clientInternalId);
|
||||
|
||||
|
@ -224,6 +226,8 @@ public interface UserProvider extends Provider,
|
|||
* @param user the user model
|
||||
* @param socialProvider alias of the identity provider, see {@link IdentityProviderModel#getAlias()}
|
||||
* @return {@code true} if the association was removed, {@code false} otherwise
|
||||
*
|
||||
* TODO: Make this method return Boolean so that store can return "I don't know" answer, this can be used for example in async stores
|
||||
*/
|
||||
boolean removeFederatedIdentity(RealmModel realm, UserModel user, String socialProvider);
|
||||
|
||||
|
|
Loading…
Reference in a new issue