001/*
002 *  Copyright 2016 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.web.population;
017
018import java.util.Collection;
019import java.util.HashSet;
020import java.util.Set;
021import java.util.regex.Matcher;
022import java.util.regex.Pattern;
023
024import org.ametys.core.right.RightManager.RightResult;
025import org.ametys.core.user.UserIdentity;
026import org.ametys.core.user.population.UserPopulation;
027import org.ametys.runtime.authentication.AccessDeniedException;
028
029
030/**
031 * Helper for associating {@link UserPopulation}s to contexts.
032 * This override allows a user to get user populations on a 'site' context if user belongs to the BO+FO site context ('/sites/SITENAME') or FO site context  ('/sites-fo/SITENAME')
033 */
034public class PopulationContextHelper extends org.ametys.core.user.population.PopulationContextHelper
035{
036    private static final Pattern _SITES_CONTEXT_PATTERN = Pattern.compile("^/sites/(.+)$");
037    private static final Pattern _SITES_FO_CONTEXT_PATTERN = Pattern.compile("^/sites-fo/(.+)$");
038    
039    private static final String _SITES_CONTEXT_PREFIX = "/sites/";
040    private static final String _SITES_FO_CONTEXT_PREFIX = "/sites-fo/";
041    
042    @Override
043    public Set<String> getUserPopulationsOnContexts(Collection<String> contexts, boolean withDisabled, boolean checkRights)
044    {
045        UserIdentity currentUser = getCurrentUserProvider().getUser();
046        
047        if (!checkRights || contexts.contains(ADMIN_CONTEXT) || currentUser == null)
048        {
049            // no override required
050            return super.getUserPopulationsOnContexts(contexts, withDisabled, checkRights);
051        }
052        
053        boolean isAdministrator = getRightManager().currentUserHasRight(__ADMIN_RIGHT_ACCESS, ADMIN_CONTEXT) == RightResult.RIGHT_ALLOW;
054        Set<String> populations = new HashSet<>();
055        
056        Set<String> treatedContexts = new HashSet<>();
057        
058        for (String context : contexts)
059        {
060            if (!treatedContexts.contains(context))
061            {
062                Set<String> ctxPopulations = getUserPopulationsOnContext(context, withDisabled);
063                treatedContexts.add(context);
064                if (!isAdministrator)
065                {
066                    Set<String> ctxPopulationsToCheckAccess = new HashSet<>(ctxPopulations); 
067                    
068                    String complementaryContext = _getSiteComplementaryContext(context);
069                    if (complementaryContext != null)
070                    {
071                        Set<String> compPopulations = getUserPopulationsOnContext(complementaryContext, withDisabled);
072                        ctxPopulationsToCheckAccess.addAll(compPopulations);
073                        
074                        if (contexts.contains(complementaryContext))
075                        {
076                            treatedContexts.add(complementaryContext);
077                            ctxPopulations.addAll(compPopulations);
078                        }
079                    }
080                    
081                    if (!ctxPopulationsToCheckAccess.contains(currentUser.getPopulationId()))
082                    {
083                        throw new AccessDeniedException("User " + currentUser +  " tried to access the list of user populations on context '" + context + "', but he does not belong to any populations on this context.");
084                    }
085                }
086                
087                populations.addAll(ctxPopulations);
088            }
089        }
090        
091        return populations;
092    }
093    
094    private String _getSiteComplementaryContext(String context)
095    {
096        Matcher matcher = _SITES_CONTEXT_PATTERN.matcher(context);
097        if (matcher.matches())
098        {
099            String siteName = matcher.group(1);
100            return _SITES_FO_CONTEXT_PREFIX + siteName;
101        }
102        else
103        {
104            matcher = _SITES_FO_CONTEXT_PATTERN.matcher(context);
105            if (matcher.matches())
106            {
107                String siteName = matcher.group(1);
108                return  _SITES_CONTEXT_PREFIX + siteName;
109            }
110        }
111        
112        return null;
113    }
114}