diff options
Diffstat (limited to 'eidas_modules')
12 files changed, 1025 insertions, 0 deletions
diff --git a/eidas_modules/authmodule-eIDAS-v2/pom.xml b/eidas_modules/authmodule-eIDAS-v2/pom.xml new file mode 100644 index 00000000..48a5a249 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/pom.xml @@ -0,0 +1,124 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.gv.egiz.eidas.ms_specific</groupId> + <artifactId>modules</artifactId> + <version>1.x</version> + </parent> + + <artifactId>authmodule-eIDAS-v2</artifactId> + <name>eIDAS v2 authentication module</name> + <version>${egiz.eidas.version}</version> + <description>eIDAS module based on eIDAS node reference implementation v2.x</description> + + <properties> + <eidas-commons.version>2.0.0</eidas-commons.version> + <eidas-light-commons.version>2.0.0</eidas-light-commons.version> + <eidas-specific-communication-definition.version>2.0.0</eidas-specific-communication-definition.version> + </properties> + + <profiles> + <profile> + <id>default</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <repositories> + <repository> + <id>egiz-commons</id> + <url>https://demo.egiz.gv.at/int-repo/</url> + <releases> + <enabled>true</enabled> + </releases> + </repository> + </repositories> + </profile> + </profiles> + + <dependencies> + <dependency> + <groupId>at.gv.egiz.components</groupId> + <artifactId>egiz-spring-api</artifactId> + </dependency> + + + <!-- eIDAS reference implemenation libs --> + <dependency> + <groupId>eu.eidas</groupId> + <artifactId>eidas-commons</artifactId> + <version>${eidas-commons.version}</version> + <!--scope>provided</scope --> + <exclusions> + <exclusion> + <groupId>log4j</groupId> + <artifactId>log4j</artifactId> + </exclusion> + <exclusion> + <artifactId>log4j-over-slf4j</artifactId> + <groupId>org.slf4j</groupId> + </exclusion> + </exclusions> + </dependency> + + <dependency> + <groupId>eu.eidas</groupId> + <artifactId>eidas-light-commons</artifactId> + <version>${eidas-light-commons.version}</version> + </dependency> + + <dependency> + <groupId>eu.eidas</groupId> + <artifactId>eidas-specific-communication-definition</artifactId> + <version>${eidas-specific-communication-definition.version}</version> + </dependency> + + <!-- other third party libs --> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-lang3</artifactId> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-text</artifactId> + </dependency> + <dependency> + <groupId>org.springframework</groupId> + <artifactId>spring-webmvc</artifactId> + </dependency> + <dependency> + <groupId>javax.servlet</groupId> + <artifactId>javax.servlet-api</artifactId> + <scope>provided</scope> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <configuration> + <source>1.8</source> + <target>1.8</target> + </configuration> + </plugin> + + <!-- enable co-existence of testng and junit --> + <plugin> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <threadCount>1</threadCount> + <argLine>--add-modules java.xml.bind</argLine> + </configuration> + <dependencies> + <dependency> + <groupId>org.apache.maven.surefire</groupId> + <artifactId>surefire-junit47</artifactId> + <version>${surefire.version}</version> + </dependency> + </dependencies> + </plugin> + </plugins> + </build> +</project>
\ No newline at end of file diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/Constants.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/Constants.java new file mode 100644 index 00000000..de7d9100 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/Constants.java @@ -0,0 +1,45 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class Constants { + + //configuration properties + public static final String CONIG_PROPS_EIDAS_PREFIX="auth.eIDAS"; + public static final String CONIG_PROPS_EIDAS_NODE= CONIG_PROPS_EIDAS_PREFIX + ".node_v2"; + public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode"; + + + //http endpoint descriptions + public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/light/sp/post"; + public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/light/sp/redirect"; + public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/light/ColleagueRequest"; + public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/light/metadata"; + + //eIDAS request parameters + public static final String eIDAS_REQ_NAMEID_FORMAT = "urn:oasis:names:tc:SAML:2.0:nameid-format:persistent"; + + //eIDAS attribute names + public static final String eIDAS_ATTR_PERSONALIDENTIFIER = "PersonIdentifier"; + public static final String eIDAS_ATTR_DATEOFBIRTH = "DateOfBirth"; + public static final String eIDAS_ATTR_CURRENTGIVENNAME = "FirstName"; + public static final String eIDAS_ATTR_CURRENTFAMILYNAME = "FamilyName"; + public static final String eIDAS_ATTR_LEGALPERSONIDENTIFIER = "LegalPersonIdentifier"; + public static final String eIDAS_ATTR_LEGALNAME = "LegalName"; + + public static final List<URI> NATURALPERSONMINIMUMDATASETLIST = Collections.unmodifiableList(new ArrayList<URI>() { + private static final long serialVersionUID = 1L; + { + //TODO: find correct location of attribute definitions +// add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME.getNameUri()); +// add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME.getNameUri()); +// add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH.getNameUri()); +// add(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri()); + } + }); +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java new file mode 100644 index 00000000..1ce2f949 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationModulImpl.java @@ -0,0 +1,52 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egovernment.moa.id.auth.modules.AuthModule; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * @author tlenz + * + */ +public class eIDASAuthenticationModulImpl implements AuthModule { + + private int priority = 1; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv.egovernment.moa.id.process.api.ExecutionContext) + */ + @Override + public String selectProcess(ExecutionContext context) { + if (StringUtils.isNotBlank((String) context.get("ccc")) || + StringUtils.isNotBlank((String) context.get("CCC"))) + return "eIDASAuthentication_v2"; + else + return null; + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() + */ + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:eIDAS.Authentication.process.xml" }; + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java new file mode 100644 index 00000000..b491b8d8 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASAuthenticationSpringResourceProvider.java @@ -0,0 +1,30 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +public class eIDASAuthenticationSpringResourceProvider implements SpringResourceProvider { + + @Override + public String getName() { + return "Auth. module for eIDAS Ref. Impl. v2.x"; + } + + @Override + public String[] getPackagesToScan() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Resource[] getResourcesToLoad() { + ClassPathResource eIDASAuthConfig = new ClassPathResource("/eidas_v2_auth.beans", eIDASAuthenticationSpringResourceProvider.class); + + return new Resource[] {eIDASAuthConfig}; + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java new file mode 100644 index 00000000..51d1bd0c --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/eIDASSignalServlet.java @@ -0,0 +1,82 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.text.StringEscapeUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import at.gv.egovernment.moa.id.auth.servlet.AbstractProcessEngineSignalController; + +/** + * @author tlenz + * + */ +@Controller +public class eIDASSignalServlet extends AbstractProcessEngineSignalController { + + private static final Logger log = LoggerFactory.getLogger(eIDASSignalServlet.class); + + + public eIDASSignalServlet() { + super(); + log.debug("Registering servlet " + getClass().getName() + + " with mappings '"+ Constants.eIDAS_HTTP_ENDPOINT_SP_POST + + "' and '"+ Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT + "'."); + + } + + @RequestMapping(value = { Constants.eIDAS_HTTP_ENDPOINT_SP_POST, + Constants.eIDAS_HTTP_ENDPOINT_SP_REDIRECT + }, + method = {RequestMethod.POST, RequestMethod.GET}) + public void performCitizenCardAuthentication(HttpServletRequest req, HttpServletResponse resp) throws IOException { + signalProcessManagement(req, resp); + } + + @Override + /** + * Protocol specific implementation to get the pending-requestID + * from http request object + * + * @param request The http Servlet-Request object + * @return The Pending-request id + * + */ + public String getPendingRequestId(HttpServletRequest request) { + String sessionId = super.getPendingRequestId(request); + + try { + + // use SAML2 relayState + if (sessionId == null) { + log.trace("No transaction identifier from pendingReq. Search for SAML2 'RelayState' ..."); + sessionId = StringEscapeUtils.escapeHtml4(request.getParameter("RelayState")); + + if (StringUtils.isEmpty(sessionId)) + log.info("NO transaction identifier found! Stopping process ...."); + else + log.debug("Find transaction identifier in SAML2 'RelayState': " + sessionId); + + + } else + log.trace("Find transaction identifier from pendingReq."); + + } catch (Exception e) { + log.warn("Unable to retrieve moa session id.", e); + + } + + return sessionId; + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java new file mode 100644 index 00000000..dfd945c9 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/CreateIdentityLinkTask.java @@ -0,0 +1,160 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks; + +import java.io.InputStream; +import java.text.SimpleDateFormat; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.joda.time.DateTime; +import org.springframework.stereotype.Component; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionStorageConstants; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.eIDASAttributeException; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; +import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.util.IdentityLinkReSigner; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; + +/** + * @author tlenz + * + */ +@Component("CreateIdentityLinkTask") +public class CreateIdentityLinkTask extends AbstractAuthServletTask { + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, + HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + try{ + defaultTaskInitialization(request, executionContext); + + //get eIDAS attributes from MOA-Session + ImmutableAttributeMap eIDASAttributes = moasession.getGenericDataFromSession( + AuthenticationSessionStorageConstants.eIDAS_ATTRIBUTELIST, + ImmutableAttributeMap.class); + + IIdentityLink identityLink = null; + + //connect SZR-Gateway + //TODO: implement SZR-Gateway communication!!!! + if(true) { + + // create fake IdL + // - fetch IdL template from resources + InputStream s = CreateIdentityLinkTask.class.getResourceAsStream("/resources/xmldata/fakeIdL_IdL_template.xml"); + Element idlTemplate = DOMUtils.parseXmlValidating(s); + + identityLink = new IdentityLinkAssertionParser(idlTemplate).parseIdentityLink(); + + // replace data + Element idlassertion = identityLink.getSamlAssertion(); + + // - set fake baseID; + Node prIdentification = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_IDENT_VALUE_XPATH); + + + Object eIdentifier = eIDASAttributes.getFirstValue( + SAMLEngineUtils.getMapOfAllAvailableAttributes().get( + Constants.eIDAS_ATTR_PERSONALIDENTIFIER)); + if (eIdentifier == null || !(eIdentifier instanceof String)) + throw new eIDASAttributeException(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); + prIdentification.getFirstChild().setNodeValue((String) eIdentifier); + + //build personal identifier which looks like a baseID +// String fakeBaseID = new BPKBuilder().buildBPK(eIdentifier, "baseID"); +// Logger.info("Map eIDAS eIdentifier:" + eIdentifier + " to fake baseID:" + fakeBaseID); +// prIdentification.getFirstChild().setNodeValue(fakeBaseID); + + // - set last name + Node prFamilyName = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_FAMILY_NAME_XPATH); + Object familyName = eIDASAttributes.getFirstValue( + SAMLEngineUtils.getMapOfAllAvailableAttributes().get( + Constants.eIDAS_ATTR_CURRENTFAMILYNAME)); + if (familyName == null || !(familyName instanceof String)) + throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTFAMILYNAME); + prFamilyName.getFirstChild().setNodeValue((String) familyName); + + // - set first name + Node prGivenName = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_GIVEN_NAME_XPATH); + Object givenName = eIDASAttributes.getFirstValue( + SAMLEngineUtils.getMapOfAllAvailableAttributes().get( + Constants.eIDAS_ATTR_CURRENTGIVENNAME)); + if (givenName == null || !(givenName instanceof String)) + throw new eIDASAttributeException(Constants.eIDAS_ATTR_CURRENTGIVENNAME); + prGivenName.getFirstChild().setNodeValue((String) givenName); + + // - set date of birth + Node prDateOfBirth = XPathUtils.selectSingleNode(idlassertion, IdentityLinkAssertionParser.PERSON_DATE_OF_BIRTH_XPATH); + Object dateOfBirth = eIDASAttributes.getFirstValue( + SAMLEngineUtils.getMapOfAllAvailableAttributes().get( + Constants.eIDAS_ATTR_DATEOFBIRTH)); + if (dateOfBirth == null || !(dateOfBirth instanceof DateTime)) + throw new eIDASAttributeException(Constants.eIDAS_ATTR_DATEOFBIRTH); + + String formatedDateOfBirth = new SimpleDateFormat("yyyy-MM-dd").format(((DateTime)dateOfBirth).toDate()); + prDateOfBirth.getFirstChild().setNodeValue(formatedDateOfBirth); + + identityLink = new IdentityLinkAssertionParser(idlassertion).parseIdentityLink(); + + //resign IDL + IdentityLinkReSigner identitylinkresigner = IdentityLinkReSigner.getInstance(); + Element resignedilAssertion = identitylinkresigner.resignIdentityLink(identityLink.getSamlAssertion(), authConfig.getStorkFakeIdLResigningKey()); + identityLink = new IdentityLinkAssertionParser(resignedilAssertion).parseIdentityLink(); + + } else { + //contact SZR Gateway + Logger.debug("Starting connecting SZR Gateway"); + + //TODO:!!!!!! + + } + + Logger.debug("SZR communication was successfull"); + + if (identityLink == null) { + Logger.error("SZR Gateway did not return an identity link."); + throw new MOAIDException("stork.10", null); + } + + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_PEPS_IDL_RECEIVED); + moasession.setForeigner(true); + moasession.setIdentityLink(identityLink); + moasession.setBkuURL("Not applicable (eIDASAuthentication)"); + + //store MOA-session to database + requestStoreage.storePendingRequest(pendingReq); + + } catch (eIDASAttributeException e) { + throw new TaskExecutionException(pendingReq, "Minimum required eIDAS attributeset not found.", e); + + } catch (MOAIDException | MOADatabaseException e) { + throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); + + } catch (Exception e) { + Logger.error("IdentityLink generation for foreign person FAILED.", e); + throw new TaskExecutionException(pendingReq, "IdentityLink generation for foreign person FAILED.", e); + + } + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java new file mode 100644 index 00000000..358b681e --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/GenerateAuthnRequestTask.java @@ -0,0 +1,313 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.BooleanUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.google.common.net.MediaType; + +import at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.Constants; +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.IRequest; +import at.gv.egovernment.moa.id.commons.api.data.CPEPS; +import at.gv.egovernment.moa.id.commons.api.data.StorkAttribute; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.EidasStringUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; +import eu.eidas.auth.commons.light.impl.LightRequest; +import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; +import eu.eidas.auth.commons.protocol.IRequestMessage; +import eu.eidas.auth.commons.protocol.eidas.LevelOfAssurance; +import eu.eidas.auth.commons.protocol.eidas.LevelOfAssuranceComparison; +import eu.eidas.auth.commons.protocol.eidas.SpType; +import eu.eidas.auth.commons.protocol.eidas.impl.EidasAuthenticationRequest; + +/** + * @author tlenz + * + */ +@Component("GenerateAuthnRequestTask") +public class GenerateAuthnRequestTask extends AbstractAuthServletTask { + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, + HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + try{ + //get service-provider configuration + IOAAuthParameters oaConfig = pendingReq.getOnlineApplicationConfiguration(); + + // get target and validate citizen countryCode + String citizenCountryCode = (String) executionContext.get(MOAIDAuthConstants.PARAM_CCC); + + if (StringUtils.isEmpty(citizenCountryCode)) { + // illegal state; task should not have been executed without a selected country + throw new AuthenticationException("eIDAS.03", new Object[] { "" }); + + } + CPEPS cpeps = authConfig.getStorkConfig().getCPEPSWithFullName(citizenCountryCode); + if(null == cpeps) { + Logger.error("PEPS unknown for country: " + citizenCountryCode); + throw new AuthenticationException("eIDAS.04", new Object[] {citizenCountryCode}); + } + Logger.debug("Found eIDaS Node/C-PEPS configuration for citizen of country: " + citizenCountryCode); + + + //TODO: load authnReq End-Point URL from configuration + SingleSignOnService authnReqEndpoint = null; + + + //TODO: switch to entityID and set new status codes +// revisionsLogger.logEvent(oaConfig, pendingReq, +// MOAIDEventConstants.AUTHPROCESS_PEPS_SELECTED, +// metadataUrl); + + // assemble requested attributes + Collection<StorkAttribute> attributesFromConfig = oaConfig.getRequestedSTORKAttributes(); + + // - prepare attribute list + + // - fill container + List<AttributeDefinition<?>> reqAttrList = new ArrayList<AttributeDefinition<?>>(); + //TODO: update requested attribute builder +// for (StorkAttribute current : attributesFromConfig) { +// AttributeDefinition<?> newAttribute = SAMLEngineUtils.getMapOfAllAvailableAttributes().get(current.getName()); +// +// if (newAttribute == null) { +// Logger.warn("eIDAS attribute with friendlyName:" + current.getName() + " is not supported."); +// +// } else { +// boolean globallyMandatory = false; +// for (StorkAttribute currentGlobalAttribute : authConfig.getStorkConfig().getStorkAttributes()) +// if (current.getName().equals(currentGlobalAttribute.getName())) { +// globallyMandatory = BooleanUtils.isTrue(currentGlobalAttribute.getMandatory()); +// break; +// } +// +// Builder<?> attrBuilder = AttributeDefinition.builder(newAttribute).required(current.getMandatory() || globallyMandatory); +// reqAttrList.add(attrBuilder.build()); +// +// } +// } + + //request +// if (reqAttrList.isEmpty()) { +// Logger.info("No attributes requested by OA:" + pendingReq.getOnlineApplicationConfiguration().getPublicURLPrefix() +// + " --> Request attr:" + Constants.eIDAS_ATTR_PERSONALIDENTIFIER + " by default"); +// AttributeDefinition<?> newAttribute = SAMLEngineUtils.getMapOfAllAvailableAttributes().get(Constants.eIDAS_ATTR_PERSONALIDENTIFIER); +// Builder<?> attrBuilder = AttributeDefinition.builder(newAttribute).required(true); +// reqAttrList.add(attrBuilder.build()); +// +// } + + //build requested attribute set + ImmutableAttributeMap reqAttrMap = new ImmutableAttributeMap.Builder().putAll(reqAttrList).build(); + + //build eIDAS AuthnRequest + LightRequest.Builder authnRequestBuilder = LightRequest.builder(); + + authnRequestBuilder.id(UUID.randomUUID().toString()); + authnRequestBuilder.providerName(pendingReq.getAuthURL()); + String issur = pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA; + authnRequestBuilder.issuer(issur); + + //TODO: + //authnRequestBuilder.destination(authnReqEndpoint.getLocation()); + + + authnRequestBuilder.nameIdFormat(Constants.eIDAS_REQ_NAMEID_FORMAT); + + //set minimum required eIDAS LoA from OA config + String LoA = oaConfig.getQaaLevel(); + //TODO: +// if (MiscUtil.isNotEmpty(LoA)) +// authnRequestBuilder.levelOfAssurance(LevelOfAssurance.fromString(oaConfig.getQaaLevel())); +// else + authnRequestBuilder.levelOfAssurance(LevelOfAssurance.HIGH.getValue()); + + //TODO: check if required + //authnRequestBuilder.levelOfAssuranceComparison(LevelOfAssuranceComparison.MINIMUM); + + + //set correct SPType for this online application + if (oaConfig.hasBaseIdTransferRestriction()) + authnRequestBuilder.spType(SpType.PRIVATE.getValue()); + else + authnRequestBuilder.spType(SpType.PUBLIC.getValue()); + + + //TODO + //set service provider (eIDAS node) countryCode +// authnRequestBuilder.serviceProviderCountryCode( +// authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT")); + + //set citizen country code for foreign uses + authnRequestBuilder.citizenCountryCode(cpeps.getCountryCode()); + + //add requested attributes + authnRequestBuilder.requestedAttributes(reqAttrMap); + + + LightRequest lightAuthnReq = authnRequestBuilder.build(); + + + + //IRequestMessage authnRequest = engine.generateRequestMessage(authnRequestBuilder.build(), issur); + + //encode AuthnRequest +// byte[] token = authnRequest.getMessageBytes(); +// String SAMLRequest = EidasStringUtil.encodeToBase64(token); + + +// if (SAMLConstants.SAML2_POST_BINDING_URI.equals(authnReqEndpoint.getBinding())) +// buildPostBindingRequest(pendingReq, authnReqEndpoint, SAMLRequest, authnRequest, response); +// +// //TODO: redirect Binding is not completely implemented +// //else if (SAMLConstants.SAML2_REDIRECT_BINDING_URI.equals(authnReqEndpoint.getBinding())) +// //buildRedirecttBindingRequest(pendingReq, authnReqEndpoint, token, authnRequest, response); +// +// else { +// Logger.error("eIDAS-node use an unsupported binding (" +// + authnReqEndpoint.getBinding() + "). Request eIDAS node not possible."); +// throw new MOAIDException("eIDAS.02", new Object[]{"eIDAS-node use an unsupported binding"}); +// +// } + + + +// }catch (EIDASSAMLEngineException e){ +// throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", +// new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e)); + + } catch (MOAIDException e) { + throw new TaskExecutionException(pendingReq, "eIDAS AuthnRequest generation FAILED.", e); + + } catch (Exception e) { + Logger.error("eIDAS AuthnRequest generation FAILED.", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + } + + /** + * Encode the eIDAS request with POST binding + * + * @param pendingReq + * @param authnReqEndpoint + * @param SAMLRequest + * @param authnRequest + * @param response + * @throws MOAIDException + */ + private void buildPostBindingRequest(IRequest pendingReq, SingleSignOnService authnReqEndpoint, + String SAMLRequest, IRequestMessage authnRequest, HttpServletResponse response) + throws MOAIDException { + //send + try { + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/eidas_postbinding_template.vm"); + VelocityContext context = new VelocityContext(); + + String actionType = "SAMLRequest"; + context.put(actionType, SAMLRequest); + context.put("RelayState", pendingReq.getRequestID()); + context.put("action", authnReqEndpoint.getLocation()); + + Logger.debug("Using SingleSignOnService url as action: " + authnReqEndpoint.getLocation()); + Logger.debug("Encoded " + actionType + " original: " + SAMLRequest); + + Logger.trace("Starting template merge"); + StringWriter writer = new StringWriter(); + + Logger.trace("Doing template merge"); + template.merge(context, writer); + + Logger.trace("Template merge done"); + Logger.trace("Sending html content: " + writer.getBuffer().toString()); + + + byte[] content = writer.getBuffer().toString().getBytes("UTF-8"); + response.setContentType(MediaType.HTML_UTF_8.toString()); + response.setContentLength(content.length); + response.getOutputStream().write(content); + + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_REQUESTED, + authnRequest.getRequest().getId()); + + } catch (Exception e) { + Logger.error("Velocity general error: " + e.getMessage()); + throw new MOAIDException("eIDAS.02", new Object[]{e.getMessage()}, e); + + } + + } + + /** + * Select a SingleSignOnService endPoint from eIDAS node metadata. + * This endPoint receives the Authn. request + * + * @param idpEntity + * @return + */ + private SingleSignOnService selectSingleSignOnServiceFromMetadata(EntityDescriptor idpEntity) { + //select SingleSignOn Service endpoint from IDP metadata + SingleSignOnService endpoint = null; + if (idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS) == null) { + return null; + + } + + for (SingleSignOnService sss : + idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { + + // use POST binding as default if it exists + if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) + endpoint = sss; + + //TODO: redirect Binding is not completely implemented + // use Redirect binding as backup +// else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) +// && endpoint == null ) +// endpoint = sss; + + } + + return endpoint; + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java new file mode 100644 index 00000000..055c402f --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/java/at/gv/egiz/eidas/specific/modules/authmodule_eIDASv2/tasks/ReceiveAuthnResponseTask.java @@ -0,0 +1,143 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opensaml.saml2.core.StatusCode; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSessionStorageConstants; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; +import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; +import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; +import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASResponseNotSuccessException; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.eidas.validator.eIDASResponseValidator; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.EidasStringUtil; +import eu.eidas.auth.commons.protocol.IAuthenticationResponse; +import eu.eidas.auth.engine.ProtocolEngineI; +import eu.eidas.engine.exceptions.EIDASSAMLEngineException; + +@Component("ReceiveAuthnResponseTask") +public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { + + @Autowired(required=true) MOAeIDASChainingMetadataProvider eIDASMetadataProvider; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) throws TaskExecutionException { + + try{ + //get SAML Response + String base64SamlToken = request.getParameter("SAMLResponse"); + if (MiscUtil.isEmpty(base64SamlToken)) { + Logger.warn("No eIDAS SAMLReponse found in http request."); + throw new MOAIDException("HTTP request includes no eIDAS SAML-Response element.", null); + + } + + //get MOASession + defaultTaskInitialization(request, executionContext); + + //decode SAML response + byte[] decSamlToken = EidasStringUtil.decodeBytesFromBase64(base64SamlToken); + + //get eIDAS SAML-engine + ProtocolEngineI engine = SAMLEngineUtils.createSAMLEngine(eIDASMetadataProvider); + + //validate SAML token + IAuthenticationResponse samlResp = engine.unmarshallResponseAndValidate(decSamlToken, + request.getRemoteHost(), + Constants.CONFIG_PROPS_SKEWTIME_BEFORE, + Constants.CONFIG_PROPS_SKEWTIME_AFTER, + pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA); + + if (samlResp.isEncrypted()) { + Logger.info("Received encrypted eIDAS SAML-Response."); + //TODO: check if additional decryption operation is required + + } + + + //check response StatusCode + if (!samlResp.getStatusCode().equals(StatusCode.SUCCESS_URI)) { + Logger.info("Receice eIDAS Response with StatusCode:" + samlResp.getStatusCode() + + " Subcode:" + samlResp.getSubStatusCode() + " Msg:" + samlResp.getStatusMessage()); + throw new EIDASResponseNotSuccessException("eIDAS.11", new Object[]{samlResp.getStatusMessage()}); + + } + + // ********************************************************** + // ******* MOA-ID specific response validation ********** + // ********************************************************** + String spCountry = authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRYCODE, "AT"); + eIDASResponseValidator.validateResponse(pendingReq, samlResp, spCountry); + + + // ********************************************************** + // ******* Store resonse infos into session object ********** + // ********************************************************** + + //update MOA-Session data with received information + Logger.debug("Store eIDAS response information into MOA-session."); + + moasession.setQAALevel(samlResp.getLevelOfAssurance()); + + moasession.setGenericDataToSession( + AuthenticationSessionStorageConstants.eIDAS_ATTRIBUTELIST, + samlResp.getAttributes()); + + moasession.setGenericDataToSession( + AuthenticationSessionStorageConstants.eIDAS_RESPONSE, + decSamlToken); + + //set issuer nation as PVP attribute into MOASession + moasession.setGenericDataToSession(PVPConstants.EID_ISSUING_NATION_NAME, samlResp.getCountry()); + + //store MOA-session to database + requestStoreage.storePendingRequest(pendingReq); + + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_RECEIVED, + samlResp.getId()); + + } catch (MOAIDException e) { + throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", e); + + }catch (EIDASSAMLEngineException e) { + Logger.warn("eIDAS Response validation FAILED.", e); + Logger.debug("eIDAS response was: " + request.getParameter("SAMLResponse")); + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_RECEIVED_ERROR); + throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", + new EIDASEngineException("eIDAS.09", new Object[]{e.getMessage()}, e)); + + } catch (MOADatabaseException e) { + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_RECEIVED_ERROR); + throw new TaskExecutionException(pendingReq, "eIDAS Response processing FAILED.", + new MOAIDException("init.04", new Object[]{""}, e)); + + } catch (Exception e) { + Logger.warn("eIDAS Response processing FAILED.", e); + revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, + MOAIDEventConstants.AUTHPROCESS_PEPS_RECEIVED_ERROR); + throw new TaskExecutionException(pendingReq, e.getMessage(), + new MOAIDException("eIDAS.10", new Object[]{e.getMessage()}, e)); + + } + + } + +} diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 00000000..f5af2dc4 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.eIDASAuthenticationSpringResourceProvider
\ No newline at end of file diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml new file mode 100644 index 00000000..958c3391 --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eIDAS.Authentication.process.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<pd:ProcessDefinition id="eIDASAuthentication_v2" + xmlns:pd="http://reference.e-government.gv.at/namespace/moa/process/definition/v1"> + + + <pd:Task id="createAuthnRequest" class="GenerateAuthnRequestTask" /> + <pd:Task id="receiveAuthnResponse" class="ReceiveAuthnResponseTask" + async="true" /> + <pd:Task id="finalizeAuthentication" class="FinalizeAuthenticationTask" /> + <pd:Task id="generateIdentityLink" class="CreateIdentityLinkTask" /> + + <pd:StartEvent id="start" /> + <pd:Transition from="start" to="createAuthnRequest" /> + <pd:Transition from="createAuthnRequest" to="receiveAuthnResponse" /> + <pd:Transition from="receiveAuthnResponse" to="generateIdentityLink" /> + <pd:Transition from="generateIdentityLink" to="finalizeAuthentication" /> + <pd:Transition from="finalizeAuthentication" to="end" /> + <pd:EndEvent id="end" /> + +</pd:ProcessDefinition> diff --git a/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml new file mode 100644 index 00000000..1ad8cbeb --- /dev/null +++ b/eidas_modules/authmodule-eIDAS-v2/src/main/resources/eidas_v2_auth.beans.xml @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <context:annotation-config /> + + <bean id="eIDASAuthModule" + class="at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.eIDASAuthenticationModulImpl"> + <property name="priority" value="2" /> + </bean> + + <bean id="eIDASSignalServlet" + class="at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.eIDASSignalServlet" /> + + + <!-- Authentication Process Tasks --> + <bean id="GenerateAuthnRequestTask" + class="at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks.GenerateAuthnRequestTask" + scope="prototype" /> + + <bean id="ReceiveAuthnResponseTask" + class="at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks.ReceiveAuthnResponseTask" + scope="prototype" /> + + <bean id="CreateIdentityLinkTask" + class="at.gv.egiz.eidas.specific.modules.authmodule_eIDASv2.tasks.CreateIdentityLinkTask" + scope="prototype" /> + +</beans>
\ No newline at end of file diff --git a/eidas_modules/pom.xml b/eidas_modules/pom.xml new file mode 100644 index 00000000..2111af3a --- /dev/null +++ b/eidas_modules/pom.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>at.gv.egiz.eidas</groupId> + <artifactId>ms_specific</artifactId> + <version>1.x</version> + </parent> + + <groupId>at.gv.egiz.eidas.ms_specific</groupId> + <artifactId>modules</artifactId> + <packaging>pom</packaging> + + <name>Modules for MS specific eIDAS Node</name> + + <modules> + <!-- <module>authmodule-eIDAS-v2</module> --> + </modules> + + +</project>
\ No newline at end of file |