diff --git a/modules/core/src/com/haulmont/cuba/core/app/AttributeSecuritySupport.java b/modules/core/src/com/haulmont/cuba/core/app/AttributeSecuritySupport.java new file mode 100644 index 0000000000..7c3db6cd92 --- /dev/null +++ b/modules/core/src/com/haulmont/cuba/core/app/AttributeSecuritySupport.java @@ -0,0 +1,216 @@ +/* + * Copyright (c) 2008-2015 Haulmont. All rights reserved. + * Use is subject to license terms, see http://www.cuba-platform.com/license for details. + */ + +package com.haulmont.cuba.core.app; + +import com.haulmont.bali.util.Preconditions; +import com.haulmont.chile.core.model.MetaClass; +import com.haulmont.chile.core.model.MetaProperty; +import com.haulmont.cuba.core.PersistenceSecurity; +import com.haulmont.cuba.core.entity.BaseGenericIdEntity; +import com.haulmont.cuba.core.entity.Entity; +import com.haulmont.cuba.core.global.*; +import com.haulmont.cuba.core.sys.persistence.CubaEntityFetchGroup; +import org.eclipse.persistence.queries.FetchGroup; +import org.eclipse.persistence.queries.FetchGroupTracker; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +/** + * Supports enforcing entity attribute permissions on Middleware. + * + * @author Konstantin Krivopustov + * @version $Id$ + */ +@Component(AttributeSecuritySupport.NAME) +public class AttributeSecuritySupport { + + public static final String NAME = "cuba_AttributeSecuritySupport"; + + @Inject + protected Metadata metadata; + + @Inject + protected MetadataTools metadataTools; + + @Inject + protected PersistenceSecurity security; + + @Inject + protected ServerConfig config; + + /** + * Removes restricted attributes from a view. + * + * @param view source view + * @return restricted view + */ + public View createRestrictedView(View view) { + if (!config.getEntityAttributePermissionChecking()) { + return view; + } + Preconditions.checkNotNullArgument(view, "view is null"); + + View restrictedView = new View(view.getEntityClass()); + copyViewConsideringPermissions(view, restrictedView); + return restrictedView; + } + + private void copyViewConsideringPermissions(View srcView, View dstView) { + MetaClass metaClass = metadata.getClassNN(srcView.getEntityClass()); + for (ViewProperty property : srcView.getProperties()) { + if (security.isEntityAttrReadPermitted(metaClass, property.getName())) { + View viewCopy = null; + if (property.getView() != null) { + viewCopy = new View(property.getView().getEntityClass(), property.getView().getName() + "(restricted)"); + copyViewConsideringPermissions(property.getView(), viewCopy); + } + dstView.addProperty(property.getName(), viewCopy, property.getFetchMode()); + } + } + } + + /** + * Should be called after loading an entity from the database. + * + * @param entity just loaded detached entity + */ + public void afterLoad(Entity entity) { + if (!config.getEntityAttributePermissionChecking()) { + return; + } + if (entity != null) { + metadataTools.traverseAttributes(entity, new FillingInaccessibleAttributesVisitor()); + } + } + + /** + * Should be called after loading a list of entities from the database. + * + * @param entities list of just loaded detached entities + */ + public void afterLoad(Collection entities) { + if (!config.getEntityAttributePermissionChecking()) { + return; + } + Preconditions.checkNotNullArgument(entities, "entities list is null"); + + for (Entity entity : entities) { + afterLoad(entity); + } + } + + /** + * Should be called before persisting a new entity. + * + * @param entity new entity + */ + public void beforePersist(Entity entity) { + if (!config.getEntityAttributePermissionChecking()) { + return; + } + metadata.getTools().traverseAttributes(entity, new ClearReadOnlyAttributesVisitor()); + } + + /** + * Should be called before merging an entity. + * + * @param entity detached entity + */ + public void beforeMerge(Entity entity) { + if (!config.getEntityAttributePermissionChecking()) { + return; + } + MetaClass metaClass = metadata.getClassNN(entity.getClass()); + FetchGroup fetchGroup = ((FetchGroupTracker) entity)._persistence_getFetchGroup(); + if (fetchGroup != null) { + List attributesToRemove = new ArrayList<>(); + for (String attrName : fetchGroup.getAttributeNames()) { + String[] parts = attrName.split("\\."); + MetaClass tmpMetaClass = metaClass; + for (String part : parts) { + if (!security.isEntityAttrUpdatePermitted(tmpMetaClass, part)) { + attributesToRemove.add(attrName); + break; + } + MetaProperty metaProperty = tmpMetaClass.getPropertyNN(part); + if (metaProperty.getRange().isClass()) { + tmpMetaClass = metaProperty.getRange().asClass(); + } + } + } + if (!attributesToRemove.isEmpty()) { + List attributeNames = new ArrayList<>(fetchGroup.getAttributeNames()); + attributeNames.removeAll(attributesToRemove); + ((FetchGroupTracker) entity)._persistence_setFetchGroup(new CubaEntityFetchGroup(attributeNames)); + } + } else { + List attributeNames = new ArrayList<>(); + for (MetaProperty metaProperty : metaClass.getProperties()) { + if (security.isEntityAttrUpdatePermitted(metaClass, metaProperty.getName())) { + attributeNames.add(metaProperty.getName()); + } + } + ((FetchGroupTracker) entity)._persistence_setFetchGroup(new CubaEntityFetchGroup(attributeNames)); + } + } + + /** + * Should be called after merging an entity and transaction commit. + * + * @param entity detached entity + */ + public void afterMerge(Entity entity, View view) { + if (!config.getEntityAttributePermissionChecking()) { + return; + } + if (entity != null) { + metadataTools.traverseAttributesByView(view, entity, new ClearInaccessibleAttributesVisitor()); + } + } + + private void addInaccessibleAttribute(BaseGenericIdEntity entity, String property) { + String[] attributes = entity.__inaccessibleAttributes(); + attributes = attributes == null ? new String[1] : Arrays.copyOf(attributes, attributes.length + 1); + attributes[attributes.length - 1] = property; + entity.__inaccessibleAttributes(attributes); + } + + private class FillingInaccessibleAttributesVisitor implements EntityAttributeVisitor { + @Override + public void visit(Entity entity, MetaProperty property) { + MetaClass metaClass = metadata.getClassNN(entity.getClass()); + if (!security.isEntityAttrReadPermitted(metaClass, property.getName())) { + addInaccessibleAttribute((BaseGenericIdEntity) entity, property.getName()); + } + } + } + + private class ClearReadOnlyAttributesVisitor implements EntityAttributeVisitor { + @Override + public void visit(Entity entity, MetaProperty property) { + MetaClass metaClass = metadata.getClassNN(entity.getClass()); + if (!security.isEntityAttrUpdatePermitted(metaClass, property.getName())) { + entity.setValue(property.getName(), null); + } + } + } + + private class ClearInaccessibleAttributesVisitor implements EntityAttributeVisitor { + @Override + public void visit(Entity entity, MetaProperty property) { + MetaClass metaClass = metadata.getClassNN(entity.getClass()); + if (!security.isEntityAttrReadPermitted(metaClass, property.getName())) { + addInaccessibleAttribute((BaseGenericIdEntity) entity, property.getName()); + entity.setValue(property.getName(), null); + } + } + } +} diff --git a/modules/core/src/com/haulmont/cuba/core/app/DataManagerBean.java b/modules/core/src/com/haulmont/cuba/core/app/DataManagerBean.java index edbe69a154..7fc001f17e 100644 --- a/modules/core/src/com/haulmont/cuba/core/app/DataManagerBean.java +++ b/modules/core/src/com/haulmont/cuba/core/app/DataManagerBean.java @@ -26,8 +26,8 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; - import org.springframework.stereotype.Component; + import javax.annotation.Nullable; import javax.inject.Inject; import java.util.*; @@ -55,6 +55,9 @@ public class DataManagerBean implements DataManager { @Inject protected PersistenceSecurity security; + @Inject + protected AttributeSecuritySupport attributeSecurity; + @Inject protected Persistence persistence; @@ -95,7 +98,7 @@ public class DataManagerBean implements DataManager { com.haulmont.cuba.core.Query query = createQuery(em, context); //noinspection unchecked - List resultList = query.getResultList(); + List resultList = executeQuery(query); if (!resultList.isEmpty()) result = resultList.get(0); @@ -108,6 +111,8 @@ public class DataManagerBean implements DataManager { tx.end(); } + attributeSecurity.afterLoad(result); + return result; } @@ -161,6 +166,8 @@ public class DataManagerBean implements DataManager { tx.end(); } + attributeSecurity.afterLoad(resultList); + return resultList; } @@ -225,6 +232,7 @@ public class DataManagerBean implements DataManager { // persist new for (Entity entity : context.getCommitInstances()) { if (PersistenceHelper.isNew(entity)) { + attributeSecurity.beforePersist(entity); em.persist(entity); res.add(entity); persisted.add(entity); @@ -238,8 +246,14 @@ public class DataManagerBean implements DataManager { // merge detached for (Entity entity : context.getCommitInstances()) { if (PersistenceHelper.isDetached(entity)) { + attributeSecurity.beforeMerge(entity); View view = context.getViews().get(entity); - Entity merged = em.merge(entity, view); + if (view == null) { + view = viewRepository.getView(entity.getClass(), View.LOCAL); + } + View restrictedView = attributeSecurity.createRestrictedView(view); + + Entity merged = em.merge(entity, restrictedView); res.add(merged); if (entityHasDynamicAttributes(entity)) { BaseGenericIdEntity originalBaseGenericIdEntity = (BaseGenericIdEntity) entity; @@ -280,6 +294,16 @@ public class DataManagerBean implements DataManager { tx.end(); } + for (Entity entity : res) { + if (!persisted.contains(entity)) { + View view = context.getViews().get(entity); + if (view == null) { + view = viewRepository.getView(entity.getClass(), View.LOCAL); + } + attributeSecurity.afterMerge(entity, view); + } + } + updateReferences(persisted, res); return res; @@ -415,10 +439,13 @@ public class DataManagerBean implements DataManager { } if (entityLoadInfoBuilder.contains(newInstances, entity)) { + attributeSecurity.beforePersist(entity); em.persist(entity); result.add(entity); } else { - Entity e = em.merge(entity); + attributeSecurity.beforeMerge(entity); + View view = context.getViews().get(entity); + Entity e = em.merge(entity, view); result.add(e); } } @@ -486,16 +513,16 @@ public class DataManagerBean implements DataManager { query.setMaxResults(contextQuery.getMaxResults()); } - if (context.getView() != null) { - query.setView(context.getView()); - } + View view = context.getView() != null ? context.getView() : + viewRepository.getView(metadata.getClassNN(context.getMetaClass()), View.LOCAL); + View restrictedView = attributeSecurity.createRestrictedView(view); + query.setView(restrictedView); return query; } protected List getResultList(LoadContext context, Query query, boolean ensureDistinct) { - //noinspection unchecked - List list = query.getResultList(); + List list = executeQuery(query); if (!ensureDistinct || list.size() == 0) return list; @@ -553,6 +580,23 @@ public class DataManagerBean implements DataManager { return result; } + protected List executeQuery(Query query) { + List list; + try { + //noinspection unchecked + list = query.getResultList(); + } catch (javax.persistence.PersistenceException e) { + if (e.getCause() instanceof org.eclipse.persistence.exceptions.QueryException + && e.getMessage() != null + && e.getMessage().contains("Fetch group cannot be set on report query")) { + throw new DevelopmentException("DataManager cannot execute query for single attributes"); + } else { + throw e; + } + } + return list; + } + protected void checkPermissions(CommitContext context) { Set checkedCreateRights = new HashSet<>(); Set checkedUpdateRights = new HashSet<>(); diff --git a/modules/core/src/com/haulmont/cuba/core/app/ServerConfig.java b/modules/core/src/com/haulmont/cuba/core/app/ServerConfig.java index 3bec503cca..2fa7fd0983 100644 --- a/modules/core/src/com/haulmont/cuba/core/app/ServerConfig.java +++ b/modules/core/src/com/haulmont/cuba/core/app/ServerConfig.java @@ -132,4 +132,12 @@ public interface ServerConfig extends Config { @Property("cuba.prettyTimeProperties") @DefaultString("") String getPrettyTimeProperties(); + + /** + * If set to false, attribute permissions are not enforced on Middleware. This is appropriate if only server-side + * clients are used. + */ + @Property("cuba.entityAttributePermissionChecking") + @DefaultBoolean(true) + boolean getEntityAttributePermissionChecking(); } diff --git a/modules/core/src/com/haulmont/cuba/core/sys/EntityManagerImpl.java b/modules/core/src/com/haulmont/cuba/core/sys/EntityManagerImpl.java index 55843b321a..cf230dd732 100644 --- a/modules/core/src/com/haulmont/cuba/core/sys/EntityManagerImpl.java +++ b/modules/core/src/com/haulmont/cuba/core/sys/EntityManagerImpl.java @@ -268,7 +268,10 @@ public class EntityManagerImpl implements EntityManager { return delegate.unwrap(Connection.class); } - private void deepCopyIgnoringNulls(Entity source, Entity dest) { + /** + * Copies all property values from source to dest excluding null values. + */ + protected void deepCopyIgnoringNulls(Entity source, Entity dest) { for (MetaProperty srcProperty : source.getMetaClass().getProperties()) { String name = srcProperty.getName(); diff --git a/modules/core/test/com/haulmont/cuba/core/DataManagerTest.java b/modules/core/test/com/haulmont/cuba/core/DataManagerTest.java index 3c91dc2626..cc5a783bd6 100644 --- a/modules/core/test/com/haulmont/cuba/core/DataManagerTest.java +++ b/modules/core/test/com/haulmont/cuba/core/DataManagerTest.java @@ -95,8 +95,12 @@ public class DataManagerTest extends CubaTestCase { loadContext.setQueryString("select u.group from sec$User u where u.id = :userId") .setParameter("userId", UUID.fromString("60885987-1b61-4247-94c7-dff348347f93")); - List list = dataManager.loadList(loadContext); - assertTrue(list.size() == 1); + try { + dataManager.loadList(loadContext); + fail(); + } catch (DevelopmentException e) { + assertEquals("DataManager cannot execute query for single attributes", e.getMessage()); + } } public void testLoadListCaseInsensitive() { diff --git a/modules/core/test/com/haulmont/cuba/testsupport/TestContainer.java b/modules/core/test/com/haulmont/cuba/testsupport/TestContainer.java index afed2736d7..65a11c5ff1 100644 --- a/modules/core/test/com/haulmont/cuba/testsupport/TestContainer.java +++ b/modules/core/test/com/haulmont/cuba/testsupport/TestContainer.java @@ -6,10 +6,13 @@ package com.haulmont.cuba.testsupport; import com.haulmont.bali.db.QueryRunner; +import com.haulmont.chile.core.model.MetaClass; import com.haulmont.cuba.core.EntityManager; import com.haulmont.cuba.core.Persistence; +import com.haulmont.cuba.core.entity.Entity; import com.haulmont.cuba.core.global.AppBeans; import com.haulmont.cuba.core.global.Metadata; +import com.haulmont.cuba.core.global.MetadataTools; import com.haulmont.cuba.core.sys.AbstractAppContextLoader; import com.haulmont.cuba.core.sys.AppContext; import com.haulmont.cuba.core.sys.AppContextLoader; @@ -130,12 +133,12 @@ public class TestContainer extends ExternalResource { return AppBeans.get(Metadata.class); } - public void deleteRecord(String table, UUID... ids) { + public void deleteRecord(String table, Object... ids) { deleteRecord(table, "ID", ids); } - public void deleteRecord(String table, String primaryKeyCol, UUID... ids) { - for (UUID id : ids) { + public void deleteRecord(String table, String primaryKeyCol, Object... ids) { + for (Object id : ids) { String sql = "delete from " + table + " where " + primaryKeyCol + " = '" + id.toString() + "'"; QueryRunner runner = new QueryRunner(persistence().getDataSource()); try { @@ -146,6 +149,20 @@ public class TestContainer extends ExternalResource { } } + public void deleteRecord(Entity... entities) { + for (Entity entity : entities) { + MetadataTools metadataTools = metadata().getTools(); + MetaClass metaClass = metadata().getClassNN(entity.getClass()); + + String table = metadataTools.getDatabaseTable(metaClass); + String primaryKey = metadataTools.getPrimaryKeyName(metaClass); + if (table == null || primaryKey == null) + throw new RuntimeException("Unable to determine table or primary key name for " + entity); + + deleteRecord(table, primaryKey, entity.getId()); + } + } + public List getAppPropertiesFiles() { return appPropertiesFiles; } diff --git a/modules/global/src/com/haulmont/cuba/core/entity/BaseGenericIdEntity.java b/modules/global/src/com/haulmont/cuba/core/entity/BaseGenericIdEntity.java index 60e1fb584e..962b1d739b 100644 --- a/modules/global/src/com/haulmont/cuba/core/entity/BaseGenericIdEntity.java +++ b/modules/global/src/com/haulmont/cuba/core/entity/BaseGenericIdEntity.java @@ -54,15 +54,18 @@ public abstract class BaseGenericIdEntity extends AbstractInstance implements @Transient protected boolean __removed; + @Transient + protected String[] __inaccessibleAttributes; + + @Transient + protected Map dynamicAttributes = null; + @Column(name = "CREATE_TS") protected Date createTs; @Column(name = "CREATED_BY", length = LOGIN_FIELD_LEN) protected String createdBy; - @Transient - protected Map dynamicAttributes = null; - public abstract void setId(T id); private void writeObject(java.io.ObjectOutputStream out) throws IOException { @@ -111,6 +114,16 @@ public abstract class BaseGenericIdEntity extends AbstractInstance implements this.__removed = removed; } + /** INTERNAL */ + public String[] __inaccessibleAttributes() { + return __inaccessibleAttributes; + } + + /** INTERNAL */ + public void __inaccessibleAttributes(String[] __inaccessibleAttributes) { + this.__inaccessibleAttributes = __inaccessibleAttributes; + } + @Override public MetaClass getMetaClass() { Metadata metadata = AppBeans.get(Metadata.NAME); diff --git a/modules/global/src/com/haulmont/cuba/core/entity/StandardEntity.java b/modules/global/src/com/haulmont/cuba/core/entity/StandardEntity.java index c21e589681..40ed38dfa1 100644 --- a/modules/global/src/com/haulmont/cuba/core/entity/StandardEntity.java +++ b/modules/global/src/com/haulmont/cuba/core/entity/StandardEntity.java @@ -41,6 +41,11 @@ public class StandardEntity extends BaseUuidEntity implements Versioned, Updatab return version; } + @Override + public void setVersion(Integer version) { + this.version = version; + } + @Override public Date getUpdateTs() { return updateTs; diff --git a/modules/global/src/com/haulmont/cuba/core/entity/Versioned.java b/modules/global/src/com/haulmont/cuba/core/entity/Versioned.java index a24d96c752..e99f7f449d 100644 --- a/modules/global/src/com/haulmont/cuba/core/entity/Versioned.java +++ b/modules/global/src/com/haulmont/cuba/core/entity/Versioned.java @@ -12,7 +12,11 @@ package com.haulmont.cuba.core.entity; */ public interface Versioned { - String[] PROPERTIES = {"version"}; - Integer getVersion(); + + /** + * Do not set version if you are not sure - it must be null for a new entity or loaded from the database + * for a persistent one. + */ + void setVersion(Integer version); } diff --git a/modules/global/src/com/haulmont/cuba/core/global/NotDetachedCommitContext.java b/modules/global/src/com/haulmont/cuba/core/global/NotDetachedCommitContext.java index 7d47ec45cc..f7bb918818 100644 --- a/modules/global/src/com/haulmont/cuba/core/global/NotDetachedCommitContext.java +++ b/modules/global/src/com/haulmont/cuba/core/global/NotDetachedCommitContext.java @@ -4,6 +4,9 @@ */ package com.haulmont.cuba.core.global; +import com.haulmont.cuba.core.entity.Entity; + +import java.util.Collection; import java.util.HashSet; import java.util.Set; @@ -13,6 +16,18 @@ public class NotDetachedCommitContext extends CommitContext { protected Set newInstanceIds = new HashSet<>(); + public NotDetachedCommitContext(Entity... commitInstances) { + super(commitInstances); + } + + public NotDetachedCommitContext(Collection commitInstances) { + super(commitInstances); + } + + public NotDetachedCommitContext(Collection commitInstances, Collection removeInstances) { + super(commitInstances, removeInstances); + } + public Set getNewInstanceIds() { return newInstanceIds; } diff --git a/modules/global/src/com/haulmont/cuba/core/global/PersistenceHelper.java b/modules/global/src/com/haulmont/cuba/core/global/PersistenceHelper.java index 6a341ba1e5..d1d7028380 100644 --- a/modules/global/src/com/haulmont/cuba/core/global/PersistenceHelper.java +++ b/modules/global/src/com/haulmont/cuba/core/global/PersistenceHelper.java @@ -118,6 +118,13 @@ public class PersistenceHelper { * @return true if loaded */ public static boolean isLoaded(Object entity, String property) { + if (entity instanceof BaseGenericIdEntity + && ((BaseGenericIdEntity) entity).__inaccessibleAttributes() != null) { + for (String inaccessibleAttr : ((BaseGenericIdEntity) entity).__inaccessibleAttributes()) { + if (inaccessibleAttr.equals(property)) + return false; + } + } if (entity instanceof FetchGroupTracker) { FetchGroup fetchGroup = ((FetchGroupTracker) entity)._persistence_getFetchGroup(); if (fetchGroup != null) diff --git a/modules/global/src/com/haulmont/cuba/core/sys/persistence/CubaEntityFetchGroup.java b/modules/global/src/com/haulmont/cuba/core/sys/persistence/CubaEntityFetchGroup.java index 211554d131..e5138fe58d 100644 --- a/modules/global/src/com/haulmont/cuba/core/sys/persistence/CubaEntityFetchGroup.java +++ b/modules/global/src/com/haulmont/cuba/core/sys/persistence/CubaEntityFetchGroup.java @@ -5,12 +5,15 @@ package com.haulmont.cuba.core.sys.persistence; +import com.haulmont.cuba.core.entity.BaseGenericIdEntity; import com.haulmont.cuba.core.global.IllegalEntityStateException; import org.eclipse.persistence.internal.localization.ExceptionLocalization; import org.eclipse.persistence.internal.queries.EntityFetchGroup; import org.eclipse.persistence.queries.FetchGroup; import org.eclipse.persistence.queries.FetchGroupTracker; +import java.util.Collection; + /** * @author krivopustov * @version $Id$ @@ -21,8 +24,20 @@ public class CubaEntityFetchGroup extends EntityFetchGroup { super(fetchGroup); } + public CubaEntityFetchGroup(Collection attributeNames) { + super(attributeNames); + } + @Override public String onUnfetchedAttribute(FetchGroupTracker entity, String attributeName) { + String[] inaccessible = ((BaseGenericIdEntity) entity).__inaccessibleAttributes(); + if (inaccessible != null) { + for (String inaccessibleAttribute : inaccessible) { + if (attributeName.equals(inaccessibleAttribute)) + return null; + } + } + if (attributeName == null && entity._persistence_getSession() != null) { // occurs on merge return super.onUnfetchedAttribute(entity, null); } diff --git a/modules/global/src/com/haulmont/cuba/security/global/UserSession.java b/modules/global/src/com/haulmont/cuba/security/global/UserSession.java index a75df49b22..37eef47e04 100644 --- a/modules/global/src/com/haulmont/cuba/security/global/UserSession.java +++ b/modules/global/src/com/haulmont/cuba/security/global/UserSession.java @@ -44,6 +44,9 @@ public class UserSession implements Serializable { protected Map attributes; + /** + * INTERNAL + */ public UserSession(UUID id, User user, Collection roles, Locale locale, boolean system) { this.id = id; this.user = user; @@ -69,12 +72,18 @@ public class UserSession implements Serializable { attributes = new ConcurrentHashMap<>(); } + /** + * INTERNAL + */ public UserSession(UserSession src, User user, Collection roles, Locale locale) { this(src.id, user, roles, locale, src.system); this.user = src.user; this.substitutedUser = this.user.equals(user) ? null : user; } + /** + * INTERNAL + */ public UserSession(UserSession src) { id = src.id; user = src.user; @@ -104,7 +113,7 @@ public class UserSession implements Serializable { } /** - * Don't do it + * INTERNAL */ public void setUser(User user) { this.user = user; @@ -118,7 +127,7 @@ public class UserSession implements Serializable { } /** - * Don't do it + * INTERNAL */ public void setSubstitutedUser(User substitutedUser) { this.substitutedUser = substitutedUser; @@ -145,6 +154,9 @@ public class UserSession implements Serializable { return locale; } + /** + * INTERNAL + */ public void setLocale(Locale locale) { this.locale = locale; } @@ -157,6 +169,9 @@ public class UserSession implements Serializable { return timeZone; } + /** + * INTERNAL + */ public void setTimeZone(TimeZone timeZone) { this.timeZone = timeZone; } @@ -168,6 +183,9 @@ public class UserSession implements Serializable { return address; } + /** + * INTERNAL + */ public void setAddress(String address) { this.address = address; } @@ -179,14 +197,17 @@ public class UserSession implements Serializable { return clientInfo; } + /** + * INTERNAL + */ public void setClientInfo(String clientInfo) { this.clientInfo = clientInfo; } /** - * This method is used by security subsystem + * INTERNAL */ - public void addPermission(PermissionType type, String target, String extTarget, int value) { + public void addPermission(PermissionType type, String target, @Nullable String extTarget, int value) { Integer currentValue = permissions[type.ordinal()].get(target); if (currentValue == null || currentValue < value) { permissions[type.ordinal()].put(target, value); @@ -196,14 +217,14 @@ public class UserSession implements Serializable { } /** - * This method is used by security subsystem + * INTERNAL */ public void removePermission(PermissionType type, String target) { permissions[type.ordinal()].remove(target); } /** - * This method is used by security subsystem + * INTERNAL */ public Integer getPermissionValue(PermissionType type, String target) { return permissions[type.ordinal()].get(target); @@ -286,7 +307,7 @@ public class UserSession implements Serializable { } /** - * This method is used by security subsystem + * INTERNAL */ public void addConstraint(String entityName, String joinClause, String whereClause) { List list = constraints.get(entityName); @@ -298,7 +319,7 @@ public class UserSession implements Serializable { } /** - * This method is used by security subsystem + * INTERNAL */ public List getConstraints(String entityName) { List list = constraints.get(entityName);