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.LinkedHashSet;
021import java.util.Set;
022import java.util.regex.Matcher;
023import java.util.regex.Pattern;
024
025import org.ametys.core.right.RightManager.RightResult;
026import org.ametys.core.user.UserIdentity;
027import org.ametys.core.user.population.UserPopulation;
028import org.ametys.runtime.authentication.AccessDeniedException;
029
030
031/**
032 * Helper for associating {@link UserPopulation}s to contexts.
033 * 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')
034 */
035public class PopulationContextHelper extends org.ametys.core.user.population.PopulationContextHelper
036{
037    private static final Pattern _SITES_CONTEXT_PATTERN = Pattern.compile("^/sites/(.+)$");
038    private static final Pattern _SITES_FO_CONTEXT_PATTERN = Pattern.compile("^/sites-fo/(.+)$");
039    
040    private static final String _SITES_CONTEXT_PREFIX = "/sites/";
041    private static final String _SITES_FO_CONTEXT_PREFIX = "/sites-fo/";
042    
043    @Override
044    public Set<String> getUserPopulationsOnContexts(Collection<String> contexts, boolean withDisabled, boolean checkRights)
045    {
046        UserIdentity currentUser = getCurrentUserProvider().getUser();
047        
048        if (!checkRights || contexts.contains(ADMIN_CONTEXT) || currentUser == null)
049        {
050            // no override required
051            return super.getUserPopulationsOnContexts(contexts, withDisabled, checkRights);
052        }
053        
054        boolean isAdministrator = getRightManager().currentUserHasRight(__ADMIN_RIGHT_ACCESS, ADMIN_CONTEXT) == RightResult.RIGHT_ALLOW;
055        Set<String> populations = new LinkedHashSet<>();
056        
057        Set<String> handledContexts = new HashSet<>();
058        
059        for (String context : contexts)
060        {
061            if (!handledContexts.contains(context))
062            {
063                Set<String> ctxPopulations = getUserPopulationsOnContext(context, withDisabled);
064                handledContexts.add(context);
065                if (!isAdministrator)
066                {
067                    Set<String> ctxPopulationsToCheckAccess = new HashSet<>(ctxPopulations); 
068                    
069                    String complementaryContext = _getSiteComplementaryContext(context);
070                    if (complementaryContext != null)
071                    {
072                        Set<String> compPopulations = getUserPopulationsOnContext(complementaryContext, withDisabled);
073                        ctxPopulationsToCheckAccess.addAll(compPopulations);
074                        
075                        if (contexts.contains(complementaryContext))
076                        {
077                            handledContexts.add(complementaryContext);
078                            ctxPopulations.addAll(compPopulations);
079                        }
080                    }
081                    
082                    if (!ctxPopulationsToCheckAccess.contains(currentUser.getPopulationId()))
083                    {
084                        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.");
085                    }
086                }
087                
088                populations.addAll(ctxPopulations);
089            }
090        }
091        
092        return populations;
093    }
094    
095    private String _getSiteComplementaryContext(String context)
096    {
097        Matcher matcher = _SITES_CONTEXT_PATTERN.matcher(context);
098        if (matcher.matches())
099        {
100            String siteName = matcher.group(1);
101            return _SITES_FO_CONTEXT_PREFIX + siteName;
102        }
103        else
104        {
105            matcher = _SITES_FO_CONTEXT_PATTERN.matcher(context);
106            if (matcher.matches())
107            {
108                String siteName = matcher.group(1);
109                return  _SITES_CONTEXT_PREFIX + siteName;
110            }
111        }
112        
113        return null;
114    }
115}