com.haulmont.cuba.security.global.UserSession.java Source code

Java tutorial

Introduction

Here is the source code for com.haulmont.cuba.security.global.UserSession.java

Source

/*
 * Copyright (c) 2008-2016 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.security.global;

import com.google.common.collect.ArrayListMultimap;
import com.haulmont.chile.core.model.MetaClass;
import com.haulmont.cuba.security.entity.*;

import javax.annotation.Nullable;
import java.io.Serializable;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * Class that encapsulates an active user session.
 * <p>It contains user attributes, credentials, set of permissions, and methods to check permissions for certain
 * objects.</p>
 * <p>On the client side a descendant of this class is maintained:
 * <code>com.haulmont.cuba.client.ClientUserSession</code></p>
 *
 */
public class UserSession implements Serializable {

    private static final long serialVersionUID = -8248326616891177382L;

    protected UUID id;
    protected User user;
    protected User substitutedUser;
    private List<String> roles = new ArrayList<>();
    private EnumSet<RoleType> roleTypes = EnumSet.noneOf(RoleType.class);
    protected Locale locale;
    protected TimeZone timeZone;
    protected String address;
    protected String clientInfo;
    protected boolean system;

    protected Map<String, Integer>[] permissions;
    protected ArrayListMultimap<String, ConstraintData> constraints;

    protected Map<String, Serializable> attributes;

    /**
     * INTERNAL
     */
    public UserSession(UUID id, User user, Collection<Role> roles, Locale locale, boolean system) {
        this.id = id;
        this.user = user;
        this.system = system;

        for (Role role : roles) {
            this.roles.add(role.getName());
            if (role.getType() != null)
                roleTypes.add(role.getType());
        }

        this.locale = locale;
        if (user.getTimeZone() != null)
            this.timeZone = TimeZone.getTimeZone(user.getTimeZone());

        //noinspection unchecked
        permissions = new Map[PermissionType.values().length];
        for (int i = 0; i < permissions.length; i++) {
            permissions[i] = new HashMap<>();
        }

        constraints = ArrayListMultimap.create();
        attributes = new ConcurrentHashMap<>();
    }

    /**
     * INTERNAL
     */
    public UserSession(UserSession src, User user, Collection<Role> 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;
        substitutedUser = src.substitutedUser;
        system = src.system;
        roles = src.roles;
        locale = src.locale;
        timeZone = src.timeZone;
        permissions = src.permissions;
        constraints = src.constraints;
        attributes = src.attributes;
        roleTypes = src.roleTypes;
    }

    /**
     * Session ID
     */
    public UUID getId() {
        return id;
    }

    /**
     * Logged-in user
     */
    public User getUser() {
        return user;
    }

    /**
     * INTERNAL
     */
    public void setUser(User user) {
        this.user = user;
    }

    /**
     * Substituted user. May be null.
     */
    public User getSubstitutedUser() {
        return substitutedUser;
    }

    /**
     * INTERNAL
     */
    public void setSubstitutedUser(User substitutedUser) {
        this.substitutedUser = substitutedUser;
    }

    /**
     * Returns substituted user if it is not null, logged-in user otherwise.
     */
    public User getCurrentOrSubstitutedUser() {
        return substitutedUser == null ? user : substitutedUser;
    }

    /**
     * User role names
     */
    public Collection<String> getRoles() {
        return Collections.unmodifiableList(roles);
    }

    /**
     * User locale
     */
    public Locale getLocale() {
        return locale;
    }

    /**
     * INTERNAL
     */
    public void setLocale(Locale locale) {
        this.locale = locale;
    }

    /**
     * User time zone. Can be null.
     */
    @Nullable
    public TimeZone getTimeZone() {
        return timeZone;
    }

    /**
     * INTERNAL
     */
    public void setTimeZone(TimeZone timeZone) {
        this.timeZone = timeZone;
    }

    /**
     * Client IP-address
     */
    public String getAddress() {
        return address;
    }

    /**
     * INTERNAL
     */
    public void setAddress(String address) {
        this.address = address;
    }

    /**
     * Client application info
     */
    public String getClientInfo() {
        return clientInfo;
    }

    /**
     * INTERNAL
     */
    public void setClientInfo(String clientInfo) {
        this.clientInfo = clientInfo;
    }

    /**
     * INTERNAL
     */
    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);
            if (extTarget != null)
                permissions[type.ordinal()].put(extTarget, value);
        }
    }

    /**
     * INTERNAL
     */
    public void removePermission(PermissionType type, String target) {
        permissions[type.ordinal()].remove(target);
    }

    /**
     * INTERNAL
     */
    public Integer getPermissionValue(PermissionType type, String target) {
        return permissions[type.ordinal()].get(target);
    }

    /**
     * Get permissions by type
     */
    public Map<String, Integer> getPermissionsByType(PermissionType type) {
        return Collections.unmodifiableMap(permissions[type.ordinal()]);
    }

    /**
     * Check user permission for the screen
     */
    public boolean isScreenPermitted(String windowAlias) {
        return isPermitted(PermissionType.SCREEN, windowAlias);
    }

    /**
     * Check user permission for the entity operation
     */
    public boolean isEntityOpPermitted(MetaClass metaClass, EntityOp entityOp) {
        return isPermitted(PermissionType.ENTITY_OP,
                metaClass.getName() + Permission.TARGET_PATH_DELIMETER + entityOp.getId());
    }

    /**
     * Check user permission for the entity attribute
     */
    public boolean isEntityAttrPermitted(MetaClass metaClass, String property, EntityAttrAccess access) {
        return isPermitted(PermissionType.ENTITY_ATTR,
                metaClass.getName() + Permission.TARGET_PATH_DELIMETER + property, access.getId());
    }

    /**
     * Check specific user permission
     */
    public boolean isSpecificPermitted(String name) {
        return isPermitted(PermissionType.SPECIFIC, name);
    }

    /**
     * Check user permission.
     * <br>Same as {@link #isPermitted(com.haulmont.cuba.security.entity.PermissionType, String, int)}
     * with value=1
     * <br>This method makes sense for permission types with two possible values 0,1
     *
     * @param type   permission type
     * @param target permission target:<ul>
     *               <li>screen
     *               <li>entity operation (view, create, update, delete)
     *               <li>entity attribute name
     *               <li>specific permission name
     *               </ul>
     * @return true if permitted, false otherwise
     */
    public boolean isPermitted(PermissionType type, String target) {
        return isPermitted(type, target, 1);
    }

    /**
     * Check user permission for the specified value.
     *
     * @param type   permission type
     * @param target permission target:<ul>
     *               <li>screen
     *               <li>entity operation (view, create, update, delete)
     *               <li>entity attribute name
     *               <li>specific permission name
     *               </ul>
     * @param value  method returns true if the corresponding {@link com.haulmont.cuba.security.entity.Permission}
     *               record contains value equal or greater than specified
     * @return true if permitted, false otherwise
     */
    public boolean isPermitted(PermissionType type, String target, int value) {
        // If we have super-role no need to check anything
        if (roleTypes.contains(RoleType.SUPER))
            return true;
        // Get permission value assigned by the set of permissions
        Integer v = permissions[type.ordinal()].get(target);
        // Get permission value assigned by non-standard roles
        for (RoleType roleType : roleTypes) {
            Integer v1 = roleType.permissionValue(type, target);
            if (v1 != null && (v == null || v < v1)) {
                v = v1;
            }
        }
        // Return true if no value set for this target, or if the value is more than requested
        return v == null || v >= value;
    }

    /**
     * INTERNAL
     */
    public void addConstraint(Constraint constraint) {
        String entityName = constraint.getEntityName();
        constraints.put(entityName, new ConstraintData(constraint));
    }

    /**
     * INTERNAL
     */
    public void removeConstraint(Constraint constraintToRemove) {
        String entityName = constraintToRemove.getEntityName();
        List<ConstraintData> constraintData = this.constraints.get(entityName);
        constraintData.stream().filter(constraint -> constraintToRemove.getId().equals(constraint.getId()))
                .collect(Collectors.toList())//to avoid ConcurrentModificationException
                .forEach(constraint -> this.constraints.remove(entityName, constraint));
    }

    /**
     * INTERNAL
     */
    public List<ConstraintData> getConstraints(String entityName) {
        return Collections.unmodifiableList(constraints.get(entityName));
    }

    /**
     * INTERNAL
     */
    public boolean hasConstraints(String entityName) {
        return constraints.containsKey(entityName);
    }

    /**
     * INTERNAL
     */
    public boolean hasConstraints() {
        return !constraints.isEmpty();
    }

    /**
     * INTERNAL
     */
    public List<ConstraintData> getConstraints(String entityName, Predicate<ConstraintData> predicate) {
        List<ConstraintData> list = constraints.get(entityName);
        return Collections.unmodifiableList(list.stream().filter(predicate).collect(Collectors.toList()));
    }

    /**
     * Get user session attribute. Attribute is a named serializable object bound to session.
     *
     * @param name attribute name. The following names have predefined values:
     *             <ul>
     *             <li>userId - current or substituted user ID</li>
     *             <li>userLogin - current or substituted user login in lower case</li>
     *             </ul>
     * @return attribute value or null if attribute with the given name is not found
     */
    @SuppressWarnings("unchecked")
    @Nullable
    public <T> T getAttribute(String name) {
        if ("userId".equals(name))
            return (T) getCurrentOrSubstitutedUser().getId();
        if ("userLogin".equals(name))
            return (T) getCurrentOrSubstitutedUser().getLoginLowerCase();
        else
            return (T) attributes.get(name);
    }

    /**
     * Remove user session attribute. Attribute is a named serializable object bound to session.
     *
     * @param name attribute name
     */
    public void removeAttribute(String name) {
        attributes.remove(name);
    }

    /**
     * Set user session attribute. Attribute is a named serializable object bound to session.
     *
     * @param name  attribute name
     * @param value attribute value
     */
    public void setAttribute(String name, Serializable value) {
        attributes.put(name, value);
    }

    /**
     * User session attribute names. Attribute is a named serializable object bound to session.
     */
    public Collection<String> getAttributeNames() {
        //noinspection unchecked
        return new ArrayList(attributes.keySet());
    }

    /**
     * System session is created by <code>LoginWorker.loginSystem()</code> for system users like schedulers and JMX.
     * <p>
     * It is not replicated in cluster.
     */
    public boolean isSystem() {
        return system;
    }

    public String toString() {
        return id + " [" + user.getLogin() + (substitutedUser == null ? "" : " / " + substitutedUser.getLogin())
                + "]";
    }
}