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.authentication;
017
018import java.util.ArrayList;
019import java.util.HashMap;
020import java.util.List;
021import java.util.Map;
022
023import org.apache.avalon.framework.parameters.Parameters;
024import org.apache.avalon.framework.service.ServiceException;
025import org.apache.avalon.framework.service.ServiceManager;
026import org.apache.cocoon.acting.ServiceableAction;
027import org.apache.cocoon.environment.ObjectModelHelper;
028import org.apache.cocoon.environment.Redirector;
029import org.apache.cocoon.environment.Request;
030import org.apache.cocoon.environment.SourceResolver;
031import org.apache.commons.lang3.StringUtils;
032
033import org.ametys.core.authentication.CredentialProvider;
034import org.ametys.core.authentication.CredentialProviderFactory;
035import org.ametys.core.authentication.CredentialProviderModel;
036import org.ametys.core.cocoon.ActionResultGenerator;
037import org.ametys.core.user.population.UserPopulation;
038import org.ametys.core.user.population.UserPopulationDAO;
039import org.ametys.core.util.JSONUtils;
040import org.ametys.runtime.model.checker.ItemChecker;
041import org.ametys.runtime.model.checker.ItemCheckerDescriptor;
042import org.ametys.runtime.model.type.ModelItemTypeConstants;
043
044/**
045 * This action checks the validity of a credential provider
046 */
047public class CheckCredentialProviderAction extends ServiceableAction
048{
049    /** Helper component gathering utility methods for the management of JSON entities */
050    private JSONUtils _jsonUtils;
051    
052    /** The credential providers factory */
053    private CredentialProviderFactory _credentialProviderFactory;
054
055    private UserPopulationDAO _userPopulationDAO;
056    
057    @Override
058    public void service(ServiceManager smanager) throws ServiceException
059    {
060        _jsonUtils = (JSONUtils) smanager.lookup(JSONUtils.ROLE);
061        _credentialProviderFactory = (CredentialProviderFactory) smanager.lookup(CredentialProviderFactory.ROLE);
062        _userPopulationDAO = (UserPopulationDAO) smanager.lookup(UserPopulationDAO.ROLE);
063        super.service(smanager);
064    }
065    
066    @SuppressWarnings("unchecked")
067    @Override
068    public Map act(Redirector redirector, SourceResolver resolver, Map objectModel, String source, Parameters parameters) throws Exception
069    {
070        Map<String, String> result = new HashMap<>();
071        Request request = ObjectModelHelper.getRequest(objectModel);
072        
073        // Prepare the values for the test
074        String fieldCheckersInfoJSON = request.getParameter("fieldCheckersInfo");
075        Map<String, Object> fieldCheckersInfo = _jsonUtils.convertJsonToMap(fieldCheckersInfoJSON);
076        Map<String, Object> valuesByParameterChecker = _getValuesByParamCheckerId(fieldCheckersInfo);
077
078        // Dispatch the requests
079        for (String fieldCheckerId : valuesByParameterChecker.keySet())
080        {
081            ItemChecker fieldChecker = (ItemChecker) ((Map<String, Object>) valuesByParameterChecker.get(fieldCheckerId)).get("checker");
082            List<String> values = (List<String>) ((Map<String, Object>) valuesByParameterChecker.get(fieldCheckerId)).get("values");
083            try 
084            {
085                fieldChecker.check(values); 
086            }
087            catch (Throwable t)
088            {
089                getLogger().error("The test '" + fieldCheckerId + "' failed : \n" + t.getMessage(), t);
090                String msg = t.getMessage() != null ? t.getMessage() : "Unknown error";
091                result.put(fieldCheckerId, msg);
092            }
093        }
094        
095        request.setAttribute(ActionResultGenerator.MAP_REQUEST_ATTR, result);
096        return result;
097    }
098    
099    @SuppressWarnings("unchecked")
100    private Map<String, Object> _getValuesByParamCheckerId(Map<String, Object> paramCheckersInfo)
101    {
102        Map<String, Object> result = new HashMap<> ();
103        
104        String populationId = (String) paramCheckersInfo.get("_user_population_id");
105        paramCheckersInfo.remove("_user_population_id");
106        UserPopulation userPopulation = null;
107        
108        for (String paramCheckerId : paramCheckersInfo.keySet())
109        {
110            Map<String, Object> valuesByParamCheckerId = new HashMap<> (); 
111            
112            // Check the ids of the parameter checkers and build the parameter checkers' list
113            ItemCheckerDescriptor parameterCheckerDescriptor = null;
114            CredentialProviderModel cpModel = null;
115            for (String credentialProviderModelId : _credentialProviderFactory.getExtensionsIds())
116            {
117                if (parameterCheckerDescriptor != null)
118                {
119                    break; // param checker was found
120                }
121                cpModel = _credentialProviderFactory.getExtension(credentialProviderModelId);
122                for (String localCheckerId : cpModel.getParameterCheckers().keySet())
123                {
124                    if (localCheckerId.equals(paramCheckerId))
125                    {
126                        parameterCheckerDescriptor = cpModel.getParameterCheckers().get(localCheckerId);
127                        break;
128                    }
129                }
130            }
131            if (cpModel == null || parameterCheckerDescriptor == null)
132            {
133                throw new IllegalArgumentException("The parameter checker '" + paramCheckerId + "' was not found.");
134            }
135            
136            ItemChecker parameterChecker  = parameterCheckerDescriptor.getParameterChecker();
137            
138            valuesByParamCheckerId.put("checker", parameterChecker);
139            
140            List<String> paramNames = (List<String>) ((Map<String, Object>) paramCheckersInfo.get(paramCheckerId)).get("testParamsNames");
141            List<String> paramRawValues = (List<String>) ((Map<String, Object>) paramCheckersInfo.get(paramCheckerId)).get("rawTestValues");
142            
143            List<String> values = new ArrayList<> ();
144            
145            // Compute the proper values for the test
146            String cpId = paramRawValues.get(paramRawValues.size() - 1);
147            for (int i = 0; i < paramNames.size() - 1; i++)
148            {
149                String paramName = StringUtils.substringAfter(paramNames.get(i), "$");
150                String untypedValue = paramRawValues.get(i);
151                
152                // Handle password field
153                if (untypedValue == null && ModelItemTypeConstants.PASSWORD_ELEMENT_TYPE_ID.equals(cpModel.getParameters().get(paramName).getType().getId()))
154                {
155                    // The password is null => it means we use the existing password
156                    
157                    if (userPopulation == null)
158                    {
159                        userPopulation = _userPopulationDAO.getUserPopulation(populationId);
160                    }
161                    CredentialProvider cp = userPopulation.getCredentialProvider(cpId);
162                    values.add((String) cp.getParameterValues().get(paramName));
163                }
164                else
165                {
166                    values.add(untypedValue);
167                }
168            }
169            
170            valuesByParamCheckerId.put("values", values);
171            
172            result.put(paramCheckerId, valuesByParamCheckerId);
173        }
174        
175        return result;
176    }
177
178}