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.plugins.core.impl.user.directory;
017
018import java.util.Collection;
019import java.util.Comparator;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023import java.util.stream.Collectors;
024
025import org.apache.avalon.framework.component.Component;
026import org.apache.commons.lang3.StringUtils;
027
028import org.ametys.core.user.User;
029import org.ametys.core.user.UserIdentity;
030import org.ametys.core.user.directory.NotUniqueUserException;
031import org.ametys.core.user.directory.UserDirectory;
032import org.ametys.runtime.plugin.component.AbstractLogEnabled;
033
034/**
035 * This implementation only uses predefined users 
036 */
037public class StaticUserDirectory extends AbstractLogEnabled implements UserDirectory, Component
038{
039    private static final String __PARAM_USERS = "runtime.users.static.users";
040    
041    private Map<String, User> _staticUsers;
042
043    private String _udModelId;
044
045    private Map<String, Object> _paramValues;
046
047    private String _populationId;
048
049    private String _label;
050
051    private String _id;
052
053    private boolean _grantAllCredentials = true;
054    
055    public String getId()
056    {
057        return _id;
058    }
059    
060    public String getLabel()
061    {
062        return _label;
063    }
064    
065    @Override
066    public void init(String id, String udModelId, Map<String, Object> paramValues, String label)
067    {
068        _id = id;
069        _udModelId = udModelId;
070        _staticUsers = new HashMap<>();
071        _label = label;
072        
073        _paramValues = paramValues;
074        
075        String usersAsText = (String) paramValues.get(__PARAM_USERS);
076        for (String userLine : usersAsText.split("\\n"))
077        {
078            User user = _createUser(userLine);
079            _staticUsers.put(user.getIdentity().getLogin(), user);
080        }
081    }
082    
083    @Override
084    public void setPopulationId(String populationId)
085    {
086        _populationId = populationId;
087    }
088    
089    @Override
090    public String getPopulationId()
091    {
092        return _populationId;
093    }
094    
095    @Override
096    public Map<String, Object> getParameterValues()
097    {
098        return _paramValues;
099    }
100    
101    /**
102     * Set to false to disallow any user to be authenticated by its credentials
103     * @param grantAllCredentials true if the directory should grant all call to checkCredentials
104     */
105    public void setGrantAllCredentials(boolean grantAllCredentials)
106    {
107        _grantAllCredentials  = grantAllCredentials;
108    }
109    
110    @Override
111    public String getUserDirectoryModelId()
112    {
113        return _udModelId;
114    }
115    
116    @Override
117    public Collection<User> getUsers()
118    {
119        return _staticUsers.values();
120    }
121
122    @Override
123    public List<User> getUsers(int count, int offset, Map<String, Object> parameters)
124    {
125        String pattern = StringUtils.defaultIfEmpty((String) parameters.get("pattern"), "");
126        boolean sort = (boolean) parameters.getOrDefault("sort", false);
127        int boundedCount = count >= 0 ? count : Integer.MAX_VALUE;
128        int boundedOffset = offset >= 0 ? offset : 0;
129        
130        List<User> result = _staticUsers.values().stream().filter(user-> _isLike(user, pattern)).collect(Collectors.toList());
131        if (sort)
132        {
133            result.sort(Comparator.comparing(User::getSortableName));
134        }
135        
136        int toIndex = boundedOffset + boundedCount; 
137        toIndex = toIndex > result.size() ? result.size() : toIndex;
138        return result.subList(boundedOffset, toIndex);
139    }
140
141    @Override
142    public User getUser(String login)
143    {
144        return _staticUsers.get(login);
145    }
146    
147    public User getUserByEmail(String email) throws NotUniqueUserException
148    {
149        List<User> users = _staticUsers.values().stream().filter(user-> email.equals(user.getEmail())).collect(Collectors.toList());
150        
151        if (users.size() == 1)
152        {
153            return users.get(0);
154        }
155        else if (users.isEmpty())
156        {
157            return null;
158        }
159        else
160        {
161            throw new NotUniqueUserException("Find " + users.size() + " users matching the email " + email);
162        }
163    }
164
165    @Override
166    public boolean checkCredentials(String login, String password)
167    {
168        return _grantAllCredentials && _staticUsers.containsKey(login);
169    }
170    
171    private User _createUser(String userLine)
172    {
173        String[] userInfo = userLine.split(":");
174        
175        String login = null;
176        String lastName = null;
177        String firstName = null;
178        String email = null;
179        
180        switch (userInfo.length)
181        {
182            case 4:
183                email = userInfo[3];
184                //fall through
185            case 3:
186                firstName = userInfo[2];
187                //fall through
188            case 2:
189                lastName = userInfo[1];
190                login = userInfo[0];
191                break;
192            case 1:
193                login = userInfo[0];
194                lastName = login;
195                break;
196            default:
197                getLogger().error("Error while reading StaticUserDirectory users, cannot create a user with the data from line {}", userLine);
198                break;
199        }
200        
201        return new User(new UserIdentity(login, _populationId), lastName, firstName, email, this);
202    }
203    
204    private boolean _isLike(User user, String pattern)
205    {
206        String modifiedPattern = StringUtils.stripAccents(pattern);
207        return StringUtils.containsIgnoreCase(StringUtils.stripAccents(user.getIdentity().getLogin()), modifiedPattern) 
208                || StringUtils.containsIgnoreCase(StringUtils.stripAccents(user.getFirstName()), modifiedPattern)
209                || StringUtils.containsIgnoreCase(StringUtils.stripAccents(user.getLastName()), modifiedPattern);
210    }
211}