aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java14
-rw-r--r--connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java46
-rw-r--r--connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java207
-rw-r--r--connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java3
4 files changed, 254 insertions, 16 deletions
diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java
index 97defade..94c77297 100644
--- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java
+++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/MSeIDASNodeConstants.java
@@ -33,7 +33,7 @@ public class MSeIDASNodeConstants {
//default values
public static final String POLICY_DEFAULT_ALLOWED_TARGETS =
- EAAFConstants.URN_PREFIX_CDID.replaceAll(".", "\\.").replaceAll("+", "\\+") + ".*";
+ EAAFConstants.URN_PREFIX_CDID.replaceAll("\\.", "\\\\.").replaceAll("\\+", "\\\\+") + ".*";
public static final int METADATA_SOCKED_TIMEOUT = 20 * 1000; //20 seconds metadata socked timeout
public static final int DEFAULT_PVP_METADATA_VALIDITY = 24; //24 hours
@@ -42,12 +42,20 @@ public class MSeIDASNodeConstants {
public static final String ENDPOINT_PVP_POST = "/pvp/post";
public static final String ENDPOINT_PVP_REDIRECT = "/pvp/redirect";
-
+ public static final String ENDPOINT_COUNTRYSELECTION = "/myHomeCountry";
+
//paths and templates
public static final String CLASSPATH_TEMPLATE_DIR = "/templates/";
public static final String TEMPLATE_HTML_ERROR = "error.html";
public static final String TEMPLATE_HTML_PVP_POSTBINDING = "pvp2_post_binding.html";
-
+ public static final String TEMPLATE_HTML_COUNTRYSELECTION = "countrySelection.html";
+
+ //execution context and generic data
+ public static final String REQ_PARAM_SELECTED_COUNTRY = "selectedCountry";
+ public static final String DATA_REQUESTERID = "req_requesterId";
+ public static final String DATA_PROVIDERNAME = "req_providerName";
+ public static final String DATA_REQUESTED_LOA_LIST = "req_requestedLoA";
+ public static final String DATA_REQUESTED_LOA_COMPERISON = "req_requestedLoAComperision";
}
diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java
index 0edc5fcd..57f6e373 100644
--- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java
+++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/provider/PVPMetadataProvider.java
@@ -8,6 +8,7 @@ import java.util.List;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.params.HttpClientParams;
+import org.apache.commons.lang3.StringUtils;
import org.opensaml.saml2.metadata.provider.MetadataProvider;
import org.opensaml.xml.parse.BasicParserPool;
import org.slf4j.Logger;
@@ -18,11 +19,14 @@ import org.springframework.stereotype.Service;
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration;
import at.gv.egiz.eaaf.core.exceptions.EAAFConfigurationException;
+import at.gv.egiz.eaaf.core.impl.utils.FileUtils;
+import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2MetadataException;
import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.AbstractChainingMetadataProvider;
import at.gv.egiz.eaaf.modules.pvp2.impl.metadata.MetadataFilterChain;
import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.PVPEntityCategoryFilter;
import at.gv.egiz.eaaf.modules.pvp2.impl.validation.metadata.SchemaValidationFilter;
import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants;
+import at.gv.egiz.eidas.specific.connector.verification.MetadataSignatureVerificationFilter;
@Service("PVPMetadataProvider")
public class PVPMetadataProvider extends AbstractChainingMetadataProvider{
@@ -47,14 +51,31 @@ public class PVPMetadataProvider extends AbstractChainingMetadataProvider{
throws EAAFConfigurationException, IOException, CertificateException {
ISPConfiguration spConfig = basicConfig.getServiceProviderConfiguration(entityId);
if (spConfig != null) {
- String metadataURL = spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_URL);
- String trustStoreUrl = spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE);
- return createNewSimpleMetadataProvider(metadataURL,
- buildMetadataFilterChain(spConfig, metadataURL, trustStoreUrl),
- spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER),
- getTimer(),
- new BasicParserPool(),
- createHttpClient(metadataURL));
+ try {
+ String metadataURL = spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_URL);
+ if (StringUtils.isEmpty(metadataURL)) {
+ log.debug("Use EntityId: " + entityId + " instead of explicite metadataURL ... ");
+ metadataURL = entityId;
+
+ }
+ String trustStoreUrl = FileUtils.makeAbsoluteURL(
+ spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE),
+ authConfig.getConfigurationRootDirectory());
+ String trustStorePassword = spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_PVP2_METADATA_TRUSTSTORE_PASSWORD);
+
+ return createNewSimpleMetadataProvider(metadataURL,
+ buildMetadataFilterChain(spConfig, metadataURL, trustStoreUrl, trustStorePassword),
+ spConfig.getConfigurationValue(MSeIDASNodeConstants.PROP_CONFIG_SP_UNIQUEIDENTIFIER),
+ getTimer(),
+ new BasicParserPool(),
+ createHttpClient(metadataURL));
+
+ } catch (PVP2MetadataException e) {
+ log.info("Can NOT initialize Metadata signature-verification filter. Reason: " + e.getMessage());
+ throw new EAAFConfigurationException(
+ "Can NOT initialize Metadata signature-verification filter. Reason: " + e.getMessage(), e);
+
+ }
} else
log.info("No ServiceProvider with entityId: " + entityId + " in configuration.");
@@ -77,14 +98,15 @@ public class PVPMetadataProvider extends AbstractChainingMetadataProvider{
}
- private MetadataFilterChain buildMetadataFilterChain(ISPConfiguration oaParam, String metadataURL, String trustStoreUrl) throws CertificateException{
+ private MetadataFilterChain buildMetadataFilterChain(ISPConfiguration oaParam, String metadataURL, String trustStoreUrl, String trustStorePassword) throws CertificateException, PVP2MetadataException{
MetadataFilterChain filterChain = new MetadataFilterChain();
filterChain.getFilters().add(new SchemaValidationFilter(
basicConfig.getBasicMOAIDConfigurationBoolean(MSeIDASNodeConstants.PROP_CONFIG_PVP_SCHEME_VALIDATION, true)));
+
+ filterChain.getFilters().add(
+ new MetadataSignatureVerificationFilter(
+ trustStoreUrl, trustStorePassword, metadataURL));
- //TODO: add signature validation filter
-
-
filterChain.getFilters().add(new PVPEntityCategoryFilter(
basicConfig.getBasicMOAIDConfigurationBoolean(MSeIDASNodeConstants.PROP_CONFIG_PVP_ENABLE_ENTITYCATEGORIES, true)));
diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java
new file mode 100644
index 00000000..1b912ed4
--- /dev/null
+++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/AuthnRequestValidator.java
@@ -0,0 +1,207 @@
+package at.gv.egiz.eidas.specific.connector.verification;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.commons.lang3.StringUtils;
+import org.opensaml.saml2.core.AuthnContextClassRef;
+import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration;
+import org.opensaml.saml2.core.AuthnRequest;
+import org.opensaml.saml2.core.NameID;
+import org.opensaml.saml2.core.NameIDPolicy;
+import org.opensaml.saml2.core.RequestedAuthnContext;
+import org.opensaml.saml2.core.Scoping;
+import org.opensaml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.xml.XMLObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import at.gv.egiz.eaaf.core.api.IRequest;
+import at.gv.egiz.eaaf.core.api.data.PVPAttributeDefinitions;
+import at.gv.egiz.eaaf.core.exceptions.AuthnRequestValidatorException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFException;
+import at.gv.egiz.eaaf.core.exceptions.EAAFStorageException;
+import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EAAFRequestedAttribute;
+import at.gv.egiz.eaaf.modules.pvp2.api.reqattr.EAAFRequestedAttributes;
+import at.gv.egiz.eaaf.modules.pvp2.api.validation.IAuthnRequestValidator;
+import at.gv.egiz.eaaf.modules.pvp2.exception.NameIDFormatNotSupportedException;
+import at.gv.egiz.eidas.specific.connector.MSeIDASNodeConstants;
+import at.gv.egiz.eidas.specific.connector.config.ServiceProviderConfiguration;
+
+public class AuthnRequestValidator implements IAuthnRequestValidator {
+
+ private static final Logger log = LoggerFactory.getLogger(AuthnRequestValidator.class);
+
+ @Override
+ public void validate(HttpServletRequest httpReq, IRequest pendingReq, AuthnRequest authnReq,
+ SPSSODescriptor spSSODescriptor) throws AuthnRequestValidatorException {
+ try {
+ //validate NameIDPolicy
+ NameIDPolicy nameIDPolicy = authnReq.getNameIDPolicy();
+ if (nameIDPolicy != null) {
+ String nameIDFormat = nameIDPolicy.getFormat();
+ if (nameIDFormat != null) {
+ if ( !(NameID.TRANSIENT.equals(nameIDFormat) ||
+ NameID.PERSISTENT.equals(nameIDFormat)) ) {
+
+ throw new NameIDFormatNotSupportedException(nameIDFormat);
+
+ }
+
+ } else
+ log.trace("Find NameIDPolicy, but NameIDFormat is 'null'");
+ } else
+ log.trace("AuthnRequest includes no 'NameIDPolicy'");
+
+
+ //post-process RequesterId
+ String spEntityId = extractScopeRequsterId(authnReq);
+ if (StringUtils.isEmpty(spEntityId)) {
+ log.info("NO service-provider entityID in Authn. request. Stop authn. process ... ");
+ throw new AuthnRequestValidatorException("TODO", null,
+ "NO service-provider entityID in Authn. request", pendingReq);
+
+ } else
+ pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTERID, spEntityId);
+
+
+ //post-process ProviderName
+ String providerName = authnReq.getProviderName();
+ if (StringUtils.isEmpty(providerName))
+ log.info("Authn. request contains NO SP friendlyName");
+ else
+ pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_PROVIDERNAME, spEntityId);
+
+ //TODO: set to SPConfiguration
+ //post-process requested LoA
+ List<String> reqLoA = extractLoA(authnReq);
+ pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTED_LOA_LIST, reqLoA);
+
+ //TODO: set to SPConfiguration
+ //post-process requested LoA comparison-level
+ String reqLoAComperison = extractComparisonLevel(authnReq);
+ pendingReq.setGenericDataToSession(MSeIDASNodeConstants.DATA_REQUESTED_LOA_COMPERISON, reqLoAComperison);
+
+ //validate and process requested attributes
+ boolean sectorDetected = false;
+ List<XMLObject> requestedAttributes = authnReq.getExtensions().getUnknownXMLObjects();
+ for (XMLObject reqAttrObj : requestedAttributes) {
+ if (reqAttrObj instanceof EAAFRequestedAttributes) {
+ EAAFRequestedAttributes reqAttr = (EAAFRequestedAttributes)reqAttrObj;
+ if (reqAttr.getAttributes() != null && reqAttr.getAttributes().size() != 0 ) {
+ for (EAAFRequestedAttribute el : reqAttr.getAttributes()) {
+ log.trace("Processing req. attribute '" + el.getName() + "' ... ");
+ if (el.getName().equals(PVPAttributeDefinitions.EID_SECTOR_FOR_IDENTIFIER_NAME)) {
+ if (el.getAttributeValues() != null && el.getAttributeValues().size() == 1) {
+ String sectorId = el.getAttributeValues().get(0).getDOM().getTextContent();
+ ServiceProviderConfiguration spConfig = pendingReq.getServiceProviderConfiguration(ServiceProviderConfiguration.class);
+
+ try {
+ spConfig.setbPKTargetIdentifier(sectorId);
+ sectorDetected = true;
+
+ } catch (EAAFException e) {
+ log.info("Requested sector: " + sectorId + " DOES NOT match to allowed sectors for SP: " + spConfig.getUniqueIdentifier());
+ }
+
+ } else
+ log.info("Req. attribute '" + el.getName() + "' contains NO or MORE THEN ONE attribute-values. Ignore full req. attribute");
+
+ } else
+ log.debug("Ignore req. attribute: " + el.getName());
+
+ }
+
+ } else
+ log.debug("No requested Attributes in Authn. Request");
+
+ } else
+ log.info("Ignore unknown requested attribute: " + reqAttrObj.getElementQName().toString());
+
+ }
+
+ if (!sectorDetected) {
+ log.info("Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information.");
+ throw new AuthnRequestValidatorException("TODO", null,
+ "Authn.Req validation FAILED. Reason: Contains NO or NO VALID target-sector information.");
+
+ }
+
+ } catch (EAAFStorageException e) {
+ log.info("Can NOT store Authn. Req. data into pendingRequest." , e);
+ throw new AuthnRequestValidatorException("TODO", null,
+ "Can NOT store Authn. Req. data into pendingRequest.", e);
+
+ }
+
+ }
+
+ private String extractComparisonLevel(AuthnRequest authnReq) {
+ if (authnReq.getRequestedAuthnContext() != null) {
+ RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
+ return authContext.getComparison().toString();
+
+ }
+
+ return null;
+ }
+
+ private List<String> extractLoA(AuthnRequest authnReq) throws AuthnRequestValidatorException {
+ List<String> result = new ArrayList<String>();
+ if (authnReq.getRequestedAuthnContext() != null) {
+ RequestedAuthnContext authContext = authnReq.getRequestedAuthnContext();
+ if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.MINIMUM)) {
+ if (authContext.getAuthnContextClassRefs().isEmpty()) {
+ log.debug("Authn. Req. contains no requested LoA");
+
+ } else if (authContext.getAuthnContextClassRefs().size() > 1) {
+ log.info("Authn. Req. contains MORE THAN ONE requested LoA, but "
+ + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one" );
+ throw new AuthnRequestValidatorException("TODO", null,
+ "Authn. Req. contains MORE THAN ONE requested LoA, but "
+ + AuthnContextComparisonTypeEnumeration.MINIMUM + " allows only one");
+
+ } else
+ result.add(authContext.getAuthnContextClassRefs().get(0).getAuthnContextClassRef());
+
+ } else if (authContext.getComparison().equals(AuthnContextComparisonTypeEnumeration.EXACT)) {
+ for (AuthnContextClassRef el : authContext.getAuthnContextClassRefs())
+ result.add(el.getAuthnContextClassRef());
+
+ } else {
+ log.info("Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
+ + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported");
+ throw new AuthnRequestValidatorException("TODO", null,
+ "Currently only '" + AuthnContextComparisonTypeEnumeration.MINIMUM + "' and '"
+ + AuthnContextComparisonTypeEnumeration.EXACT + "' are supported");
+
+ }
+
+ }
+
+ return result;
+ }
+
+ private String extractScopeRequsterId(AuthnRequest authnReq) {
+ if (authnReq.getScoping() != null) {
+ Scoping scoping = authnReq.getScoping();
+ if (scoping.getRequesterIDs() != null &&
+ scoping.getRequesterIDs().size() > 0) {
+ if (scoping.getRequesterIDs().size() == 1)
+ return scoping.getRequesterIDs().get(0).getRequesterID();
+
+ else {
+ log.info("Authn. request contains more than on RequesterIDs! Only use first one");
+ return scoping.getRequesterIDs().get(0).getRequesterID();
+
+ }
+ }
+ }
+
+ return null;
+ }
+
+
+}
diff --git a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java
index ed88091b..d7d75f90 100644
--- a/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java
+++ b/connector/src/main/java/at/gv/egiz/eidas/specific/connector/verification/MetadataSignatureVerificationFilter.java
@@ -61,7 +61,8 @@ public class MetadataSignatureVerificationFilter extends AbstractMetadataSignatu
}
- }
+ } else
+ throw new PVP2MetadataException("Can not open trustStore: " + trustStorePath + " for metadata: " + metadataURL, null);
} catch (KeyStoreException | IOException e) {
log.warn("Can not open trustStore: " + trustStorePath + " for metadata: " + metadataURL + " Reason: " + e.getMessage(), e);