/*
 *   Licensed to the Apache Software Foundation (ASF) under one
 *   or more contributor license agreements.  See the NOTICE file
 *   distributed with this work for additional information
 *   regarding copyright ownership.  The ASF licenses this file
 *   to you 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.apache.directory.fortress.core.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import net.sf.ehcache.search.Attribute;
import net.sf.ehcache.search.Query;
import net.sf.ehcache.search.Result;
import net.sf.ehcache.search.Results;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.api.ldap.model.constants.SchemaConstants;
import org.apache.directory.fortress.core.*;
import org.apache.directory.fortress.core.SecurityException;
import org.apache.directory.fortress.core.model.*;
import org.apache.directory.fortress.core.util.Config;
import org.apache.directory.fortress.core.util.cache.Cache;
import org.apache.directory.fortress.core.util.cache.CacheMgr;
import org.apache.directory.fortress.core.util.cache.DsdCacheEntry;

/**
 * This utilty provides functionality necessary for SSD and DSD processing and cannot be called by components outside fortress.
 * This class also contains utility functions for maintaining the SSD and DSD cache.
 * <p>
 * This class is thread safe.
 *
 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
 * @created September 3, 2010
 */
final class SDUtil
{
    private Cache m_dsdCache;
    private static final String FORTRESS_DSDS = "fortress.dsd";
    private Cache m_ssdCache;
    private static final String FORTRESS_SSDS = "fortress.ssd";
    private SdP sp;
    private static final String IS_DSD_CACHE_DISABLED_PARM = "enable.dsd.cache";
    private static final String DSD_NAME = "name";
    private static final String EMPTY_ELEMENT = "empty";
    private static final String CONTEXT_ID = "contextId";

    private static volatile SDUtil sINSTANCE = null;

    static SDUtil getInstance()
    {
        if(sINSTANCE == null)
        {
            synchronized (SDUtil.class)
            {
                if(sINSTANCE == null)
                {
                    sINSTANCE = new SDUtil();
                }
            }
        }
        return sINSTANCE;
    }
    
    private void init()
    {
        sp = new SdP();
    
        // Get a reference to the CacheManager Singleton object:
        CacheMgr cacheMgr = CacheMgr.getInstance();
        // This cache contains a wrapper entry for DSD and is searchable by both DSD and Role name:
        m_dsdCache = cacheMgr.getCache(FORTRESS_DSDS);
        // This cache is not searchable and contains Lists of SSD objects by Role:
        m_ssdCache = cacheMgr.getCache(FORTRESS_SSDS);
    }

    /**
     * Private constructor
     *
     */
    private SDUtil()    
    {
        init();
    }

    /**
     * This method is called by AdminMgr.assignUser and is used to validate Static Separation of Duty
     * constraints when assigning a role to user.
     *
     * @param uRole
     * @throws org.apache.directory.fortress.core.SecurityException
     *
     */
    void validateSSD(UserRole uRole)
        throws SecurityException
    {
        validateSSD(new User(uRole.getUserId()), new Role(uRole.getName()));
    }

    /**
     * This method is called by AdminMgr.assignUser and is used to validate Static Separation of Duty
     * constraints when assigning a role to user.
     *
     * @param user
     * @param role
     * @throws org.apache.directory.fortress.core.SecurityException
     *
     */
    void validateSSD(User user, Role role)
        throws SecurityException
    {
        // get all authorized roles for user
        String contextId = user.getContextId();
        ReviewMgr rMgr = ReviewMgrFactory.createInstance( contextId );
        Set<String> rls = rMgr.authorizedRoles( user );

        checkSSD( role, rls, contextId);
    }

    /**
     * This method is called by GroupMgr.assign and is used to validate Static Separation of Duty
     * constraints when assigning a role to group.
     *
     * @param group
     * @param role
     * @throws org.apache.directory.fortress.core.SecurityException
     *
     */
    void validateSSD( Group group, Role role ) throws SecurityException
    {
        // get all authorized roles for this group
        String contextId = group.getContextId();
        GroupMgr groupMgr = GroupMgrFactory.createInstance(contextId);
        List<UserRole> roles = groupMgr.groupRoles( group );
        Set<String> rls = RoleUtil.getInstance().getInheritedRoles( roles, contextId);
        // check SSD constraints
        checkSSD( role, rls, contextId);
    }

    private void checkSSD( Role role, Set<String> authorizedRls, String contextId ) throws SecurityException
    {
        int matchCount;
        // Need to proceed?
        if (CollectionUtils.isEmpty( authorizedRls ))
        {
            return;
        }

        // get all SSD sets that contain the new role
        List<SDSet> ssdSets = getSsdCache( role.getName(), contextId );
        for ( SDSet ssd : ssdSets )
        {
            matchCount = 0;
            Set<String> map = ssd.getMembers();
            // iterate over every authorized role for user/group:
            for ( String authRole : authorizedRls )
            {
                // is there a match found between authorized role and SSD set's members?
                if ( map.contains( authRole ) )
                {
                    matchCount++;
                    // does the match count exceed the cardinality allowed for this particular SSD set?
                    if ( matchCount >= ssd.getCardinality() - 1 )
                    {
                        String error = "validateSSD new role [" + role.getName() + "] validates SSD Set Name:"
                                + ssd.getName() + " Cardinality:" + ssd.getCardinality();
                        throw new SecurityException( GlobalErrIds.SSD_VALIDATION_FAILED, error );
                    }
                }
            }
        }
    }

    /**
     * This method is called by AccessMgr.addActiveRole and is used to validate Dynamic Separation of Duty
     * constraints when activating a role one at a time.  For activation of multiple roles simultaneously use
     * the DSD.validate API which is used during createSession sequence.
     *
     * @param session
     * @param role
     * @throws org.apache.directory.fortress.core.SecurityException
     *
     */
    void validateDSD(Session session, Constraint role)
        throws SecurityException
    {
        // get all activated roles from user's session:
        List<UserRole> rls = session.getRoles();
        if (CollectionUtils.isEmpty( rls ))
        {
            // An empty list of roles was passed in the session variable.
            // No need to continue.
            return;
        }

        // get all DSD sets that contain the target role
        Set<SDSet> dsdSets = getDsdCache(role.getName(), session.getContextId());
        for (SDSet dsd : dsdSets)
        {
            // Keeps the number of matched roles to a particular DSD set.
            int matchCount = 0;

            // Contains the list of roles assigned to a particular DSD set.
            Set<String> map = dsd.getMembers();

            // iterate over every role active in session for match wth DSD members:
            for (UserRole actRole : rls)
            {
                // is there a match found between active role in session and DSD set members?
                if (map.contains(actRole.getName()))
                {
                    // Yes, we found a match, increment the count.
                    matchCount++;

                    // Does the match count exceed the cardinality allowed for this particular DSD set?
                    if (matchCount >= dsd.getCardinality() - 1)
                    {
                        // Yes, the target role violates DSD cardinality rule.
                        String error = "validateDSD failed for role [" + role.getName() + "] DSD Set Name:" + dsd.getName() + " Cardinality:" + dsd.getCardinality();
                        throw new SecurityException(GlobalErrIds.DSD_VALIDATION_FAILED, error);
                    }
                }
                else // Check the parents of activated role for DSD match:
                {
                    // Now pull the activated role's list of parents.
                    Set<String> parentSet = RoleUtil.getInstance().getAscendants(actRole.getName(), session.getContextId());

                    // Iterate over the list of parent roles:
                    for (String parentRole : parentSet)
                    {
                        if (map.contains(parentRole)) // is there match between parent and DSD member?
                        {
                            matchCount++;
                            if (matchCount >= dsd.getCardinality() - 1) // Does the counter exceed max per cardinality on this DSD set?
                            {
                                String error = "validateDSD failed for role [" + role.getName() + "] parent role [" + parentRole + "] DSD Set Name:" + dsd.getName() + " Cardinality:" + dsd.getCardinality();
                                throw new SecurityException(GlobalErrIds.DSD_VALIDATION_FAILED, error);
                            }
                            // Breaking out of the loop here means the DSD algorithm will only match one
                            // role per parent of active role candidate.
                            break;
                        }
                    }
                }
            }
        }
    }

    /**
     * Given DSD entry name, clear its corresponding object values from the cache.
     *
     * @param name contains the name of object to be cleared.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.     *
     * @throws SecurityException in the event of system or rule violation.
     */
    void clearDsdCacheEntry(String name, String contextId)
    {
        Attribute<String> context = m_dsdCache.getSearchAttribute(CONTEXT_ID);
        Attribute<String> dsdName = m_dsdCache.getSearchAttribute(DSD_NAME);
        Query query = m_dsdCache.createQuery();
        query.includeKeys();
        query.includeValues();
        query.addCriteria(dsdName.eq(name).and(context.eq(contextId)));
        Results results = query.execute();
        for (Result result : results.all())
        {
            m_dsdCache.clear(result.getKey());
        }
    }

    /**
     * Given a role name, return the set of DSD's that have a matching member.
     *
     * @param name contains name of authorized Role used to search the cache.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return un-ordered set of matching DSD's.
     * @throws SecurityException in the event of system or rule violation.
     */
    private Set<SDSet> getDsdCache(String name, String contextId)
        throws SecurityException
    {
        contextId = getContextId(contextId);
        Set<SDSet> finalSet = new HashSet<>();
        Attribute<String> context = m_dsdCache.getSearchAttribute(CONTEXT_ID);
        Attribute<String> member = m_dsdCache.getSearchAttribute(SchemaConstants.MEMBER_AT);
        Query query = m_dsdCache.createQuery();
        query.includeKeys();
        query.includeValues();
        query.addCriteria(member.eq(name).and(context.eq(contextId)));
        Results results = query.execute();
        boolean empty = false;
        for (Result result : results.all())
        {
            DsdCacheEntry entry = (DsdCacheEntry) result.getValue();
            if (!entry.isEmpty())
            {
                finalSet.add(entry.getSdSet());
                finalSet = putDsdCache(name, contextId);
            }
            else
            {
                empty = true;
            }
            finalSet.add(entry.getSdSet());
        }
        // If nothing was found in the cache, determine if it needs to be seeded:
        if (finalSet.size() == 0 && !empty)
        {
            finalSet = putDsdCache(name, contextId);
        }
        return finalSet;
    }

    /**
     * Given a Set of authorized Roles, return the set of DSD's that have matching members.
     *
     * @param authorizedRoleSet contains an un-order Set of authorized Roles.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return un-ordered set of matching DSD's.
     * @throws SecurityException in the event of system or rule violation.
     */
    Set<SDSet> getDsdCache(Set<String> authorizedRoleSet, String contextId)
        throws SecurityException
    {
        contextId = getContextId(contextId);
        Set<SDSet> dsdRetSets = new HashSet<>();
        // Need to proceed?
        if (!CollectionUtils.isNotEmpty( authorizedRoleSet ))
        {
            return dsdRetSets;
        }
        // Was the DSD Cache switched off?
        boolean isCacheDisabled = Config.getInstance().getBoolean(IS_DSD_CACHE_DISABLED_PARM, false);
        // If so, get DSD's from LDAP:
        if (isCacheDisabled)
        {
            SDSet sdSet = new SDSet();
            sdSet.setType(SDSet.SDType.DYNAMIC);
            sdSet.setContextId(contextId);
            dsdRetSets = sp.search(authorizedRoleSet, sdSet);
        }
        // Search the DSD cache for matching Role members:
        else
        {
            // Search on roleName attribute which maps to 'member' attr on the cache record:
            Attribute<String> member = m_dsdCache.getSearchAttribute(SchemaConstants.MEMBER_AT);
            Attribute<String> context = m_dsdCache.getSearchAttribute(CONTEXT_ID);
            Query query = m_dsdCache.createQuery();
            query.includeKeys();
            query.includeValues();
            // Add the passed in authorized Role names to this cache query:
            Set<String> roles = new HashSet<>(authorizedRoleSet);
            query.addCriteria(member.in(roles).and(context.eq(contextId)));
            // Return all DSD cache entries that match roleName to the 'member' attribute in cache entry:
            Results results = query.execute();
            for (Result result : results.all())
            {
                DsdCacheEntry entry = (DsdCacheEntry) result.getValue();
                // Do not add dummy DSD sets to the final list:
                if (!entry.isEmpty())
                {
                    dsdRetSets.add(entry.getSdSet());
                }
                // Remove role member from authorizedRoleSet to preclude from upcoming DSD search:
                //authorizedRoleSet.remove(entry.getMember());
            }
            // Authorized roles remaining in this set correspond to missed cache hits from above:
            if (authorizedRoleSet.size() > 0)
            {
                dsdRetSets = putDsdCache(authorizedRoleSet, contextId);
            }
        }
        return dsdRetSets;
    }

    /**
     * Get the matching DSD's from directory and add to the cache (if found).  If matching DSD not found,
     * add dummy entry to cache to prevent repeated searches.
     *
     * @param authorizedRoleSet contains set of Roles used to search directory for matching DSD's.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return List of DSD's who have matching Role members.
     * @throws SecurityException in the event of system or rule violation.
     */
    private Set<SDSet> putDsdCache(Set<String> authorizedRoleSet, String contextId)
        throws SecurityException
    {
        contextId = getContextId(contextId);
        Set<SDSet> dsdSets = new HashSet<>();
        // Search the DSD's iteratively to seed the DSD cache by Role name:
        for (String roleName : authorizedRoleSet)
        {
            Role role = new Role(roleName);
            role.setContextId(contextId);
            List<SDSet> dsdList = sp.search(role, SDSet.SDType.DYNAMIC);
            if (CollectionUtils.isNotEmpty( dsdList ))
            {
                for (SDSet dsd : dsdList)
                {
                    dsd.setContextId(contextId);
                    Set<String> members = dsd.getMembers();
                    if (members != null)
                    {
                        // Seed the cache with DSD objects mapped to role name:
                        for (String member : members)
                        {
                            String key = buildKey(dsd.getName(), member);
                            DsdCacheEntry entry = new DsdCacheEntry(member, dsd, false);
                            entry.setName(dsd.getName());
                            m_dsdCache.put(getKey(key, contextId), entry);
                        }
                    }
                }
                // Maintain the set of DSD's to be returned to the caller:
                dsdSets.addAll(dsdList);
            }
            else
            {
                // Seed the cache with dummy entry for a Role that is not referenced by DSD:
                String key = buildKey(EMPTY_ELEMENT, roleName);
                SDSet sdSet = new SDSet();
                sdSet.setType(SDSet.SDType.DYNAMIC);
                sdSet.setName(key);
                sdSet.setMember(roleName);
                sdSet.setContextId(contextId);
                DsdCacheEntry entry = new DsdCacheEntry(roleName, sdSet, true);
                entry.setName(key);
                m_dsdCache.put(getKey(sdSet.getName(), contextId), entry);
            }
        }
        return dsdSets;
    }

    /**
     * Get the matching DSD's from directory and add to the cache (if found).  If matching DSD not found,
     * add dummy entry to cache to prevent repeated searches.
     *
     * @param roleName of Role is used to search directory for matching DSD's.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return Set of DSD's who have matching Role member.
     * @throws SecurityException in the event of system or rule violation.
     */
    private Set<SDSet> putDsdCache(String roleName, String contextId)
        throws SecurityException
    {
        contextId = getContextId(contextId);
        Role role = new Role(roleName);
        role.setContextId(contextId);
        List<SDSet> dsdList = sp.search(role, SDSet.SDType.DYNAMIC);
        Set<SDSet> finalSet = new HashSet<>(dsdList);
        if ( CollectionUtils.isNotEmpty( dsdList ))
        {
            for (SDSet dsd : dsdList)
            {
                dsd.setContextId(contextId);
                Set<String> members = dsd.getMembers();
                if (members != null)
                {
                    // Seed the cache with DSD objects mapped to role name:
                    for (String member : members)
                    {
                        String key = buildKey(dsd.getName(), member);
                        DsdCacheEntry entry = new DsdCacheEntry(member, dsd, false);
                        entry.setName(dsd.getName());
                        m_dsdCache.put(getKey(key, contextId), entry);
                    }
                }
            }
        }
        else
        {
            // Seed the cache with dummy entry for Role that does not have DSD:
            String key = buildKey(EMPTY_ELEMENT, roleName);
            SDSet sdSet = new SDSet();
            sdSet.setType(SDSet.SDType.DYNAMIC);
            sdSet.setName(key);
            sdSet.setMember(roleName);
            sdSet.setContextId(contextId);
            DsdCacheEntry entry = new DsdCacheEntry(roleName, sdSet, true);
            entry.setName(key);
            m_dsdCache.put(getKey(sdSet.getName(), contextId), entry);
        }
        return finalSet;
    }

    /**
     * Given entry name, clear its corresponding object value from the cache.
     *
     * @param name contains the name of object to be cleared.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @throws SecurityException in the event of system or rule violation.
     */
    void clearSsdCacheEntry(String name, String contextId)
    {
        contextId = getContextId(contextId);
        m_ssdCache.clear(getKey(name, contextId));
    }

    /**
     * Get the matching SSD's from directory and add to the cache (if found).
     *
     * @param name of Role is used to search directory for matching SSD's.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return List of SSD's who have matching Role member.
     * @throws SecurityException in the event of system or rule violation.
     */
    private List<SDSet> putSsdCache(String name, String contextId)
        throws SecurityException
    {
        Role role = new Role(name);
        role.setContextId(contextId);
        List<SDSet> ssdSets = sp.search(role, SDSet.SDType.STATIC);
        m_ssdCache.put(getKey(name, contextId), ssdSets);
        return ssdSets;
    }

    /**
     * Look in cache for matching List of SSD's.
     *
     * @param name of Role is used to search directory for matching SSD's.
     * @param contextId maps to sub-tree in DIT, e.g. ou=contextId, dc=example, dc=com.
     * @return List of SSD's who have matching Role member.
     * @throws SecurityException in the event of system or rule violation.
     */
    private List<SDSet> getSsdCache(String name, String contextId)
        throws SecurityException
    {
        List<SDSet> ssdSets = (List<SDSet>) m_ssdCache.get(getKey(name, contextId));
        if (ssdSets == null)
        {
            ssdSets = putSsdCache(name, contextId);
        }
        return ssdSets;
    }

    /**
     *
     * @param parm1
     * @param parm2
     * @return
     */
    private static String buildKey(String parm1, String parm2)
    {
        return parm1 + ":" + parm2;
    }

    /**
     *
     * @param name
     * @param contextId
     * @return
     */
    private static String getKey(String name, String contextId)
    {
        contextId = getContextId(contextId);
        return name += ":" + contextId;
    }

    /**
     *
     * @param contextId
     * @return
     */
    private static String getContextId(String contextId)
    {
        String szContextId = GlobalIds.HOME;
        if( StringUtils.isNotEmpty( contextId ) && !contextId.equals(GlobalIds.NULL))
        {
            szContextId = contextId;
        }
        return szContextId;
    }
}
