parent
3f5741e988
commit
7d96f3ad5a
30 changed files with 1341 additions and 18 deletions
|
@ -17,6 +17,8 @@
|
|||
package org.keycloak.models.map.storage.jpa;
|
||||
|
||||
public interface Constants {
|
||||
public static final Integer CURRENT_SCHEMA_VERSION_ADMIN_EVENT = 1;
|
||||
public static final Integer CURRENT_SCHEMA_VERSION_AUTH_EVENT = 1;
|
||||
public static final Integer CURRENT_SCHEMA_VERSION_AUTH_SESSION = 1;
|
||||
public static final Integer CURRENT_SCHEMA_VERSION_AUTHZ_PERMISSION = 1;
|
||||
public static final Integer CURRENT_SCHEMA_VERSION_AUTHZ_POLICY = 1;
|
||||
|
|
|
@ -56,6 +56,8 @@ import org.keycloak.common.Profile;
|
|||
import org.keycloak.common.util.StackUtil;
|
||||
import org.keycloak.common.util.StringPropertyReplacer;
|
||||
import org.keycloak.component.AmphibianProviderFactory;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.ClientModel;
|
||||
import org.keycloak.models.ClientScopeModel;
|
||||
import org.keycloak.models.GroupModel;
|
||||
|
@ -108,6 +110,10 @@ import org.keycloak.models.map.storage.jpa.client.JpaClientMapKeycloakTransactio
|
|||
import org.keycloak.models.map.storage.jpa.client.entity.JpaClientEntity;
|
||||
import org.keycloak.models.map.storage.jpa.clientscope.JpaClientScopeMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.clientscope.entity.JpaClientScopeEntity;
|
||||
import org.keycloak.models.map.storage.jpa.event.admin.JpaAdminEventMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.event.admin.entity.JpaAdminEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.event.auth.JpaAuthEventMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.group.JpaGroupMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.group.entity.JpaGroupEntity;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.listeners.JpaAutoFlushListener;
|
||||
|
@ -158,6 +164,9 @@ public class JpaMapStorageProviderFactory implements
|
|||
.constructor(MapProtocolMapperEntity.class, MapProtocolMapperEntityImpl::new)
|
||||
//client-scope
|
||||
.constructor(JpaClientScopeEntity.class, JpaClientScopeEntity::new)
|
||||
//event
|
||||
.constructor(JpaAdminEventEntity.class, JpaAdminEventEntity::new)
|
||||
.constructor(JpaAuthEventEntity.class, JpaAuthEventEntity::new)
|
||||
//group
|
||||
.constructor(JpaGroupEntity.class, JpaGroupEntity::new)
|
||||
//realm
|
||||
|
@ -184,6 +193,9 @@ public class JpaMapStorageProviderFactory implements
|
|||
MODEL_TO_TX.put(RootAuthenticationSessionModel.class, JpaRootAuthenticationSessionMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(ClientScopeModel.class, JpaClientScopeMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(ClientModel.class, JpaClientMapKeycloakTransaction::new);
|
||||
//event
|
||||
MODEL_TO_TX.put(AdminEvent.class, JpaAdminEventMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(Event.class, JpaAuthEventMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(GroupModel.class, JpaGroupMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(RealmModel.class, JpaRealmMapKeycloakTransaction::new);
|
||||
MODEL_TO_TX.put(RoleModel.class, JpaRoleMapKeycloakTransaction::new);
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
package org.keycloak.models.map.storage.jpa;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.admin;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Selection;
|
||||
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.map.events.MapAdminEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.JpaModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.jpa.JpaRootEntity;
|
||||
import org.keycloak.models.map.storage.jpa.event.admin.entity.JpaAdminEventEntity;
|
||||
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_ADMIN_EVENT;
|
||||
|
||||
/**
|
||||
* A {@link org.keycloak.models.map.storage.MapKeycloakTransaction} implementation for admin event entities.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAdminEventMapKeycloakTransaction extends JpaMapKeycloakTransaction<JpaAdminEventEntity, MapAdminEventEntity, AdminEvent> {
|
||||
|
||||
public JpaAdminEventMapKeycloakTransaction(final EntityManager em) {
|
||||
super(JpaAdminEventEntity.class, AdminEvent.class, em);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Selection<? extends JpaAdminEventEntity> selectCbConstruct(CriteriaBuilder cb, Root<JpaAdminEventEntity> root) {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEntityVersion(JpaRootEntity entity) {
|
||||
entity.setEntityVersion(CURRENT_SCHEMA_VERSION_ADMIN_EVENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JpaModelCriteriaBuilder createJpaModelCriteriaBuilder() {
|
||||
return new JpaAdminEventModelCriteriaBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapAdminEventEntity mapToEntityDelegate(JpaAdminEventEntity original) {
|
||||
return original;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.admin;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.models.map.storage.CriterionNotSupportedException;
|
||||
import org.keycloak.models.map.storage.jpa.JpaModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.jpa.event.admin.entity.JpaAdminEventEntity;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
import org.keycloak.util.EnumWithStableIndex;
|
||||
|
||||
/**
|
||||
* A {@link JpaModelCriteriaBuilder} implementation for admin events.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAdminEventModelCriteriaBuilder extends JpaModelCriteriaBuilder<JpaAdminEventEntity, AdminEvent, JpaAdminEventModelCriteriaBuilder> {
|
||||
|
||||
private static final Map<String, String> FIELD_TO_JSON_PROP = new HashMap<>();
|
||||
static {
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.AUTH_CLIENT_ID.getName(), "fAuthClientId");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.AUTH_REALM_ID.getName(), "fAuthRealmId");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.AUTH_USER_ID.getName(), "fAuthUserId");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.AUTH_IP_ADDRESS.getName(), "fAuthIpAddress");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.RESOURCE_PATH.getName(), "fResourcePath");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.RESOURCE_TYPE.getName(), "fResourceType");
|
||||
FIELD_TO_JSON_PROP.put(AdminEvent.SearchableFields.OPERATION_TYPE.getName(), "fOperationType");
|
||||
}
|
||||
|
||||
public JpaAdminEventModelCriteriaBuilder() {
|
||||
super(JpaAdminEventModelCriteriaBuilder::new);
|
||||
}
|
||||
|
||||
private JpaAdminEventModelCriteriaBuilder(BiFunction<CriteriaBuilder, Root<JpaAdminEventEntity>, Predicate> predicateFunc) {
|
||||
super(JpaAdminEventModelCriteriaBuilder::new, predicateFunc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaAdminEventModelCriteriaBuilder compare(SearchableModelField<? super AdminEvent> modelField, Operator op, Object... value) {
|
||||
switch(op) {
|
||||
case EQ:
|
||||
if (modelField == AdminEvent.SearchableFields.REALM_ID) {
|
||||
|
||||
validateValue(value, modelField, op, String.class);
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.equal(root.get(modelField.getName()), value[0])
|
||||
);
|
||||
} else if (modelField == AdminEvent.SearchableFields.AUTH_CLIENT_ID ||
|
||||
modelField == AdminEvent.SearchableFields.AUTH_REALM_ID ||
|
||||
modelField == AdminEvent.SearchableFields.AUTH_USER_ID ||
|
||||
modelField == AdminEvent.SearchableFields.AUTH_IP_ADDRESS) {
|
||||
|
||||
validateValue(value, modelField, op, String.class);
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.equal(
|
||||
cb.function("->>", String.class, root.get("metadata"),
|
||||
cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))), value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case LE:
|
||||
if (modelField == AdminEvent.SearchableFields.TIMESTAMP) {
|
||||
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.le(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case LT:
|
||||
if (modelField == AdminEvent.SearchableFields.TIMESTAMP) {
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.lt(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case LIKE:
|
||||
if (modelField == AdminEvent.SearchableFields.RESOURCE_PATH) {
|
||||
validateValue(value, modelField, op, String.class);
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.like(
|
||||
cb.function("->>", String.class, root.get("metadata"), cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))),
|
||||
value[0].toString())
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case GE:
|
||||
if (modelField == AdminEvent.SearchableFields.TIMESTAMP) {
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.ge(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case IN:
|
||||
if (modelField == AdminEvent.SearchableFields.OPERATION_TYPE) {
|
||||
Set<Integer> values = super.getValuesForInOperator(value, modelField).stream()
|
||||
.map(o -> ((EnumWithStableIndex) o).getStableIndex()).collect(Collectors.toSet());
|
||||
|
||||
if (values.isEmpty()) return new JpaAdminEventModelCriteriaBuilder((cb, root) -> cb.or());
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) -> {
|
||||
CriteriaBuilder.In<Integer> in = cb.in(cb.function("->>", String.class, root.get("metadata"),
|
||||
cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))).as(Integer.class));
|
||||
values.forEach(in::value);
|
||||
return in;
|
||||
});
|
||||
}
|
||||
else if (modelField == AdminEvent.SearchableFields.RESOURCE_TYPE) {
|
||||
Set<String> values = super.getValuesForInOperator(value, modelField).stream()
|
||||
.map(Object::toString).collect(Collectors.toSet());
|
||||
|
||||
if (values.isEmpty()) return new JpaAdminEventModelCriteriaBuilder((cb, root) -> cb.or());
|
||||
|
||||
return new JpaAdminEventModelCriteriaBuilder((cb, root) -> {
|
||||
CriteriaBuilder.In<String> in = cb.in(cb.function("->>", String.class, root.get("metadata"),
|
||||
cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))));
|
||||
values.forEach(in::value);
|
||||
return in;
|
||||
});
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
default:
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,263 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.admin.entity;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
import org.hibernate.annotations.TypeDefs;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.UuidValidator;
|
||||
import org.keycloak.models.map.events.MapAdminEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.JpaRootVersionedEntity;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
|
||||
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_ADMIN_EVENT;
|
||||
|
||||
/**
|
||||
* JPA {@link MapAdminEventEntity} implementation. Some fields are annotated with {@code @Column(insertable = false, updatable = false)}
|
||||
* to indicate that they are automatically generated from json fields. As such, these fields are non-insertable and non-updatable.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "kc_admin_event")
|
||||
@TypeDefs({@TypeDef(name = "jsonb", typeClass = JsonbType.class)})
|
||||
public class JpaAdminEventEntity extends MapAdminEventEntity.AbstractAdminEventEntity implements JpaRootVersionedEntity {
|
||||
|
||||
@Id
|
||||
@Column
|
||||
private UUID id;
|
||||
|
||||
//used for implicit optimistic locking
|
||||
@Version
|
||||
@Column
|
||||
private int version;
|
||||
|
||||
@Type(type = "jsonb")
|
||||
@Column(columnDefinition = "jsonb")
|
||||
private final JpaAdminEventMetadata metadata;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Integer entityVersion;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private String realmId;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Long timestamp;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Long expiration;
|
||||
|
||||
/**
|
||||
* No-argument constructor, used by hibernate to instantiate entities.
|
||||
*/
|
||||
public JpaAdminEventEntity() {
|
||||
this.metadata = new JpaAdminEventMetadata();
|
||||
}
|
||||
|
||||
public JpaAdminEventEntity(final DeepCloner cloner) {
|
||||
this.metadata = new JpaAdminEventMetadata(cloner);
|
||||
}
|
||||
|
||||
public boolean isMetadataInitialized() {
|
||||
return metadata != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEntityVersion() {
|
||||
if (this.isMetadataInitialized()) return metadata.getEntityVersion();
|
||||
return this.entityVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityVersion(final Integer entityVersion) {
|
||||
this.metadata.setEntityVersion(entityVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id == null ? null : id.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(final String id) {
|
||||
String validatedId = UuidValidator.validateAndConvert(id);
|
||||
this.id = UUID.fromString(validatedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCurrentSchemaVersion() {
|
||||
return CURRENT_SCHEMA_VERSION_ADMIN_EVENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getExpiration() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getExpiration();
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpiration(final Long expiration) {
|
||||
this.metadata.setExpiration(expiration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimestamp() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getTimestamp();
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(final Long time) {
|
||||
this.metadata.setTimestamp(time);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmId() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getRealmId();
|
||||
return this.realmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRealmId(final String realmId) {
|
||||
this.metadata.setRealmId(realmId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OperationType getOperationType() {
|
||||
return this.metadata.getOperationType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOperationType(final OperationType operationType) {
|
||||
this.metadata.setOperationType(operationType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourcePath() {
|
||||
return this.metadata.getResourcePath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourcePath(final String resourcePath) {
|
||||
this.metadata.setResourcePath(resourcePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResourceType() {
|
||||
return this.metadata.getResourceType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceType(final String resourceType) {
|
||||
this.metadata.setResourceType(resourceType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRepresentation() {
|
||||
return this.metadata.getRepresentation();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRepresentation(final String representation) {
|
||||
this.metadata.setRepresentation(representation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getError() {
|
||||
return this.metadata.getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(final String error) {
|
||||
this.metadata.setError(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthClientId() {
|
||||
return this.metadata.getAuthClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthClientId(final String clientId) {
|
||||
this.metadata.setAuthClientId(clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthRealmId() {
|
||||
return this.metadata.getAuthRealmId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthRealmId(final String realmId) {
|
||||
this.metadata.setAuthRealmId(realmId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthUserId() {
|
||||
return this.metadata.getAuthUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthUserId(final String userId) {
|
||||
this.metadata.setAuthUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAuthIpAddress() {
|
||||
return this.metadata.getAuthIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAuthIpAddress(final String ipAddress) {
|
||||
this.metadata.setAuthIpAddress(ipAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof JpaAdminEventEntity)) return false;
|
||||
return Objects.equals(getId(), ((JpaAdminEventEntity) obj).getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.admin.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.events.MapAdminEventEntityImpl;
|
||||
|
||||
/**
|
||||
* Class that contains all the admin event metadata that is written as JSON into the database.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAdminEventMetadata extends MapAdminEventEntityImpl implements Serializable {
|
||||
|
||||
public JpaAdminEventMetadata(final DeepCloner cloner) {
|
||||
super(cloner);
|
||||
}
|
||||
|
||||
public JpaAdminEventMetadata() {
|
||||
super();
|
||||
}
|
||||
|
||||
private Integer entityVersion;
|
||||
|
||||
public Integer getEntityVersion() {
|
||||
return entityVersion;
|
||||
}
|
||||
|
||||
public void setEntityVersion(Integer entityVersion) {
|
||||
this.entityVersion = entityVersion;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.auth;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Selection;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.models.map.events.MapAuthEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.JpaMapKeycloakTransaction;
|
||||
import org.keycloak.models.map.storage.jpa.JpaModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.jpa.JpaRootEntity;
|
||||
import org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventEntity;
|
||||
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTH_EVENT;
|
||||
|
||||
/**
|
||||
* A {@link org.keycloak.models.map.storage.MapKeycloakTransaction} implementation for auth event entities.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAuthEventMapKeycloakTransaction extends JpaMapKeycloakTransaction<JpaAuthEventEntity, MapAuthEventEntity, Event> {
|
||||
|
||||
public JpaAuthEventMapKeycloakTransaction(final EntityManager em) {
|
||||
super(JpaAuthEventEntity.class, Event.class, em);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Selection<? extends JpaAuthEventEntity> selectCbConstruct(CriteriaBuilder cb, Root<JpaAuthEventEntity> root) {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEntityVersion(JpaRootEntity entity) {
|
||||
entity.setEntityVersion(CURRENT_SCHEMA_VERSION_AUTH_EVENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JpaModelCriteriaBuilder createJpaModelCriteriaBuilder() {
|
||||
return new JpaAuthEventModelCriteriaBuilder();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected MapAuthEventEntity mapToEntityDelegate(JpaAuthEventEntity original) {
|
||||
return original;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.auth;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.models.map.storage.CriterionNotSupportedException;
|
||||
import org.keycloak.models.map.storage.jpa.JpaModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventEntity;
|
||||
import org.keycloak.storage.SearchableModelField;
|
||||
import org.keycloak.util.EnumWithStableIndex;
|
||||
|
||||
public class JpaAuthEventModelCriteriaBuilder extends JpaModelCriteriaBuilder<JpaAuthEventEntity, Event, JpaAuthEventModelCriteriaBuilder> {
|
||||
|
||||
private static final Map<String, String> FIELD_TO_JSON_PROP = new HashMap<>();
|
||||
static {
|
||||
FIELD_TO_JSON_PROP.put(Event.SearchableFields.CLIENT_ID.getName(), "fClientId");
|
||||
FIELD_TO_JSON_PROP.put(Event.SearchableFields.USER_ID.getName(), "fUserId");
|
||||
FIELD_TO_JSON_PROP.put(Event.SearchableFields.IP_ADDRESS.getName(), "fIpAddress");
|
||||
FIELD_TO_JSON_PROP.put(Event.SearchableFields.EVENT_TYPE.getName(), "fType");
|
||||
}
|
||||
|
||||
public JpaAuthEventModelCriteriaBuilder() {
|
||||
super(JpaAuthEventModelCriteriaBuilder::new);
|
||||
}
|
||||
|
||||
private JpaAuthEventModelCriteriaBuilder(BiFunction<CriteriaBuilder, Root<JpaAuthEventEntity>, Predicate> predicateFunc) {
|
||||
super(JpaAuthEventModelCriteriaBuilder::new, predicateFunc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JpaAuthEventModelCriteriaBuilder compare(SearchableModelField<? super Event> modelField, Operator op, Object... value) {
|
||||
switch (op) {
|
||||
case EQ:
|
||||
if (modelField == Event.SearchableFields.REALM_ID) {
|
||||
|
||||
validateValue(value, modelField, op, String.class);
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.equal(root.get(modelField.getName()), value[0])
|
||||
);
|
||||
} else if (modelField == Event.SearchableFields.CLIENT_ID ||
|
||||
modelField == Event.SearchableFields.USER_ID ||
|
||||
modelField == Event.SearchableFields.IP_ADDRESS) {
|
||||
|
||||
validateValue(value, modelField, op, String.class);
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.equal(
|
||||
cb.function("->>", String.class, root.get("metadata"),
|
||||
cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))), value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case LE:
|
||||
if (modelField == Event.SearchableFields.TIMESTAMP) {
|
||||
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.le(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case LT:
|
||||
if (modelField == Event.SearchableFields.TIMESTAMP) {
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.lt(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case GE:
|
||||
if (modelField == Event.SearchableFields.TIMESTAMP) {
|
||||
validateValue(value, modelField, op, Number.class);
|
||||
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) ->
|
||||
cb.ge(root.get(modelField.getName()), (Number) value[0])
|
||||
);
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
case IN:
|
||||
if (modelField == Event.SearchableFields.EVENT_TYPE) {
|
||||
Set<Integer> values = super.getValuesForInOperator(value, modelField).stream()
|
||||
.map(o -> ((EnumWithStableIndex) o).getStableIndex()).collect(Collectors.toSet());
|
||||
|
||||
if (values.isEmpty()) return new JpaAuthEventModelCriteriaBuilder((cb, root) -> cb.or());
|
||||
|
||||
return new JpaAuthEventModelCriteriaBuilder((cb, root) -> {
|
||||
CriteriaBuilder.In<Integer> in = cb.in(cb.function("->>", String.class, root.get("metadata"),
|
||||
cb.literal(FIELD_TO_JSON_PROP.get(modelField.getName()))).as(Integer.class));
|
||||
values.forEach(in::value);
|
||||
return in;
|
||||
});
|
||||
} else {
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
default:
|
||||
throw new CriterionNotSupportedException(modelField, op);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.auth.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
|
||||
import org.keycloak.models.map.storage.jpa.JpaAttributeEntity;
|
||||
|
||||
/**
|
||||
* JPA implementation for auth event details.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "kc_auth_event_detail", uniqueConstraints = {
|
||||
@UniqueConstraint(columnNames = {"fk_root", "name", "value"})
|
||||
})
|
||||
public class JpaAuthEventDetailEntity extends JpaAttributeEntity<JpaAuthEventEntity> {
|
||||
|
||||
public JpaAuthEventDetailEntity() {
|
||||
}
|
||||
|
||||
public JpaAuthEventDetailEntity(final JpaAuthEventEntity root, final String name, final String value) {
|
||||
super(root, name, value);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.auth.entity;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.hibernate.annotations.TypeDef;
|
||||
import org.hibernate.annotations.TypeDefs;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.common.UuidValidator;
|
||||
import org.keycloak.models.map.events.MapAuthEventEntity;
|
||||
import org.keycloak.models.map.storage.jpa.JpaRootVersionedEntity;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.JsonbType;
|
||||
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTH_EVENT;
|
||||
|
||||
/**
|
||||
* JPA {@link MapAuthEventEntity} implementation. Some fields are annotated with {@code @Column(insertable = false, updatable = false)}
|
||||
* to indicate that they are automatically generated from json fields. As such, these fields are non-insertable and non-updatable.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
@Entity
|
||||
@Table(name = "kc_auth_event")
|
||||
@TypeDefs({@TypeDef(name = "jsonb", typeClass = JsonbType.class)})
|
||||
public class JpaAuthEventEntity extends MapAuthEventEntity.AbstractAuthEventEntity implements JpaRootVersionedEntity {
|
||||
|
||||
@Id
|
||||
@Column
|
||||
private UUID id;
|
||||
|
||||
//used for implicit optimistic locking
|
||||
@Version
|
||||
@Column
|
||||
private int version;
|
||||
|
||||
@Type(type = "jsonb")
|
||||
@Column(columnDefinition = "jsonb")
|
||||
private final JpaAuthEventMetadata metadata;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Integer entityVersion;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private String realmId;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Long timestamp;
|
||||
|
||||
@Column(insertable = false, updatable = false)
|
||||
@Basic(fetch = FetchType.LAZY)
|
||||
private Long expiration;
|
||||
|
||||
@OneToMany(mappedBy = "root", cascade = CascadeType.PERSIST, orphanRemoval = true)
|
||||
private final Set<JpaAuthEventDetailEntity> details = new HashSet<>();
|
||||
|
||||
/**
|
||||
* No-argument constructor, used by hibernate to instantiate entities.
|
||||
*/
|
||||
public JpaAuthEventEntity() {
|
||||
this.metadata = new JpaAuthEventMetadata();
|
||||
}
|
||||
|
||||
public JpaAuthEventEntity(final DeepCloner cloner) {
|
||||
this.metadata = new JpaAuthEventMetadata(cloner);
|
||||
}
|
||||
|
||||
public boolean isMetadataInitialized() {
|
||||
return metadata != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getCurrentSchemaVersion() {
|
||||
return CURRENT_SCHEMA_VERSION_AUTH_EVENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getEntityVersion() {
|
||||
if (this.isMetadataInitialized()) return metadata.getEntityVersion();
|
||||
return this.entityVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEntityVersion(final Integer entityVersion) {
|
||||
this.metadata.setEntityVersion(entityVersion);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getVersion() {
|
||||
return this.version;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id == null ? null : id.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setId(final String id) {
|
||||
String validatedId = UuidValidator.validateAndConvert(id);
|
||||
this.id = UUID.fromString(validatedId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getExpiration() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getExpiration();
|
||||
return this.expiration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpiration(final Long expiration) {
|
||||
this.metadata.setExpiration(expiration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getTimestamp() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getTimestamp();
|
||||
return this.timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(final Long timestamp) {
|
||||
this.metadata.setTimestamp(timestamp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClientId() {
|
||||
return this.metadata.getClientId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClientId(final String clientId) {
|
||||
this.metadata.setClientId(clientId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getDetails() {
|
||||
return this.details.stream().collect(Collectors.toMap(JpaAuthEventDetailEntity::getName, JpaAuthEventDetailEntity::getValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDetails(final Map<String, String> details) {
|
||||
this.details.clear();
|
||||
if (details != null) {
|
||||
details.forEach((key, value) -> this.details.add(new JpaAuthEventDetailEntity(this, key, value)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getError() {
|
||||
return this.metadata.getError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setError(final String error) {
|
||||
this.metadata.setError(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIpAddress() {
|
||||
return this.metadata.getIpAddress();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIpAddress(final String ipAddress) {
|
||||
this.metadata.setIpAddress(ipAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmId() {
|
||||
if (this.isMetadataInitialized()) return this.metadata.getRealmId();
|
||||
return this.realmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRealmId(final String realmId) {
|
||||
this.metadata.setRealmId(realmId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionId() {
|
||||
return this.metadata.getSessionId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSessionId(final String sessionId) {
|
||||
this.metadata.setSessionId(sessionId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUserId() {
|
||||
return this.metadata.getUserId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUserId(final String userId) {
|
||||
this.metadata.setUserId(userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventType getType() {
|
||||
return this.metadata.getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setType(final EventType type) {
|
||||
this.metadata.setType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getClass().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object obj) {
|
||||
if (this == obj) return true;
|
||||
if (!(obj instanceof JpaAuthEventEntity)) return false;
|
||||
return Objects.equals(getId(), ((JpaAuthEventEntity) obj).getId());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.event.auth.entity;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.keycloak.models.map.common.DeepCloner;
|
||||
import org.keycloak.models.map.events.MapAuthEventEntityImpl;
|
||||
|
||||
/**
|
||||
* Class that contains all the auth event metadata that is written as JSON into the database.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAuthEventMetadata extends MapAuthEventEntityImpl implements Serializable {
|
||||
|
||||
public JpaAuthEventMetadata(final DeepCloner cloner) {
|
||||
super(cloner);
|
||||
}
|
||||
|
||||
public JpaAuthEventMetadata() {
|
||||
super();
|
||||
}
|
||||
|
||||
private Integer entityVersion;
|
||||
|
||||
public Integer getEntityVersion() {
|
||||
return entityVersion;
|
||||
}
|
||||
|
||||
public void setEntityVersion(Integer entityVersion) {
|
||||
this.entityVersion = entityVersion;
|
||||
}
|
||||
}
|
|
@ -25,6 +25,7 @@ public class JsonbPostgreSQL95Dialect extends PostgreSQL95Dialect {
|
|||
public JsonbPostgreSQL95Dialect() {
|
||||
super();
|
||||
registerFunction("->", new SQLFunctionTemplate(JsonbType.INSTANCE, "?1->?2"));
|
||||
registerFunction("->>", new SQLFunctionTemplate(StandardBasicTypes.STRING, "?1->>?2"));
|
||||
registerFunction("@>", new SQLFunctionTemplate(StandardBasicTypes.BOOLEAN, "?1@>?2::jsonb"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,11 @@ import org.keycloak.models.map.storage.jpa.authorization.scope.entity.JpaScopeMe
|
|||
import org.keycloak.models.map.storage.jpa.authorization.resourceServer.entity.JpaResourceServerMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.client.entity.JpaClientMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.clientscope.entity.JpaClientScopeMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.event.admin.entity.JpaAdminEventMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.group.entity.JpaGroupMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.migration.JpaAdminEventMigration;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.migration.JpaAuthEventMigration;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.migration.JpaAuthenticationSessionMigration;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.migration.JpaClientMigration;
|
||||
import org.keycloak.models.map.storage.jpa.hibernate.jsonb.migration.JpaClientScopeMigration;
|
||||
|
@ -52,11 +56,13 @@ import org.keycloak.models.map.storage.jpa.realm.entity.JpaComponentMetadata;
|
|||
import org.keycloak.models.map.storage.jpa.realm.entity.JpaRealmMetadata;
|
||||
import org.keycloak.models.map.storage.jpa.role.entity.JpaRoleMetadata;
|
||||
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_ADMIN_EVENT;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTHZ_PERMISSION;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTHZ_POLICY;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTHZ_RESOURCE;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTHZ_RESOURCE_SERVER;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTHZ_SCOPE;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTH_EVENT;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_AUTH_SESSION;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_CLIENT;
|
||||
import static org.keycloak.models.map.storage.jpa.Constants.CURRENT_SCHEMA_VERSION_CLIENT_SCOPE;
|
||||
|
@ -85,6 +91,10 @@ public class JpaEntityMigration {
|
|||
MIGRATIONS.put(JpaResourceMetadata.class, (tree, entityVersion) -> migrateTreeTo(entityVersion, CURRENT_SCHEMA_VERSION_AUTHZ_RESOURCE, tree, JpaResourceMigration.MIGRATORS));
|
||||
MIGRATIONS.put(JpaResourceServerMetadata.class, (tree, entityVersion) -> migrateTreeTo(entityVersion, CURRENT_SCHEMA_VERSION_AUTHZ_RESOURCE_SERVER, tree, JpaResourceServerMigration.MIGRATORS));
|
||||
MIGRATIONS.put(JpaScopeMetadata.class, (tree, entityVersion) -> migrateTreeTo(entityVersion, CURRENT_SCHEMA_VERSION_AUTHZ_SCOPE, tree, JpaScopeMigration.MIGRATORS));
|
||||
|
||||
// events
|
||||
MIGRATIONS.put(JpaAdminEventMetadata.class, (tree, entityVersion) -> migrateTreeTo(entityVersion, CURRENT_SCHEMA_VERSION_ADMIN_EVENT, tree, JpaAdminEventMigration.MIGRATORS));
|
||||
MIGRATIONS.put(JpaAuthEventMetadata.class, (tree, entityVersion) -> migrateTreeTo(entityVersion, CURRENT_SCHEMA_VERSION_AUTH_EVENT, tree, JpaAuthEventMigration.MIGRATORS));
|
||||
}
|
||||
|
||||
private static ObjectNode migrateTreeTo(int entityVersion, Integer supportedVersion, ObjectNode node, List<Function<ObjectNode, ObjectNode>> migrators) {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.hibernate.jsonb.migration;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Migration functions for admin events.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAdminEventMigration {
|
||||
|
||||
public static final List<Function<ObjectNode, ObjectNode>> MIGRATORS = Arrays.asList(
|
||||
o -> o // no migration yet
|
||||
);
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2022 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.storage.jpa.hibernate.jsonb.migration;
|
||||
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* Migration functions for authentication events.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
public class JpaAuthEventMigration {
|
||||
|
||||
public static final List<Function<ObjectNode, ObjectNode>> MIGRATORS = Arrays.asList(
|
||||
o -> o // no migration yet
|
||||
);
|
||||
}
|
|
@ -53,8 +53,10 @@ import liquibase.statement.SqlStatement;
|
|||
* </ext:createJsonIndex>
|
||||
* </changeSet>
|
||||
* </pre>
|
||||
* The above configuration is creating an index for the {@code name} property of JSON files stored in column {@code metadata} in
|
||||
* table {@code test}.
|
||||
* The above configuration is creating an inverted (GIN) index for the {@code name} property of JSON files stored in column
|
||||
* {@code metadata} in table {@code test}.
|
||||
* <p/>
|
||||
* The {@code jsonProperty} is optional - when it is absent the index will be created for the whole JSON.
|
||||
*
|
||||
* @author <a href="mailto:sguilhen@redhat.com">Stefan Guilhen</a>
|
||||
*/
|
||||
|
|
|
@ -62,7 +62,6 @@ public class CreateJsonIndexGenerator extends AbstractSqlGenerator<CreateJsonInd
|
|||
Arrays.stream(createIndexStatement.getColumns()).map(JsonEnabledColumnConfig.class::cast)
|
||||
.forEach(config -> {
|
||||
validationErrors.checkRequiredField("jsonColumn", config.getJsonColumn());
|
||||
validationErrors.checkRequiredField("jsonProperty", config.getJsonProperty());
|
||||
});
|
||||
return validationErrors;
|
||||
}
|
||||
|
@ -100,13 +99,16 @@ public class CreateJsonIndexGenerator extends AbstractSqlGenerator<CreateJsonInd
|
|||
if (database instanceof CockroachDatabase) {
|
||||
builder.append(" USING gin (");
|
||||
builder.append(Arrays.stream(statement.getColumns()).map(JsonEnabledColumnConfig.class::cast)
|
||||
.map(c -> "(" + c.getJsonColumn() + "->'" + c.getJsonProperty() + "')")
|
||||
.map(c -> c.getJsonProperty() == null ? c.getJsonColumn() :
|
||||
"(" + c.getJsonColumn() + "->'" + c.getJsonProperty() + "')")
|
||||
.collect(Collectors.joining(", ")))
|
||||
.append(")");
|
||||
}
|
||||
else if (database instanceof PostgresDatabase) { builder.append(" USING gin (");
|
||||
else if (database instanceof PostgresDatabase) {
|
||||
builder.append(" USING gin (");
|
||||
builder.append(Arrays.stream(statement.getColumns()).map(JsonEnabledColumnConfig.class::cast)
|
||||
.map(c -> "(" + c.getJsonColumn() + "->'" + c.getJsonProperty() + "') jsonb_path_ops")
|
||||
.map(c -> c.getJsonProperty() == null ? c.getJsonColumn() :
|
||||
"(" + c.getJsonColumn() + "->'" + c.getJsonProperty() + "') jsonb_path_ops")
|
||||
.collect(Collectors.joining(", ")))
|
||||
.append(")");
|
||||
}
|
||||
|
|
|
@ -194,6 +194,10 @@ public class MapJpaLiquibaseUpdaterProvider implements MapJpaUpdaterProvider {
|
|||
// for authorization services there is used single name for all modelTypes
|
||||
modelName = modelName.startsWith("authz-") ? "authz" : modelName;
|
||||
|
||||
// for events, map both event types to a single changelog name
|
||||
if (modelName.equals("auth-events") || modelName.equals("admin-events"))
|
||||
modelName = "events";
|
||||
|
||||
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
|
||||
// if database is cockroachdb, use the aggregate changelog (see GHI #11230).
|
||||
String changelog = database instanceof CockroachDatabase ? "META-INF/jpa-aggregate-changelog.xml" : "META-INF/jpa-" + modelName + "-changelog.xml";
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2022 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.
|
||||
-->
|
||||
|
||||
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
|
||||
|
||||
<changeSet author="keycloak" id="admin-events-1">
|
||||
|
||||
<createTable tableName="kc_admin_event">
|
||||
<column name="id" type="UUID">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="version" type="INTEGER" defaultValueNumeric="0">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="metadata" type="json"/>
|
||||
</createTable>
|
||||
<ext:addGeneratedColumn tableName="kc_admin_event">
|
||||
<ext:column name="entityversion" type="INTEGER" jsonColumn="metadata" jsonProperty="entityVersion"/>
|
||||
<ext:column name="realmid" type="KC_KEY" jsonColumn="metadata" jsonProperty="fRealmId"/>
|
||||
<ext:column name="timestamp" type="BIGINT" jsonColumn="metadata" jsonProperty="fTimestamp"/>
|
||||
<ext:column name="expiration" type="BIGINT" jsonColumn="metadata" jsonProperty="fExpiration"/>
|
||||
</ext:addGeneratedColumn>
|
||||
<createIndex tableName="kc_admin_event" indexName="admin_event_entityversion">
|
||||
<column name="entityversion"/>
|
||||
</createIndex>
|
||||
<createIndex tableName="kc_admin_event" indexName="admin_event_expiration">
|
||||
<column name="expiration"/>
|
||||
</createIndex>
|
||||
<createIndex tableName="kc_admin_event" indexName="admin_event_realmid_timestamp">
|
||||
<column name="realmid"/>
|
||||
<column name="timestamp"/>
|
||||
</createIndex>
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
|
@ -0,0 +1,73 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2022 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.
|
||||
-->
|
||||
|
||||
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:ext="http://www.liquibase.org/xml/ns/dbchangelog-ext"
|
||||
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd
|
||||
http://www.liquibase.org/xml/ns/dbchangelog-ext http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-ext.xsd">
|
||||
|
||||
<changeSet author="keycloak" id="auth-events-1">
|
||||
|
||||
<createTable tableName="kc_auth_event">
|
||||
<column name="id" type="UUID">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="version" type="INTEGER" defaultValueNumeric="0">
|
||||
<constraints nullable="false"/>
|
||||
</column>
|
||||
<column name="metadata" type="json"/>
|
||||
</createTable>
|
||||
<ext:addGeneratedColumn tableName="kc_auth_event">
|
||||
<ext:column name="entityversion" type="INTEGER" jsonColumn="metadata" jsonProperty="entityVersion"/>
|
||||
<ext:column name="realmid" type="KC_KEY" jsonColumn="metadata" jsonProperty="fRealmId"/>
|
||||
<ext:column name="timestamp" type="BIGINT" jsonColumn="metadata" jsonProperty="fTimestamp"/>
|
||||
<ext:column name="expiration" type="BIGINT" jsonColumn="metadata" jsonProperty="fExpiration"/>
|
||||
</ext:addGeneratedColumn>
|
||||
<createIndex tableName="kc_auth_event" indexName="auth_event_entityversion">
|
||||
<column name="entityversion"/>
|
||||
</createIndex>
|
||||
<createIndex tableName="kc_auth_event" indexName="auth_event_expiration">
|
||||
<column name="expiration"/>
|
||||
</createIndex>
|
||||
<createIndex tableName="kc_auth_event" indexName="auth_event_realmid_timestamp">
|
||||
<column name="realmid"/>
|
||||
<column name="timestamp"/>
|
||||
</createIndex>
|
||||
|
||||
<createTable tableName="kc_auth_event_detail">
|
||||
<column name="id" type="UUID">
|
||||
<constraints primaryKey="true" nullable="false"/>
|
||||
</column>
|
||||
<column name="fk_root" type="UUID">
|
||||
<constraints foreignKeyName="auth_event_detail_fk_root_fkey" references="kc_auth_event(id)" deleteCascade="true"/>
|
||||
</column>
|
||||
<column name="name" type="VARCHAR(255)"/>
|
||||
<column name="value" type="TEXT"/>
|
||||
</createTable>
|
||||
<createIndex tableName="kc_auth_event_detail" indexName="auth_event_detail_fk_root">
|
||||
<column name="fk_root"/>
|
||||
</createIndex>
|
||||
|
||||
</changeSet>
|
||||
|
||||
<changeSet author="keycloak" id="auth-events-2" dbms="postgresql">
|
||||
<!-- this is deferrable and initiallyDeferred as hibernate will first insert new entries and then delete the old by default -->
|
||||
<!-- this will not work on cockroachdb as deferred indexes are not supported in version 22.1 yet, therefore, only run it on postgresql -->
|
||||
<!-- see https://go.crdb.dev/issue-v/31632/v21.2 for the current status of the implementation -->
|
||||
<addUniqueConstraint tableName="kc_auth_event_detail" columnNames="fk_root, name, value" deferrable="true" initiallyDeferred="true" />
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
|
@ -23,6 +23,7 @@ limitations under the License.
|
|||
<include file="META-INF/jpa-authz-changelog.xml"/>
|
||||
<include file="META-INF/jpa-client-scopes-changelog.xml"/>
|
||||
<include file="META-INF/jpa-clients-changelog.xml"/>
|
||||
<include file="META-INF/jpa-events-changelog.xml"/>
|
||||
<include file="META-INF/jpa-groups-changelog.xml"/>
|
||||
<include file="META-INF/jpa-realms-changelog.xml"/>
|
||||
<include file="META-INF/jpa-roles-changelog.xml"/>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!--
|
||||
Copyright 2022 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.
|
||||
-->
|
||||
|
||||
|
||||
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-3.1.xsd">
|
||||
<include file="META-INF/events/admin-events/jpa-admin-events-changelog-1.xml"/>
|
||||
<include file="META-INF/events/auth-events/jpa-auth-events-changelog-1.xml"/>
|
||||
</databaseChangeLog>
|
|
@ -18,6 +18,10 @@
|
|||
<!--clients-->
|
||||
<class>org.keycloak.models.map.storage.jpa.client.entity.JpaClientEntity</class>
|
||||
<class>org.keycloak.models.map.storage.jpa.client.entity.JpaClientAttributeEntity</class>
|
||||
<!--events-->
|
||||
<class>org.keycloak.models.map.storage.jpa.event.admin.entity.JpaAdminEventEntity</class>
|
||||
<class>org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventEntity</class>
|
||||
<class>org.keycloak.models.map.storage.jpa.event.auth.entity.JpaAuthEventDetailEntity</class>
|
||||
<!--groups-->
|
||||
<class>org.keycloak.models.map.storage.jpa.group.entity.JpaGroupEntity</class>
|
||||
<class>org.keycloak.models.map.storage.jpa.group.entity.JpaGroupAttributeEntity</class>
|
||||
|
|
|
@ -17,13 +17,11 @@
|
|||
|
||||
package org.keycloak.models.map.events;
|
||||
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.admin.AdminEvent;
|
||||
import org.keycloak.events.admin.AdminEvent.SearchableFields;
|
||||
import org.keycloak.events.admin.AdminEventQuery;
|
||||
import org.keycloak.events.admin.OperationType;
|
||||
import org.keycloak.events.admin.ResourceType;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
|
||||
|
@ -45,7 +43,6 @@ public class MapAdminEventQuery implements AdminEventQuery {
|
|||
private Integer firstResult;
|
||||
private Integer maxResults;
|
||||
private DefaultModelCriteria<AdminEvent> mcb = criteria();
|
||||
private final DefaultModelCriteria<AdminEvent> criteria = criteria();
|
||||
private final Function<QueryParameters<AdminEvent>, Stream<AdminEvent>> resultProducer;
|
||||
|
||||
public MapAdminEventQuery(Function<QueryParameters<AdminEvent>, Stream<AdminEvent>> resultProducer) {
|
||||
|
|
|
@ -17,12 +17,10 @@
|
|||
|
||||
package org.keycloak.models.map.events;
|
||||
|
||||
import org.keycloak.common.util.Time;
|
||||
import org.keycloak.events.Event;
|
||||
import org.keycloak.events.Event.SearchableFields;
|
||||
import org.keycloak.events.EventQuery;
|
||||
import org.keycloak.events.EventType;
|
||||
import org.keycloak.models.map.storage.ModelCriteriaBuilder;
|
||||
import org.keycloak.models.map.storage.QueryParameters;
|
||||
import org.keycloak.models.map.storage.criteria.DefaultModelCriteria;
|
||||
|
||||
|
@ -43,7 +41,6 @@ public class MapAuthEventQuery implements EventQuery {
|
|||
private Integer firstResult;
|
||||
private Integer maxResults;
|
||||
private DefaultModelCriteria<Event> mcb = criteria();
|
||||
private final DefaultModelCriteria<Event> criteria = criteria();
|
||||
private final Function<QueryParameters<Event>, Stream<Event>> resultProducer;
|
||||
|
||||
public MapAuthEventQuery(Function<QueryParameters<Event>, Stream<Event>> resultProducer) {
|
||||
|
|
|
@ -890,6 +890,8 @@
|
|||
<keycloak.authSession.map.storage.provider>jpa</keycloak.authSession.map.storage.provider>
|
||||
<keycloak.client.map.storage.provider>jpa</keycloak.client.map.storage.provider>
|
||||
<keycloak.clientScope.map.storage.provider>jpa</keycloak.clientScope.map.storage.provider>
|
||||
<keycloak.adminEventsStore.map.storage.provider>jpa</keycloak.adminEventsStore.map.storage.provider>
|
||||
<keycloak.authEventsStore.map.storage.provider>jpa</keycloak.authEventsStore.map.storage.provider>
|
||||
<keycloak.group.map.storage.provider>jpa</keycloak.group.map.storage.provider>
|
||||
<keycloak.loginFailure.map.storage.provider>jpa</keycloak.loginFailure.map.storage.provider>
|
||||
<keycloak.realm.map.storage.provider>jpa</keycloak.realm.map.storage.provider>
|
||||
|
|
|
@ -28,10 +28,10 @@
|
|||
},
|
||||
"map": {
|
||||
"storage-admin-events": {
|
||||
"provider": "${keycloak.eventStore.map.storage.provider:concurrenthashmap}"
|
||||
"provider": "${keycloak.adminEventsStore.map.storage.provider:concurrenthashmap}"
|
||||
},
|
||||
"storage-auth-events": {
|
||||
"provider": "${keycloak.eventStore.map.storage.provider:concurrenthashmap}"
|
||||
"provider": "${keycloak.authEventsStore.map.storage.provider:concurrenthashmap}"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -101,7 +101,7 @@ public class JpaMapStorage extends KeycloakModelParameters {
|
|||
.spi(SingleUseObjectSpi.NAME).provider(MapSingleUseObjectProviderFactory.PROVIDER_ID) .config(STORAGE_CONFIG, ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(UserSessionSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config("storage-user-sessions.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-client-sessions.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.spi(EventStoreSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config("storage-admin-events.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", ConcurrentHashMapStorageProviderFactory.PROVIDER_ID);
|
||||
.spi(EventStoreSpi.NAME).provider(MapUserSessionProviderFactory.PROVIDER_ID) .config("storage-admin-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID)
|
||||
.config("storage-auth-events.provider", JpaMapStorageProviderFactory.PROVIDER_ID);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,12 +12,15 @@
|
|||
|
||||
"eventsStore": {
|
||||
"provider": "${keycloak.eventsStore.provider:jpa}",
|
||||
"jpa": {
|
||||
"max-detail-length": "${keycloak.eventsStore.maxDetailLength:1000}"
|
||||
},
|
||||
"map": {
|
||||
"storage-admin-events": {
|
||||
"provider": "${keycloak.eventStore.map.storage.provider:concurrenthashmap}"
|
||||
"provider": "${keycloak.adminEventsStore.map.storage.provider:concurrenthashmap}"
|
||||
},
|
||||
"storage-auth-events": {
|
||||
"provider": "${keycloak.eventStore.map.storage.provider:concurrenthashmap}"
|
||||
"provider": "${keycloak.authEventsStore.map.storage.provider:concurrenthashmap}"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue