mirror of
https://gitee.com/jmix/cuba.git
synced 2024-12-03 03:38:33 +08:00
PL-10619 REST should have an ability to work without security token for entities with constraints
This commit is contained in:
parent
d4a739d2ea
commit
a499ca3dbb
@ -102,9 +102,17 @@ public interface PersistenceSecurity extends Security {
|
||||
* Validate that security token exists for specific cases.
|
||||
* For example, security constraints exists
|
||||
* @param entity - entity to check security token
|
||||
*/
|
||||
void assertToken(Entity entity);
|
||||
|
||||
|
||||
/**
|
||||
* Validate that security token for REST exists for specific cases.
|
||||
* For example, security constraints exists
|
||||
* @param entity - entity to check security token
|
||||
* @param view - view for entity
|
||||
*/
|
||||
void checkSecurityToken(Entity entity, View view);
|
||||
void assertTokenForREST(Entity entity, View view);
|
||||
|
||||
/**
|
||||
* Calculate filtered data
|
||||
|
@ -348,7 +348,7 @@ public class RdbmsStore implements DataStore {
|
||||
for (Entity entity : context.getCommitInstances()) {
|
||||
if (!PersistenceHelper.isNew(entity)) {
|
||||
if (isAuthorizationRequired()) {
|
||||
security.checkSecurityToken(entity, null);
|
||||
security.assertToken(entity);
|
||||
}
|
||||
security.restoreSecurityStateAndFilteredData(entity);
|
||||
attributeSecurity.beforeMerge(entity);
|
||||
@ -377,7 +377,7 @@ public class RdbmsStore implements DataStore {
|
||||
// remove
|
||||
for (Entity entity : context.getRemoveInstances()) {
|
||||
if (isAuthorizationRequired()) {
|
||||
security.checkSecurityToken(entity, null);
|
||||
security.assertToken(entity);
|
||||
}
|
||||
security.restoreSecurityStateAndFilteredData(entity);
|
||||
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright (c) 2008-2018 Haulmont.
|
||||
*
|
||||
* 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 com.haulmont.cuba.core.app.importexport;
|
||||
|
||||
import com.haulmont.cuba.core.entity.Entity;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class CollectionCompare {
|
||||
protected Consumer<Entity> createConsumer;
|
||||
protected Consumer<Entity> deleteConsumer;
|
||||
protected BiConsumer<Entity, Entity> updateConsumer;
|
||||
|
||||
private CollectionCompare() {
|
||||
}
|
||||
|
||||
public static CollectionCompare with() {
|
||||
return new CollectionCompare();
|
||||
}
|
||||
|
||||
public CollectionCompare onCreate(Consumer<Entity> createConsumer) {
|
||||
this.createConsumer = createConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CollectionCompare onDelete(Consumer<Entity> deleteConsumer) {
|
||||
this.deleteConsumer = deleteConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CollectionCompare onUpdate(BiConsumer<Entity, Entity> updateConsumer) {
|
||||
this.updateConsumer = updateConsumer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void compare(Collection<Entity> src, Collection<Entity> dst) {
|
||||
final Collection<Entity> srcNN = Optional.ofNullable(src)
|
||||
.orElse(Collections.emptyList());
|
||||
final Collection<Entity> dstNN = Optional.ofNullable(dst)
|
||||
.orElse(Collections.emptyList());
|
||||
for (Entity srcEntity : srcNN) {
|
||||
Optional<Entity> existingOptional = dstNN.stream()
|
||||
.filter(e -> Objects.equals(e, srcEntity))
|
||||
.findFirst();
|
||||
if (existingOptional.isPresent()) {
|
||||
updateConsumer.accept(srcEntity, existingOptional.get());
|
||||
} else {
|
||||
createConsumer.accept(srcEntity);
|
||||
}
|
||||
}
|
||||
dstNN.stream().filter(item -> !srcNN.contains(item)).forEach(deleteConsumer);
|
||||
}
|
||||
}
|
@ -17,14 +17,11 @@
|
||||
|
||||
package com.haulmont.cuba.core.app.importexport;
|
||||
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.haulmont.chile.core.model.MetaClass;
|
||||
import com.haulmont.chile.core.model.MetaProperty;
|
||||
import com.haulmont.chile.core.model.Range;
|
||||
import com.haulmont.cuba.core.Persistence;
|
||||
import com.haulmont.cuba.core.PersistenceSecurity;
|
||||
import com.haulmont.cuba.core.Transaction;
|
||||
import com.haulmont.cuba.core.app.DataStore;
|
||||
import com.haulmont.cuba.core.app.RdbmsStore;
|
||||
import com.haulmont.cuba.core.app.StoreFactory;
|
||||
@ -54,6 +51,7 @@ import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
import static java.lang.String.format;
|
||||
@ -91,6 +89,9 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
@Inject
|
||||
protected ReferenceToEntitySupport referenceToEntitySupport;
|
||||
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Override
|
||||
public byte[] exportEntitiesToZIP(Collection<? extends Entity> entities, View view) {
|
||||
return exportEntitiesToZIP(reloadEntities(entities, view));
|
||||
@ -286,25 +287,29 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
//we must specify a view here because otherwise we may get UnfetchedAttributeException during merge
|
||||
commitContext.addInstanceToCommit(dstEntity, regularView);
|
||||
|
||||
SecurityState securityState = null;
|
||||
if (srcEntity instanceof BaseGenericIdEntity && !createOp) {
|
||||
String storeName = metadata.getTools().getStoreName(srcEntity.getMetaClass());
|
||||
SecurityState dstSecurityState = null;
|
||||
SecurityState srcSecurityState = null;
|
||||
if (dstEntity instanceof BaseGenericIdEntity && !createOp) {
|
||||
String storeName = metadata.getTools().getStoreName(dstEntity.getMetaClass());
|
||||
DataStore dataStore = storeFactory.get(storeName);
|
||||
//row-level security works only for entities from RdbmsStore
|
||||
if (dataStore instanceof RdbmsStore) {
|
||||
persistenceSecurity.checkSecurityToken(srcEntity, regularView);
|
||||
persistenceSecurity.restoreSecurityState(srcEntity);
|
||||
securityState = BaseEntityInternalAccess.getSecurityState(srcEntity);
|
||||
if (useSecurityToken()) {
|
||||
persistenceSecurity.assertTokenForREST(srcEntity, regularView);
|
||||
persistenceSecurity.restoreSecurityState(srcEntity);
|
||||
srcSecurityState = BaseEntityInternalAccess.getSecurityState(srcEntity);
|
||||
}
|
||||
persistenceSecurity.restoreSecurityState(dstEntity);
|
||||
dstSecurityState = BaseEntityInternalAccess.getSecurityState(dstEntity);
|
||||
}
|
||||
}
|
||||
|
||||
for (EntityImportViewProperty importViewProperty : importView.getProperties()) {
|
||||
String propertyName = importViewProperty.getName();
|
||||
MetaProperty metaProperty = metaClass.getPropertyNN(propertyName);
|
||||
if (BaseEntityInternalAccess.isHiddenOrReadOnly(securityState, propertyName)) {
|
||||
if (BaseEntityInternalAccess.isHiddenOrReadOnly(dstSecurityState, propertyName)) {
|
||||
continue;
|
||||
}
|
||||
if (BaseEntityInternalAccess.isRequired(securityState, propertyName) && srcEntity.getValue(propertyName) == null) {
|
||||
if (BaseEntityInternalAccess.isRequired(dstSecurityState, propertyName) && srcEntity.getValue(propertyName) == null) {
|
||||
throw new CustomValidationException(format("Attribute [%s] is required for entity %s", propertyName, srcEntity));
|
||||
}
|
||||
if ((metaProperty.getRange().isDatatype() && !"version".equals(metaProperty.getName())) || metaProperty.getRange().isEnum()) {
|
||||
@ -319,13 +324,15 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
} else {
|
||||
switch (metaProperty.getRange().getCardinality()) {
|
||||
case MANY_TO_MANY:
|
||||
importManyToManyCollectionAttribute(srcEntity, dstEntity, createOp, importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
importManyToManyCollectionAttribute(srcEntity, dstEntity, srcSecurityState,
|
||||
importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
break;
|
||||
case ONE_TO_MANY:
|
||||
importOneToManyCollectionAttribute(srcEntity, dstEntity, importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
importOneToManyCollectionAttribute(srcEntity, dstEntity, srcSecurityState,
|
||||
importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
break;
|
||||
default:
|
||||
importReference(srcEntity, dstEntity, createOp, importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
importReference(srcEntity, dstEntity, importViewProperty, regularPropertyView, commitContext, referenceInfoList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -344,15 +351,14 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
|
||||
protected void importReference(Entity srcEntity,
|
||||
Entity dstEntity,
|
||||
boolean createOp,
|
||||
EntityImportViewProperty importViewProperty,
|
||||
View regularView,
|
||||
CommitContext commitContext,
|
||||
Collection<ReferenceInfo> referenceInfoList) {
|
||||
Entity srcPropertyValue = srcEntity.<Entity>getValue(importViewProperty.getName());
|
||||
Entity dstPropertyValue = dstEntity.<Entity>getValue(importViewProperty.getName());
|
||||
Entity srcPropertyValue = srcEntity.getValue(importViewProperty.getName());
|
||||
Entity dstPropertyValue = dstEntity.getValue(importViewProperty.getName());
|
||||
if (importViewProperty.getView() == null) {
|
||||
ReferenceInfo referenceInfo = new ReferenceInfo(dstEntity, createOp, importViewProperty, srcPropertyValue, dstPropertyValue);
|
||||
ReferenceInfo referenceInfo = new ReferenceInfo(dstEntity, null, importViewProperty, srcPropertyValue, dstPropertyValue);
|
||||
referenceInfoList.add(referenceInfo);
|
||||
} else {
|
||||
dstPropertyValue = importEntity(srcPropertyValue, dstPropertyValue, importViewProperty.getView(), regularView, commitContext, referenceInfoList);
|
||||
@ -362,118 +368,98 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
|
||||
protected void importOneToManyCollectionAttribute(Entity srcEntity,
|
||||
Entity dstEntity,
|
||||
EntityImportViewProperty importViewProperty,
|
||||
SecurityState srcSecurityState,
|
||||
EntityImportViewProperty viewProperty,
|
||||
View regularView,
|
||||
CommitContext commitContext,
|
||||
Collection<ReferenceInfo> referenceInfoList) {
|
||||
String propertyName = importViewProperty.getName();
|
||||
MetaProperty metaProperty = srcEntity.getMetaClass().getPropertyNN(propertyName);
|
||||
Collection<Entity> collectionValue = srcEntity.getValue(viewProperty.getName());
|
||||
Collection<Entity> prevCollectionValue = dstEntity.getValue(viewProperty.getName());
|
||||
MetaProperty metaProperty = srcEntity.getMetaClass().getPropertyNN(viewProperty.getName());
|
||||
MetaProperty inverseMetaProperty = metaProperty.getInverse();
|
||||
|
||||
//filteredItems collection will contain entities filtered by the row-level security
|
||||
Multimap<String, Object> filteredItems = ArrayListMultimap.create();
|
||||
if (srcEntity instanceof BaseGenericIdEntity) {
|
||||
String storeName = metadata.getTools().getStoreName(srcEntity.getMetaClass());
|
||||
DataStore dataStore = storeFactory.get(storeName);
|
||||
//row-level security works only for entities from RdbmsStore
|
||||
if (dataStore instanceof RdbmsStore) {
|
||||
filteredItems = BaseEntityInternalAccess.getFilteredData(srcEntity);
|
||||
}
|
||||
}
|
||||
|
||||
Collection<Entity> srcPropertyValue = srcEntity.getValue(propertyName);
|
||||
Collection<Entity> dstPropertyValue = dstEntity.getValue(propertyName);
|
||||
if (dstPropertyValue == null) dstPropertyValue = new ArrayList<>();
|
||||
Collection<Entity> collection;
|
||||
try {
|
||||
collection = srcPropertyValue.getClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error on import entities", e);
|
||||
}
|
||||
|
||||
if (srcPropertyValue != null) {
|
||||
for (Entity srcChildEntity : srcPropertyValue) {
|
||||
if (importViewProperty.getView() != null) {
|
||||
//create new referenced entity
|
||||
Entity dstChildEntity = null;
|
||||
for (Entity _entity : dstPropertyValue) {
|
||||
if (_entity.equals(srcChildEntity)) {
|
||||
dstChildEntity = _entity;
|
||||
break;
|
||||
Collection dstFilteredIds = getFilteredIds(dstEntity, metaProperty.getName());
|
||||
Collection srcFilteredIds = getFilteredIds(srcSecurityState, metaProperty.getName());
|
||||
Collection<Entity> newCollectionValue = createNewCollection(metaProperty);
|
||||
CollectionCompare.with()
|
||||
.onCreate(e -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
Entity result = importEntity(e, null, viewProperty.getView(), regularView,
|
||||
commitContext, referenceInfoList);
|
||||
if (inverseMetaProperty != null) {
|
||||
result.setValue(inverseMetaProperty.getName(), dstEntity);
|
||||
}
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
})
|
||||
.onUpdate((src, dst) -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(src))) {
|
||||
Entity result = importEntity(src, dst, viewProperty.getView(), regularView,
|
||||
commitContext, referenceInfoList);
|
||||
if (inverseMetaProperty != null) {
|
||||
result.setValue(inverseMetaProperty.getName(), dstEntity);
|
||||
}
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
})
|
||||
.onDelete(e -> {
|
||||
Object refId = referenceToEntitySupport.getReferenceId(e);
|
||||
if (viewProperty.getCollectionImportPolicy() == CollectionImportPolicy.REMOVE_ABSENT_ITEMS) {
|
||||
if (!dstFilteredIds.contains(refId) && !srcFilteredIds.contains(refId)) {
|
||||
commitContext.addInstanceToRemove(e);
|
||||
}
|
||||
}
|
||||
dstChildEntity = importEntity(srcChildEntity, dstChildEntity, importViewProperty.getView(), regularView, commitContext, referenceInfoList);
|
||||
if (inverseMetaProperty != null) {
|
||||
dstChildEntity.setValue(inverseMetaProperty.getName(), dstEntity);
|
||||
if (srcFilteredIds.contains(refId)) {
|
||||
newCollectionValue.add(e);
|
||||
}
|
||||
collection.add(dstChildEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (importViewProperty.getCollectionImportPolicy() == CollectionImportPolicy.REMOVE_ABSENT_ITEMS) {
|
||||
Collection<? extends Entity> dstValue = dstEntity.getValue(propertyName);
|
||||
if (dstValue != null) {
|
||||
Multimap<String, Object> finalFilteredItems = filteredItems;
|
||||
List<? extends Entity> collectionItemsToRemove = dstValue.stream()
|
||||
.filter(entity -> !collection.contains(entity) &&
|
||||
(finalFilteredItems == null || !finalFilteredItems.containsValue(referenceToEntitySupport.getReferenceId(entity))))
|
||||
.collect(Collectors.toList());
|
||||
for (Entity _entity : collectionItemsToRemove) {
|
||||
commitContext.addInstanceToRemove(_entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dstEntity.setValue(propertyName, collection);
|
||||
})
|
||||
.compare(collectionValue, prevCollectionValue);
|
||||
dstEntity.setValue(metaProperty.getName(), newCollectionValue);
|
||||
}
|
||||
|
||||
protected void importManyToManyCollectionAttribute(Entity srcEntity,
|
||||
Entity dstEntity,
|
||||
boolean createOp,
|
||||
EntityImportViewProperty importViewProperty,
|
||||
SecurityState srcSecurityState,
|
||||
EntityImportViewProperty viewProperty,
|
||||
View regularView,
|
||||
CommitContext commitContext,
|
||||
Collection<ReferenceInfo> referenceInfoList) {
|
||||
Collection<Entity> srcPropertyValue = srcEntity.getValue(importViewProperty.getName());
|
||||
Collection<Entity> dstPropertyValue = dstEntity.getValue(importViewProperty.getName());
|
||||
if (dstPropertyValue == null) dstPropertyValue = new ArrayList<>();
|
||||
if (importViewProperty.getView() != null) {
|
||||
//create/update passed entities
|
||||
Collection<Entity> collection;
|
||||
try {
|
||||
collection = srcPropertyValue.getClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error on import entities", e);
|
||||
}
|
||||
Collection<Entity> collectionValue = srcEntity.getValue(viewProperty.getName());
|
||||
Collection<Entity> prevCollectionValue = dstEntity.getValue(viewProperty.getName());
|
||||
MetaProperty metaProperty = srcEntity.getMetaClass().getPropertyNN(viewProperty.getName());
|
||||
Collection dstFilteredIds = getFilteredIds(dstEntity, metaProperty.getName());
|
||||
Collection srcFilteredIds = getFilteredIds(dstEntity, metaProperty.getName());
|
||||
|
||||
for (Entity srcChildEntity : srcPropertyValue) {
|
||||
//create new referenced entity
|
||||
Entity dstChildEntity = null;
|
||||
for (Entity _entity : dstPropertyValue) {
|
||||
if (_entity.equals(srcChildEntity)) {
|
||||
dstChildEntity = _entity;
|
||||
break;
|
||||
}
|
||||
}
|
||||
dstChildEntity = importEntity(srcChildEntity, dstChildEntity, importViewProperty.getView(), regularView, commitContext, referenceInfoList);
|
||||
collection.add(dstChildEntity);
|
||||
}
|
||||
|
||||
if (importViewProperty.getCollectionImportPolicy() == CollectionImportPolicy.KEEP_ABSENT_ITEMS) {
|
||||
Collection<Entity> existingCollectionValue = dstEntity.getValue(importViewProperty.getName());
|
||||
if (existingCollectionValue != null) {
|
||||
for (Entity existingCollectionItem : existingCollectionValue) {
|
||||
if (!collection.contains(existingCollectionItem)) collection.add(existingCollectionItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dstEntity.setValue(importViewProperty.getName(), collection);
|
||||
if (viewProperty.getView() != null) {
|
||||
Collection<Entity> newCollectionValue = createNewCollection(metaProperty);
|
||||
CollectionCompare.with()
|
||||
.onCreate(e -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
Entity result = importEntity(e, null, viewProperty.getView(), regularView,
|
||||
commitContext, referenceInfoList);
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
})
|
||||
.onUpdate((src, dst) -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(src))) {
|
||||
Entity result = importEntity(src, dst, viewProperty.getView(), regularView,
|
||||
commitContext, referenceInfoList);
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
})
|
||||
.onDelete(e -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
if (srcFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
newCollectionValue.add(e);
|
||||
} else if (viewProperty.getCollectionImportPolicy() == CollectionImportPolicy.KEEP_ABSENT_ITEMS) {
|
||||
newCollectionValue.add(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.compare(collectionValue, prevCollectionValue);
|
||||
dstEntity.setValue(metaProperty.getName(), newCollectionValue);
|
||||
} else {
|
||||
//create ReferenceInfo objects - they will be parsed later
|
||||
Collection<Entity> existingCollectionValue = dstEntity.getValue(importViewProperty.getName());
|
||||
ReferenceInfo referenceInfo = new ReferenceInfo(dstEntity, createOp, importViewProperty, srcPropertyValue, existingCollectionValue);
|
||||
ReferenceInfo referenceInfo = new ReferenceInfo(dstEntity, srcSecurityState, viewProperty, collectionValue, prevCollectionValue);
|
||||
referenceInfoList.add(referenceInfo);
|
||||
}
|
||||
}
|
||||
@ -497,24 +483,29 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
dstEmbeddedEntity = metadata.create(embeddedAttrMetaClass);
|
||||
}
|
||||
|
||||
SecurityState securityState = null;
|
||||
if (srcEntity instanceof BaseGenericIdEntity && !createOp) {
|
||||
String storeName = metadata.getTools().getStoreName(srcEntity.getMetaClass());
|
||||
SecurityState dstSecurityState = null;
|
||||
SecurityState srcSecurityState = null;
|
||||
if (dstEntity instanceof BaseGenericIdEntity && !createOp) {
|
||||
String storeName = metadata.getTools().getStoreName(dstEntity.getMetaClass());
|
||||
DataStore dataStore = storeFactory.get(storeName);
|
||||
//row-level security works only for entities from RdbmsStore
|
||||
if (dataStore instanceof RdbmsStore) {
|
||||
persistenceSecurity.checkSecurityToken(srcEmbeddedEntity, null);
|
||||
persistenceSecurity.restoreSecurityState(srcEmbeddedEntity);
|
||||
securityState = BaseEntityInternalAccess.getSecurityState(srcEmbeddedEntity);
|
||||
if (useSecurityToken()) {
|
||||
persistenceSecurity.assertTokenForREST(srcEmbeddedEntity, regularView);
|
||||
persistenceSecurity.restoreSecurityState(srcEmbeddedEntity);
|
||||
srcSecurityState = BaseEntityInternalAccess.getSecurityState(srcEmbeddedEntity);
|
||||
}
|
||||
persistenceSecurity.restoreSecurityState(dstEmbeddedEntity);
|
||||
dstSecurityState = BaseEntityInternalAccess.getSecurityState(dstEmbeddedEntity);
|
||||
}
|
||||
}
|
||||
|
||||
for (EntityImportViewProperty vp : importViewProperty.getView().getProperties()) {
|
||||
MetaProperty mp = embeddedAttrMetaClass.getPropertyNN(vp.getName());
|
||||
if (BaseEntityInternalAccess.isHiddenOrReadOnly(securityState, mp.getName())) {
|
||||
if (BaseEntityInternalAccess.isHiddenOrReadOnly(dstSecurityState, mp.getName())) {
|
||||
continue;
|
||||
}
|
||||
if (BaseEntityInternalAccess.isRequired(securityState, mp.getName()) && srcEmbeddedEntity.getValue(mp.getName()) == null) {
|
||||
if (BaseEntityInternalAccess.isRequired(dstSecurityState, mp.getName()) && srcEmbeddedEntity.getValue(mp.getName()) == null) {
|
||||
throw new CustomValidationException(format("Attribute [%s] is required for entity %s", mp.getName(), srcEmbeddedEntity));
|
||||
}
|
||||
if ((mp.getRange().isDatatype() && !"version".equals(mp.getName())) || mp.getRange().isEnum()) {
|
||||
@ -522,11 +513,13 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
} else if (mp.getRange().isClass()) {
|
||||
View propertyRegularView = regularView.getProperty(propertyName) != null ? regularView.getProperty(propertyName).getView() : null;
|
||||
if (metaProperty.getRange().getCardinality() == Range.Cardinality.ONE_TO_MANY) {
|
||||
importOneToManyCollectionAttribute(srcEmbeddedEntity, dstEmbeddedEntity, vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
importOneToManyCollectionAttribute(srcEmbeddedEntity, dstEmbeddedEntity, srcSecurityState,
|
||||
vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
} else if (metaProperty.getRange().getCardinality() == Range.Cardinality.MANY_TO_MANY) {
|
||||
importManyToManyCollectionAttribute(srcEmbeddedEntity, dstEmbeddedEntity, false, vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
importManyToManyCollectionAttribute(srcEmbeddedEntity, dstEmbeddedEntity, srcSecurityState,
|
||||
vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
} else {
|
||||
importReference(srcEmbeddedEntity, dstEmbeddedEntity, false, vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
importReference(srcEmbeddedEntity, dstEmbeddedEntity, vp, propertyRegularView, commitContext, referenceInfoList);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -540,109 +533,69 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
*/
|
||||
protected void processReferenceInfo(ReferenceInfo referenceInfo, CommitContext commitContext, Set<Entity> loadedEntities) {
|
||||
Entity entity = referenceInfo.getEntity();
|
||||
String propertyName = referenceInfo.getViewProperty().getName();
|
||||
MetaProperty metaProperty = entity.getMetaClass().getPropertyNN(propertyName);
|
||||
EntityImportViewProperty viewProperty = referenceInfo.getViewProperty();
|
||||
MetaProperty metaProperty = entity.getMetaClass().getPropertyNN(viewProperty.getName());
|
||||
Collection dstFilteredIds = getFilteredIds(entity, metaProperty.getName());
|
||||
Collection srcFilteredIds = getFilteredIds(referenceInfo.getPrevSecurityState(), metaProperty.getName());
|
||||
|
||||
if (metaProperty.getRange().getCardinality() == Range.Cardinality.MANY_TO_MANY) {
|
||||
Collection<Entity> propertyValue = (Collection<Entity>) referenceInfo.getPropertyValue();
|
||||
if (propertyValue == null) {
|
||||
entity.setValue(propertyName, null);
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Entity> collectionValue = (Collection<Entity>) referenceInfo.getPropertyValue();
|
||||
@SuppressWarnings("unchecked")
|
||||
Collection<Entity> prevCollectionValue = (Collection<Entity>) referenceInfo.getPrevPropertyValue();
|
||||
if (collectionValue == null && srcFilteredIds.isEmpty()) {
|
||||
entity.setValue(metaProperty.getName(), createNewCollection(metaProperty));
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<Entity> collection;
|
||||
try {
|
||||
collection = propertyValue.getClass().newInstance();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error on import entities", e);
|
||||
}
|
||||
|
||||
for (Entity childEntity : propertyValue) {
|
||||
Entity entityFromLoadedEntities = findEntityInCollection(loadedEntities, childEntity);
|
||||
if (entityFromLoadedEntities != null) {
|
||||
collection.add(entityFromLoadedEntities);
|
||||
} else {
|
||||
Entity entityFromCommitContext = findEntityInCollection(commitContext.getCommitInstances(), childEntity);
|
||||
if (entityFromCommitContext != null) {
|
||||
collection.add(entityFromCommitContext);
|
||||
} else {
|
||||
LoadContext<? extends Entity> ctx = LoadContext.create(childEntity.getClass())
|
||||
.setSoftDeletion(false)
|
||||
.setView(View.MINIMAL)
|
||||
.setId(childEntity.getId());
|
||||
Entity loadedReference = dataManager.load(ctx);
|
||||
if (loadedReference == null) {
|
||||
if (referenceInfo.getViewProperty().getReferenceImportBehaviour() == ReferenceImportBehaviour.ERROR_ON_MISSING) {
|
||||
throw new EntityImportException("Referenced entity for property '" + propertyName + "' with id = " + entity.getId() + " is missing");
|
||||
Collection<Entity> newCollectionValue = createNewCollection(metaProperty);
|
||||
CollectionCompare.with()
|
||||
.onCreate(e -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
Entity result = findReferenceEntity(e, viewProperty, commitContext, loadedEntities);
|
||||
if (result != null) {
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
} else {
|
||||
collection.add(loadedReference);
|
||||
loadedEntities.add(loadedReference);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//keep absent collection members if we need it
|
||||
if (referenceInfo.getViewProperty().getCollectionImportPolicy() == CollectionImportPolicy.KEEP_ABSENT_ITEMS) {
|
||||
Collection<Entity> prevCollectionValue = (Collection<Entity>) referenceInfo.getPrevPropertyValue();
|
||||
if (prevCollectionValue != null) {
|
||||
for (Entity prevCollectionItem : prevCollectionValue) {
|
||||
if (!collection.contains(prevCollectionItem)) {
|
||||
collection.add(prevCollectionItem);
|
||||
})
|
||||
.onUpdate((src, dst) -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(dst))) {
|
||||
Entity result = findReferenceEntity(src, viewProperty, commitContext, loadedEntities);
|
||||
if (result != null) {
|
||||
newCollectionValue.add(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
entity.setValue(propertyName, collection);
|
||||
|
||||
//row-level security works only for entities from RdbmsStore
|
||||
String storeName = metadata.getTools().getStoreName(entity.getMetaClass());
|
||||
DataStore dataStore = storeFactory.get(storeName);
|
||||
if (dataStore instanceof RdbmsStore && !referenceInfo.isCreateOp()) {
|
||||
//restore filtered data, otherwise they will be lost
|
||||
try (Transaction tx = persistence.getTransaction()) {
|
||||
persistenceSecurity.checkSecurityToken((BaseGenericIdEntity<?>) entity, null);
|
||||
persistenceSecurity.restoreSecurityStateAndFilteredData((BaseGenericIdEntity<?>) entity);
|
||||
tx.commit();
|
||||
}
|
||||
}
|
||||
})
|
||||
.onDelete(e -> {
|
||||
if (!dstFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
if (srcFilteredIds.contains(referenceToEntitySupport.getReferenceId(e))) {
|
||||
newCollectionValue.add(e);
|
||||
} else if (viewProperty.getCollectionImportPolicy() == CollectionImportPolicy.KEEP_ABSENT_ITEMS) {
|
||||
newCollectionValue.add(e);
|
||||
}
|
||||
}
|
||||
})
|
||||
.compare(collectionValue, prevCollectionValue);
|
||||
entity.setValue(metaProperty.getName(), newCollectionValue);
|
||||
//end of many-to-many processing block
|
||||
} else {
|
||||
//all other reference types (except many-to-many)
|
||||
Entity propertyValue = (Entity) referenceInfo.getPropertyValue();
|
||||
if (propertyValue == null) {
|
||||
entity.setValue(propertyName, null);
|
||||
//in case of NULL value we must delete COMPOSITION entities
|
||||
if (metaProperty.getType() == MetaProperty.Type.COMPOSITION) {
|
||||
Object prevPropertyValue = referenceInfo.getPrevPropertyValue();
|
||||
if (prevPropertyValue != null) {
|
||||
commitContext.addInstanceToRemove((Entity) prevPropertyValue);
|
||||
Entity entityValue = (Entity) referenceInfo.getPropertyValue();
|
||||
if (entityValue == null) {
|
||||
if (dstFilteredIds.isEmpty()) {
|
||||
entity.setValue(metaProperty.getName(), null);
|
||||
//in case of NULL value we must delete COMPOSITION entities
|
||||
if (metaProperty.getType() == MetaProperty.Type.COMPOSITION) {
|
||||
Entity prevEntityValue = (Entity) referenceInfo.getPrevPropertyValue();
|
||||
if (prevEntityValue != null) {
|
||||
commitContext.addInstanceToRemove(prevEntityValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Entity entityFromLoadedEntities = findEntityInCollection(loadedEntities, propertyValue);
|
||||
if (entityFromLoadedEntities != null) {
|
||||
entity.setValue(propertyName, entityFromLoadedEntities);
|
||||
} else {
|
||||
Entity entityFromCommitContext = findEntityInCollection(commitContext.getCommitInstances(), propertyValue);
|
||||
|
||||
if (entityFromCommitContext != null) {
|
||||
entity.setValue(propertyName, entityFromCommitContext);
|
||||
} else {
|
||||
LoadContext<? extends Entity> ctx = LoadContext.create(propertyValue.getClass())
|
||||
.setSoftDeletion(false)
|
||||
.setId(propertyValue.getId());
|
||||
dataManager.load(ctx);
|
||||
Entity loadedReference = dataManager.load(ctx);
|
||||
if (loadedReference == null) {
|
||||
if (referenceInfo.getViewProperty().getReferenceImportBehaviour() == ReferenceImportBehaviour.ERROR_ON_MISSING) {
|
||||
throw new EntityImportException("Referenced entity for property '" + propertyName + "' with id = " + propertyValue.getId() + " is missing");
|
||||
}
|
||||
} else {
|
||||
entity.setValue(propertyName, loadedReference);
|
||||
loadedEntities.add(loadedReference);
|
||||
}
|
||||
if (dstFilteredIds.isEmpty()) {
|
||||
Entity result = findReferenceEntity(entityValue, viewProperty, commitContext, loadedEntities);
|
||||
if (result != null) {
|
||||
entity.setValue(metaProperty.getName(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -673,27 +626,82 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
return regularView;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected Entity findEntityInCollection(Collection<Entity> collection, Entity entity) {
|
||||
for (Entity entityFromCollection : collection) {
|
||||
if (entityFromCollection.equals(entity)) return entityFromCollection;
|
||||
protected Collection getFilteredIds(Entity entity, String propertyName) {
|
||||
if (entity instanceof BaseGenericIdEntity) {
|
||||
String storeName = metadata.getTools().getStoreName(entity.getMetaClass());
|
||||
DataStore dataStore = storeFactory.get(storeName);
|
||||
if (dataStore instanceof RdbmsStore) {
|
||||
persistenceSecurity.restoreSecurityState(entity);
|
||||
return Optional.ofNullable(BaseEntityInternalAccess.getFilteredData(entity))
|
||||
.map(v -> v.get(propertyName))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Collection getFilteredIds(SecurityState securityState, String propertyName) {
|
||||
if (securityState != null) {
|
||||
return Optional.ofNullable(BaseEntityInternalAccess.getFilteredData(securityState))
|
||||
.map(v -> v.get(propertyName))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
protected Collection<Entity> createNewCollection(MetaProperty metaProperty) {
|
||||
Collection<Entity> entities;
|
||||
Class<?> propertyType = metaProperty.getJavaType();
|
||||
if (List.class.isAssignableFrom(propertyType)) {
|
||||
entities = new ArrayList<>();
|
||||
} else if (Set.class.isAssignableFrom(propertyType)) {
|
||||
entities = new LinkedHashSet<>();
|
||||
} else {
|
||||
throw new RuntimeException(String.format("Could not instantiate collection with class [%s].", propertyType));
|
||||
}
|
||||
return entities;
|
||||
}
|
||||
|
||||
protected boolean useSecurityToken() {
|
||||
return globalConfig.getRestUseSecurityTokenForClient();
|
||||
}
|
||||
|
||||
protected Entity findReferenceEntity(Entity entity, EntityImportViewProperty viewProperty, CommitContext commitContext,
|
||||
Set<Entity> loadedEntities) {
|
||||
Entity result = Stream.concat(loadedEntities.stream(), commitContext.getCommitInstances().stream())
|
||||
.filter(item -> item.equals(entity))
|
||||
.findFirst().orElse(null);
|
||||
if (result == null) {
|
||||
LoadContext<? extends Entity> ctx = LoadContext.create(entity.getClass())
|
||||
.setSoftDeletion(false)
|
||||
.setView(View.MINIMAL)
|
||||
.setId(entity.getId());
|
||||
result = dataManager.load(ctx);
|
||||
if (result == null) {
|
||||
if (viewProperty.getReferenceImportBehaviour() == ReferenceImportBehaviour.ERROR_ON_MISSING) {
|
||||
throw new EntityImportException(String.format("Referenced entity for property '%s' with id = %s is missing",
|
||||
viewProperty.getName(), entity.getId()));
|
||||
}
|
||||
} else {
|
||||
loadedEntities.add(result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected class ReferenceInfo {
|
||||
protected Entity entity;
|
||||
protected boolean createOp;
|
||||
protected SecurityState prevSecurityState;
|
||||
protected EntityImportViewProperty viewProperty;
|
||||
protected Object propertyValue;
|
||||
protected Object prevPropertyValue;
|
||||
|
||||
public ReferenceInfo(Entity entity, boolean createOp, EntityImportViewProperty viewProperty, Object propertyValue, Object prevPropertyValue) {
|
||||
public ReferenceInfo(Entity entity, SecurityState prevSecurityState, EntityImportViewProperty viewProperty, Object propertyValue, Object prevPropertyValue) {
|
||||
this.entity = entity;
|
||||
this.prevSecurityState = prevSecurityState;
|
||||
this.viewProperty = viewProperty;
|
||||
this.propertyValue = propertyValue;
|
||||
this.prevPropertyValue = prevPropertyValue;
|
||||
this.createOp = createOp;
|
||||
}
|
||||
|
||||
public EntityImportViewProperty getViewProperty() {
|
||||
@ -708,12 +716,12 @@ public class EntityImportExport implements EntityImportExportAPI {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public SecurityState getPrevSecurityState() {
|
||||
return prevSecurityState;
|
||||
}
|
||||
|
||||
public Object getPropertyValue() {
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
public boolean isCreateOp() {
|
||||
return createOp;
|
||||
}
|
||||
}
|
||||
}
|
@ -41,6 +41,7 @@ import org.slf4j.LoggerFactory;
|
||||
import javax.inject.Inject;
|
||||
import java.io.Serializable;
|
||||
import java.util.*;
|
||||
import java.util.function.BiPredicate;
|
||||
|
||||
import static java.lang.String.format;
|
||||
|
||||
@ -66,6 +67,9 @@ public class PersistenceSecurityImpl extends SecurityImpl implements Persistence
|
||||
@Inject
|
||||
protected EntityStates entityStates;
|
||||
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
@Override
|
||||
public boolean applyConstraints(Query query) {
|
||||
QueryParser parser = QueryTransformerFactory.createParser(query.getQueryString());
|
||||
@ -213,30 +217,47 @@ public class PersistenceSecurityImpl extends SecurityImpl implements Persistence
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkSecurityToken(Entity entity, View view) {
|
||||
public void assertToken(Entity entity) {
|
||||
if (BaseEntityInternalAccess.getSecurityToken(entity) == null) {
|
||||
MetaClass metaClass = metadata.getClassNN(entity.getClass());
|
||||
for (MetaProperty metaProperty : metaClass.getProperties()) {
|
||||
if (metaProperty.getRange().isClass() && metadataTools.isPersistent(metaProperty)) {
|
||||
if (entityStates.isDetached(entity) && !entityStates.isLoaded(entity, metaProperty.getName())) {
|
||||
continue;
|
||||
} else if (view != null && !view.containsProperty(metaProperty.getName())) {
|
||||
continue;
|
||||
}
|
||||
List<ConstraintData> existingConstraints = getConstraints(metaProperty.getRange().asClass(),
|
||||
constraint -> constraint.getCheckType().memory());
|
||||
if (CollectionUtils.isNotEmpty(existingConstraints)) {
|
||||
throw new RowLevelSecurityException(format("Could not read security token from entity %s, " +
|
||||
"even though there are active constraints for the related entities.", entity),
|
||||
entity.getMetaClass().getName());
|
||||
}
|
||||
assertSecurityConstraints(entity, (e, metaProperty) -> entityStates.isDetached(entity)
|
||||
&& !entityStates.isLoaded(entity, metaProperty.getName()));
|
||||
assertTokenForAttributeAccess(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void assertTokenForREST(Entity entity, View view) {
|
||||
if (BaseEntityInternalAccess.getSecurityToken(entity) == null) {
|
||||
assertSecurityConstraints(entity,
|
||||
(e, metaProperty) -> view != null && !view.containsProperty(metaProperty.getName()));
|
||||
assertTokenForAttributeAccess(entity);
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertSecurityConstraints(Entity entity, BiPredicate<Entity, MetaProperty> predicate) {
|
||||
MetaClass metaClass = metadata.getClassNN(entity.getClass());
|
||||
for (MetaProperty metaProperty : metaClass.getProperties()) {
|
||||
if (metaProperty.getRange().isClass() && metadataTools.isPersistent(metaProperty)) {
|
||||
if (predicate.test(entity, metaProperty)) {
|
||||
continue;
|
||||
}
|
||||
if (hasInMemoryConstraints(metaProperty.getRange().asClass(), ConstraintOperationType.READ,
|
||||
ConstraintOperationType.ALL)) {
|
||||
throw new RowLevelSecurityException(format("Could not read security token from entity %s, " +
|
||||
"even though there are active READ/ALL constraints for the property: %s", entity,
|
||||
metaProperty.getName()),
|
||||
entity.getMetaClass().getName());
|
||||
}
|
||||
}
|
||||
if (attributeSecuritySupport.isAttributeAccessEnabled(metaClass)) {
|
||||
throw new RowLevelSecurityException(format("Could not read security token from entity %s, " +
|
||||
"even though there are active attribute access for the entity.", entity),
|
||||
entity.getMetaClass().getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertTokenForAttributeAccess(Entity entity) {
|
||||
MetaClass metaClass = metadata.getClassNN(entity.getClass());
|
||||
if (attributeSecuritySupport.isAttributeAccessEnabled(metaClass)) {
|
||||
throw new RowLevelSecurityException(format("Could not read security token from entity %s, " +
|
||||
"even though there are active attribute access for the entity.", entity),
|
||||
entity.getMetaClass().getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -66,10 +66,7 @@ public class SecurityTokenManager {
|
||||
String[] filteredAttributes = new String[entries.size()];
|
||||
int i = 0;
|
||||
for (Map.Entry<String, Collection<Object>> entry : entries) {
|
||||
MetaProperty metaProperty = entity.getMetaClass().getPropertyNN(entry.getKey());
|
||||
if (metadata.getTools().isOwningSide(metaProperty)) {
|
||||
jsonObject.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
jsonObject.put(entry.getKey(), entry.getValue());
|
||||
filteredAttributes[i++] = entry.getKey();
|
||||
}
|
||||
setFilteredAttributes(securityState, filteredAttributes);
|
||||
|
@ -65,6 +65,9 @@ public class EntitySerialization implements EntitySerializationAPI {
|
||||
@Inject
|
||||
protected DynamicAttributes dynamicAttributes;
|
||||
|
||||
@Inject
|
||||
protected GlobalConfig globalConfig;
|
||||
|
||||
protected ThreadLocal<EntitySerializationContext> context =
|
||||
ThreadLocal.withInitial(EntitySerializationContext::new);
|
||||
|
||||
@ -228,12 +231,14 @@ public class EntitySerialization implements EntitySerializationAPI {
|
||||
writeFields(entity, jsonObject, view, cyclicReferences);
|
||||
}
|
||||
|
||||
if (entity instanceof BaseGenericIdEntity || entity instanceof EmbeddableEntity) {
|
||||
SecurityState securityState = getSecurityState(entity);
|
||||
if (securityState != null) {
|
||||
byte[] securityToken = getSecurityToken(securityState);
|
||||
if (securityToken != null) {
|
||||
jsonObject.addProperty("__securityToken", Base64.getEncoder().encodeToString(securityToken));
|
||||
if (globalConfig.getRestUseSecurityTokenForClient()) {
|
||||
if (entity instanceof BaseGenericIdEntity || entity instanceof EmbeddableEntity) {
|
||||
SecurityState securityState = getSecurityState(entity);
|
||||
if (securityState != null) {
|
||||
byte[] securityToken = getSecurityToken(securityState);
|
||||
if (securityToken != null) {
|
||||
jsonObject.addProperty("__securityToken", Base64.getEncoder().encodeToString(securityToken));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -456,7 +461,7 @@ public class EntitySerialization implements EntitySerializationAPI {
|
||||
}
|
||||
}
|
||||
|
||||
if (entity instanceof BaseGenericIdEntity) {
|
||||
if (globalConfig.getRestUseSecurityTokenForClient() && entity instanceof BaseGenericIdEntity) {
|
||||
JsonPrimitive securityTokenJonPrimitive = jsonObject.getAsJsonPrimitive("__securityToken");
|
||||
if (securityTokenJonPrimitive != null) {
|
||||
byte[] securityToken = Base64.getDecoder().decode(securityTokenJonPrimitive.getAsString());
|
||||
@ -567,7 +572,7 @@ public class EntitySerialization implements EntitySerializationAPI {
|
||||
Entity entity = metadata.create(metaClass);
|
||||
clearFields(entity);
|
||||
readFields(jsonObject, entity);
|
||||
if (entity instanceof EmbeddableEntity) {
|
||||
if (globalConfig.getRestUseSecurityTokenForClient() && entity instanceof EmbeddableEntity) {
|
||||
JsonPrimitive securityTokenJonPrimitive = jsonObject.getAsJsonPrimitive("__securityToken");
|
||||
if (securityTokenJonPrimitive != null) {
|
||||
byte[] securityToken = Base64.getDecoder().decode(securityTokenJonPrimitive.getAsString());
|
||||
|
@ -234,4 +234,12 @@ public interface GlobalConfig extends Config {
|
||||
@Property("cuba.enableIdGenerationForEntitiesInAdditionalDataStores")
|
||||
@DefaultBoolean(true)
|
||||
boolean getEnableIdGenerationForEntitiesInAdditionalDataStores();
|
||||
|
||||
/**
|
||||
* @return true if REST doesn't check security token for entities with security constraints
|
||||
*/
|
||||
@Property("cuba.rest.useSecurityTokenForClient")
|
||||
@Source(type = SourceType.DATABASE)
|
||||
@DefaultBoolean(false)
|
||||
boolean getRestUseSecurityTokenForClient();
|
||||
}
|
Loading…
Reference in New Issue
Block a user