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.site; 017 018import java.io.File; 019import java.io.FileInputStream; 020import java.io.FileNotFoundException; 021import java.io.IOException; 022import java.io.InputStream; 023import java.nio.file.Files; 024import java.nio.file.Paths; 025import java.util.ArrayList; 026import java.util.Collection; 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Set; 032import java.util.stream.Collectors; 033 034import org.apache.avalon.framework.service.ServiceException; 035import org.apache.avalon.framework.service.ServiceManager; 036import org.apache.cocoon.ProcessingException; 037import org.apache.cocoon.generation.ServiceableGenerator; 038import org.apache.cocoon.xml.AttributesImpl; 039import org.apache.cocoon.xml.XMLUtils; 040import org.apache.commons.lang3.tuple.Pair; 041import org.apache.excalibur.xml.sax.SAXParser; 042import org.xml.sax.InputSource; 043import org.xml.sax.SAXException; 044 045import org.ametys.core.authentication.CredentialProvider; 046import org.ametys.core.authentication.CredentialProviderFactory; 047import org.ametys.core.authentication.CredentialProviderModel; 048import org.ametys.core.datasource.LDAPDataSourceManager; 049import org.ametys.core.datasource.SQLDataSourceManager; 050import org.ametys.core.user.directory.UserDirectory; 051import org.ametys.core.user.directory.UserDirectoryFactory; 052import org.ametys.core.user.directory.UserDirectoryModel; 053import org.ametys.core.user.population.PopulationContextHelper; 054import org.ametys.core.user.population.UserPopulation; 055import org.ametys.core.user.population.UserPopulationDAO; 056import org.ametys.core.util.IgnoreRootHandler; 057import org.ametys.runtime.config.Config; 058import org.ametys.runtime.model.ElementDefinition; 059import org.ametys.runtime.model.type.ModelItemTypeConstants; 060import org.ametys.web.repository.site.SiteManager; 061 062/** 063 * Sax the datasources files limited to datasources useful for front-office 064 */ 065public class SitesPopulationsGenerator extends ServiceableGenerator 066{ 067 private SiteManager _siteManager; 068 private PopulationContextHelper _populationContextHelper; 069 private UserPopulationDAO _userPopulationDAO; 070 private UserDirectoryFactory _userDirectoryFactory; 071 private CredentialProviderFactory _credentialProviderFactory; 072 private SQLDataSourceManager _sqlDataSourceManager; 073 private LDAPDataSourceManager _ldapDataSourceManager; 074 075 @Override 076 public void service(ServiceManager smanager) throws ServiceException 077 { 078 super.service(smanager); 079 _siteManager = (SiteManager) smanager.lookup(SiteManager.ROLE); 080 _populationContextHelper = (PopulationContextHelper) manager.lookup(PopulationContextHelper.ROLE); 081 _userPopulationDAO = (UserPopulationDAO) manager.lookup(UserPopulationDAO.ROLE); 082 _userDirectoryFactory = (UserDirectoryFactory) manager.lookup(UserDirectoryFactory.ROLE); 083 _credentialProviderFactory = (CredentialProviderFactory) manager.lookup(CredentialProviderFactory.ROLE); 084 _sqlDataSourceManager = (SQLDataSourceManager) manager.lookup(SQLDataSourceManager.ROLE); 085 _ldapDataSourceManager = (LDAPDataSourceManager) manager.lookup(LDAPDataSourceManager.ROLE); 086 } 087 088 public void generate() throws IOException, SAXException, ProcessingException 089 { 090 contentHandler.startDocument(); 091 XMLUtils.startElement(contentHandler, "Populations"); 092 093 _saxUsedStuff(); 094 _saxPopulationFile(); 095 _saxDatabasesFiles(); 096 _saxMonitoringInfo(); 097 _saxCaptchaInfo(); 098 _saxMaxUploadSizeInfo(); 099 100 XMLUtils.endElement(contentHandler, "Populations"); 101 contentHandler.endDocument(); 102 } 103 104 private void _saxMonitoringInfo() throws SAXException 105 { 106 boolean enabled = Config.getInstance().getValue("cache.monitoring.schedulers.enable"); 107 108 AttributesImpl attrs = new AttributesImpl(); 109 attrs.addCDATAAttribute("enabled", enabled ? "true" : "false"); 110 XMLUtils.startElement(contentHandler, "Monitoring", attrs); 111 112 if (enabled) 113 { 114 String datasourceId = Config.getInstance().getValue("cache.monitoring.datasource.jdbc.pool"); 115 XMLUtils.createElement(contentHandler, "Datasource", _replaceDefaultIds(datasourceId)); 116 } 117 118 XMLUtils.endElement(contentHandler, "Monitoring"); 119 } 120 121 private void _saxCaptchaInfo() throws SAXException 122 { 123 String type = Config.getInstance().getValue("runtime.captcha.type"); 124 String publicKey = Config.getInstance().getValue("runtime.captcha.recaptcha.publickey"); 125 String secretKey = Config.getInstance().getValue("runtime.captcha.recaptcha.secretkey"); 126 127 AttributesImpl attrs = new AttributesImpl(); 128 attrs.addCDATAAttribute("type", type); 129 attrs.addCDATAAttribute("publicKey", publicKey); 130 attrs.addCDATAAttribute("secretKey", secretKey); 131 132 XMLUtils.createElement(contentHandler, "Captcha", attrs); 133 } 134 135 private void _saxMaxUploadSizeInfo() throws SAXException 136 { 137 long uploadMaxSize = Config.getInstance().getValue("runtime.upload.max-size"); 138 139 XMLUtils.createElement(contentHandler, "UploadMaxSize", Long.toString(uploadMaxSize)); 140 } 141 142 private void _saxDatabasesFiles() throws IOException, SAXException 143 { 144 _saxSQLDatabaseFile(); 145 146 _saxLDAPDatabaseFile(); 147 } 148 149 private void _saxLDAPDatabaseFile() throws SAXException, IOException 150 { 151 XMLUtils.startElement(contentHandler, "LDAPDatasources"); 152 153 File file = _ldapDataSourceManager.getFileConfiguration(); 154 if (file.exists()) 155 { 156 SAXParser saxParser = null; 157 try (InputStream is = new FileInputStream(file)) 158 { 159 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 160 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 161 } 162 catch (FileNotFoundException e) 163 { 164 throw new IOException(e); 165 } 166 catch (ServiceException e) 167 { 168 throw new SAXException("Unable to get a SAX parser", e); 169 } 170 finally 171 { 172 manager.release(saxParser); 173 } 174 } 175 176 XMLUtils.endElement(contentHandler, "LDAPDatasources"); 177 } 178 179 private void _saxSQLDatabaseFile() throws SAXException, IOException 180 { 181 XMLUtils.startElement(contentHandler, "SQLDatasources"); 182 183 File file = _sqlDataSourceManager.getFileConfiguration(); 184 if (file.exists()) 185 { 186 SAXParser saxParser = null; 187 try (InputStream is = new FileInputStream(file)) 188 { 189 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 190 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 191 } 192 catch (FileNotFoundException e) 193 { 194 throw new IOException(e); 195 } 196 catch (ServiceException e) 197 { 198 throw new SAXException("Unable to get a SAX parser", e); 199 } 200 finally 201 { 202 manager.release(saxParser); 203 } 204 } 205 206 XMLUtils.endElement(contentHandler, "SQLDatasources"); 207 } 208 209 private void _saxPopulationFile() throws SAXException, IOException 210 { 211 XMLUtils.startElement(contentHandler, "UserPopulations"); 212 File file = _userPopulationDAO.getConfigurationFile(); 213 214 if (file != null && file.exists()) 215 { 216 SAXParser saxParser = null; 217 try (InputStream is = Files.newInputStream(Paths.get(file.getAbsolutePath()))) 218 { 219 saxParser = (SAXParser) manager.lookup(SAXParser.ROLE); 220 saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler)); 221 } 222 catch (ServiceException e) 223 { 224 throw new SAXException("Unable to get a SAX parser", e); 225 } 226 finally 227 { 228 manager.release(saxParser); 229 } 230 } 231 232 XMLUtils.endElement(contentHandler, "UserPopulations"); 233 } 234 235 private void _saxUsedStuff() throws SAXException 236 { 237 Set<UserPopulation> usedPopulations = _getPopulationsUsedBySites(); 238 239 XMLUtils.startElement(contentHandler, "InUse"); 240 241 _saxPopulationsInUse(usedPopulations); 242 243 _saxDatasourcesInUse(usedPopulations); 244 245 XMLUtils.endElement(contentHandler, "InUse"); 246 } 247 248 private void _saxDatasourcesInUse(Set<UserPopulation> usedPopulations) throws SAXException 249 { 250 Pair<Set<String>, Map<String, Set<String>>> usedDatasources = _getDatasourcesUsedByPopulations(usedPopulations); 251 252 XMLUtils.startElement(contentHandler, "Datasources"); 253 254 for (String datasourceId : usedDatasources.getLeft()) 255 { 256 XMLUtils.createElement(contentHandler, "Datasource", _replaceDefaultIds(datasourceId)); 257 } 258 259 XMLUtils.endElement(contentHandler, "Datasources"); 260 261 XMLUtils.startElement(contentHandler, "Datasources-Model"); 262 263 Map<String, Set<String>> datasourcesPerModel = usedDatasources.getRight(); 264 for (String modelId : datasourcesPerModel.keySet()) 265 { 266 XMLUtils.startElement(contentHandler, modelId); 267 268 for (String parameter : datasourcesPerModel.get(modelId)) 269 { 270 XMLUtils.createElement(contentHandler, parameter); 271 } 272 273 XMLUtils.endElement(contentHandler, modelId); 274 } 275 276 XMLUtils.endElement(contentHandler, "Datasources-Model"); 277 } 278 279 private void _saxPopulationsInUse(Set<UserPopulation> usedPopulations) throws SAXException 280 { 281 XMLUtils.startElement(contentHandler, "UserPopulations"); 282 for (UserPopulation userPopulation : usedPopulations) 283 { 284 XMLUtils.createElement(contentHandler, "UserPopulation", userPopulation.getId()); 285 } 286 XMLUtils.endElement(contentHandler, "UserPopulations"); 287 } 288 289 private String _replaceDefaultIds(String datasourceId) 290 { 291 // Default sources won't be default anymore => change it 292 if (_ldapDataSourceManager.getDefaultDataSourceId().equals(datasourceId)) 293 { 294 return _ldapDataSourceManager.getDefaultDataSourceDefinition().getId(); 295 } 296 else if (_sqlDataSourceManager.getDefaultDataSourceId().equals(datasourceId)) 297 { 298 return _sqlDataSourceManager.getDefaultDataSourceDefinition().getId(); 299 } 300 else 301 { 302 return datasourceId; 303 } 304 } 305 306 private Set<UserPopulation> _getPopulationsUsedBySites() 307 { 308 // Retrieve the sites to build the contexts to search on 309 Collection<String> siteNames = _siteManager.getSiteNames(); 310 311 // We return all the populations linked to at least one site 312 List<String> contexts = new ArrayList<>(); 313 for (String siteName : siteNames) 314 { 315 contexts.add("/sites/" + siteName); 316 contexts.add("/sites-fo/" + siteName); 317 } 318 319 Set<String> populations = _populationContextHelper.getUserPopulationsOnContexts(contexts, false, false); 320 return populations.stream().map(_userPopulationDAO::getUserPopulation).collect(Collectors.toSet()); 321 } 322 323 private Pair<Set<String>, Map<String, Set<String>>> _getDatasourcesUsedByPopulations(Set<UserPopulation> usedPopulations) 324 { 325 Set<String> datasourcesInUse = new HashSet<>(); 326 Map<String, Set<String>> datasourcesPerModel = new HashMap<>(); 327 328 for (UserPopulation userPopulation : usedPopulations) 329 { 330 for (UserDirectory userDirectory : userPopulation.getUserDirectories()) 331 { 332 String userDirectoryModelId = userDirectory.getUserDirectoryModelId(); 333 UserDirectoryModel userDirectoryModel = _userDirectoryFactory.getExtension(userDirectoryModelId); 334 335 Map<String, Object> parameterValues = userDirectory.getParameterValues(); 336 337 Map<String, ? extends ElementDefinition> userDirectoryModelParameters = userDirectoryModel.getParameters(); 338 for (String userDirectoryModelParameterId : userDirectoryModelParameters.keySet()) 339 { 340 ElementDefinition userDirectoryModelParameter = userDirectoryModelParameters.get(userDirectoryModelParameterId); 341 if (ModelItemTypeConstants.DATASOURCE_ELEMENT_TYPE_ID.equals(userDirectoryModelParameter.getType().getId())) 342 { 343 String datasourceId = (String) parameterValues.get(userDirectoryModelParameterId); 344 datasourcesInUse.add(datasourceId); 345 _addDatasourceToModel(userDirectoryModelId, userDirectoryModelParameterId, datasourcesPerModel); 346 } 347 } 348 } 349 350 for (CredentialProvider credentialProvider : userPopulation.getCredentialProviders()) 351 { 352 String credentialProviderModelId = credentialProvider.getCredentialProviderModelId(); 353 CredentialProviderModel credentialProviderModel = _credentialProviderFactory.getExtension(credentialProviderModelId); 354 355 Map<String, Object> parameterValues = credentialProvider.getParameterValues(); 356 357 Map<String, ? extends ElementDefinition> credentialProviderModelParameters = credentialProviderModel.getParameters(); 358 for (String credentialProviderParameterId : credentialProviderModelParameters.keySet()) 359 { 360 ElementDefinition credentialProviderModelParameter = credentialProviderModelParameters.get(credentialProviderParameterId); 361 if (ModelItemTypeConstants.DATASOURCE_ELEMENT_TYPE_ID.equals(credentialProviderModelParameter.getType().getId())) 362 { 363 String datasourceId = (String) parameterValues.get(credentialProviderParameterId); 364 datasourcesInUse.add(datasourceId); 365 _addDatasourceToModel(credentialProviderModelId, credentialProviderParameterId, datasourcesPerModel); 366 } 367 } 368 } 369 } 370 371 return Pair.of(datasourcesInUse, datasourcesPerModel); 372 } 373 374 private void _addDatasourceToModel(String modelId, String datasource, Map<String, Set<String>> datasourcesPerModel) 375 { 376 Set<String> datasources = datasourcesPerModel.get(modelId); 377 if (datasources == null) 378 { 379 datasources = new HashSet<>(); 380 datasourcesPerModel.put(modelId, datasources); 381 } 382 383 datasources.add(datasource); 384 } 385}