/*******************************************************************************
* Copyright 2018 A-SIT Plus GmbH
* AT-specific eIDAS Connector has been developed in a cooperation between EGIZ,
* A-SIT Plus GmbH, A-SIT, and Graz University of Technology.
*
* Licensed under the EUPL, Version 1.2 or - as soon they will be approved by
* the European Commission - subsequent versions of the EUPL (the "License");
* You may not use this work except in compliance with the License.
* You may obtain a copy of the License at:
* https://joinup.ec.europa.eu/news/understanding-eupl-v12
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This product combines work with different licenses. See the "NOTICE" text
* file for details on the various modules and licenses.
* The "NOTICE" text file is part of the distribution. Any derivative works
* that you distribute must include a readable copy of the "NOTICE" text file.
*******************************************************************************/
package at.asitplus.eidas.specific.connector.controller;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.transform.TransformerFactoryConfigurationError;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import at.asitplus.eidas.specific.connector.MSeIDASNodeConstants;
import at.gv.egiz.eaaf.core.api.data.EAAFConstants;
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.core.api.storage.ITransactionStorage;
import at.gv.egiz.eaaf.core.exceptions.EAAFException;
import at.gv.egiz.eaaf.core.impl.utils.DOMUtils;
import at.gv.egiz.eaaf.core.impl.utils.Random;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataBuilderConfiguration;
import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPVPMetadataConfigurationFactory;
import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPMetadataBuilder;
import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider;
@Controller
public class MonitoringController {
private static final Logger log = LoggerFactory.getLogger(MonitoringController.class);
private static final String MESSAGE_OK = "OK";
private static final String MESSAGE_ERROR = "ERROR";
private static final String MESSAGE_SKIPPED = "SKIPPED";
private static final String TEST_STORAGE = "Storage: ";
private static final String TEST_CONFIG = "Config: ";
private static final String TEST_PVPMETADATA = "PVP_metadata: ";
private static final String TEST_EIDASNODEMETADATA = "eIDASNode_metadata: ";
@Autowired private ITransactionStorage storage;
@Autowired private IConfiguration config;
@Autowired private PVPMetadataBuilder metadatabuilder;
@Autowired private IPVPMetadataConfigurationFactory configFactory;
private AbstractCredentialProvider pvpIDPCredentials;
/**
* Sets a specific credential provider for PVP S-Profile IDP component.
* @param pvpIDPCredentials credential provider
*/
public void setPvpIDPCredentials(AbstractCredentialProvider pvpIDPCredentials) {
this.pvpIDPCredentials = pvpIDPCredentials;
}
@ExceptionHandler({Throwable.class})
public void genericExceptionHandler(HttpServletResponse resp, Exception exception) throws IOException {
log.error("Monitoring Servlet receives an error." , exception);
resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
resp.getWriter().write("Reason: "
+ StringEscapeUtils.escapeHtml4(StringEscapeUtils.escapeEcmaScript(exception.getMessage())));
return;
}
@RequestMapping(value = {MSeIDASNodeConstants.ENDPOINT_MONITORING_MONITOR},
method = {RequestMethod.GET} )
public void startFullTest(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
try {
testConfig();
testStorage();
testPVPMetadata();
testEidasNodeMetadata();
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write(MESSAGE_OK);
} catch (Exception e) {
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
resp.getWriter().write(MESSAGE_ERROR);
}
}
@RequestMapping(value = {MSeIDASNodeConstants.ENDPOINT_MONITORING_VERIFY},
method = {RequestMethod.GET} )
public void startSingleTests(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String result = StringUtils.EMPTY;
try {
result += testConfig() + "
";
} catch (Exception e) {
result += e.getMessage() + "
";
}
try {
result += testStorage() + "
";
} catch (Exception e) {
result += e.getMessage() + "
";
}
try {
result += testPVPMetadata() + "
";
} catch (Exception e) {
result += e.getMessage() + "
";
}
try {
result += testEidasNodeMetadata() + "
";
} catch (Exception e) {
result += e.getMessage() + "
";
}
resp.setContentType(EAAFConstants.CONTENTTYPE_HTML_UTF8);
resp.setStatus(HttpServletResponse.SC_OK);
resp.getWriter().write(result);
}
private String testStorage( ) throws Exception {
try {
String key = Random.nextHexRandom16();
String value = Random.nextHexRandom16();
storage.put(key, value, -1);
String result = storage.get(key, String.class);
storage.remove(key);
if (result != null && result.equals(value))
return TEST_STORAGE + MESSAGE_OK;
else
log.warn("Montioring: TestValue: " + value + " does NOT match in Storage test");
} catch (EAAFException e) {
log.warn("Montioring: Can not read/write to storage.", e);
}
throw new Exception(TEST_STORAGE + MESSAGE_ERROR);
}
private String testConfig( ) throws Exception {
try {
if (config.getFullConfigurationProperties() != null
&& config.getFullConfigurationProperties().size() > 0)
return TEST_CONFIG + MESSAGE_OK;
else
log.warn("Montioring: Can not read from configuration file.");
} catch (Exception e) {
log.warn("Montioring: Can not read from configuration file.", e);
}
throw new Exception(TEST_CONFIG + MESSAGE_ERROR);
}
private String testPVPMetadata() throws Exception {
try {
//build metadata
IPVPMetadataBuilderConfiguration metadataConfig =
configFactory.generateMetadataBuilderConfiguration(
"http://localhost/monitoring",
pvpIDPCredentials);
metadatabuilder.buildPVPMetadata(metadataConfig);
return TEST_PVPMETADATA + MESSAGE_OK;
} catch (Exception | TransformerFactoryConfigurationError e) {
log.warn("Monitoring: Has an error in '" + TEST_PVPMETADATA + "': " + e.getMessage(), e);
throw new Exception(TEST_PVPMETADATA + MESSAGE_ERROR, e);
}
}
private String testEidasNodeMetadata() throws Exception {
try {
String urlString = config.getBasicConfiguration(MSeIDASNodeConstants.PROP_CONFIG_MONITORING_EIDASNODE_METADATAURL);
if (StringUtils.isEmpty(urlString)) {
log.debug("No eIDASNode metadata URL. Skipping test ... ");
return TEST_EIDASNODEMETADATA + MESSAGE_SKIPPED;
}
//create HTTP client
//TODO: update if we switch to openSAML3
HttpClient httpClient = new HttpClient();
//set parameters
HttpClientParams params = new HttpClientParams();
params.setSoTimeout(5*1000);
httpClient.setParams(params );
//request URL
HttpMethod method = new GetMethod(urlString);
int respCode = httpClient.executeMethod(method);
if (respCode != 200) {
log.warn("Monitoring: Has an error in '" + TEST_EIDASNODEMETADATA + "': " + " HTTP responsecode: " + respCode);
throw new Exception(TEST_EIDASNODEMETADATA + MESSAGE_ERROR);
}
//parse metadata
DOMUtils.parseXmlNonValidating(method.getResponseBodyAsStream());
return TEST_EIDASNODEMETADATA + MESSAGE_OK;
} catch (Exception | TransformerFactoryConfigurationError e) {
log.warn("Monitoring: Has an error in '" + TEST_EIDASNODEMETADATA + "': " + e.getMessage(), e);
throw new Exception(TEST_EIDASNODEMETADATA + MESSAGE_ERROR, e);
}
}
}