From cd5cef47db73c85cbb2defdec3b283655fdc859b Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 5 Jun 2018 10:46:41 +0200 Subject: update SL20 implementation --- .../VerifyXMLSignatureResponseValidator.java | 7 +- .../moa/id/moduls/AuthenticationManager.java | 18 +- .../pvp2x/utils/AssertionAttributeExtractor.java | 1 - .../moa/id/auth/AuthenticationServer.java | 6 +- .../bkamobileauthtests/BKAMobileAuthModule.java | 19 +- .../tasks/FirstBKAMobileAuthTask.java | 2 +- .../src/main/resources/BKAMobileAuth.process.xml | 14 +- .../main/resources/moaid_bka_mobileauth.beans.xml | 2 +- .../moa-id-module-sl20_authentication/pom.xml | 5 + .../sl20_auth/SL20AuthenticationModulImpl.java | 26 +- .../modules/sl20_auth/sl20/JsonSecurityUtils.java | 15 +- .../auth/modules/sl20_auth/sl20/SL20Constants.java | 8 +- .../sl20_auth/sl20/SL20HttpBindingUtils.java | 6 +- .../sl20_auth/sl20/SL20JSONBuilderUtils.java | 15 +- .../sl20_auth/sl20/SL20JSONExtractorUtils.java | 89 +++-- .../sl20/verifier/QualifiedeIDVerifier.java | 76 ++++- .../sl20_auth/tasks/CreateQualeIDRequestTask.java | 79 +++-- .../sl20_auth/tasks/ReceiveQualeIDTask.java | 41 ++- .../sl20_auth/tasks/VerifyQualifiedeIDTask.java | 62 +--- .../modules/sl20_auth/EIDDataVerifier_ATrust.java | 42 +++ .../modules/sl20_auth/EIDDataVerifier_OwnTest.java | 41 +++ .../sl20_auth/dummydata/DummyAuthConfig.java | 376 +++++++++++++++++++++ .../auth/modules/sl20_auth/dummydata/DummyOA.java | 264 +++++++++++++++ .../modules/sl20_auth/eIDDataVerifierTest.java | 105 ++++++ .../src/test/resources/SpringTest-context.xml | 13 + .../src/test/resources/tests/eIDdata_atrust.json | 14 + .../src/test/resources/tests/eIDdata_own_test.json | 8 + 27 files changed, 1167 insertions(+), 187 deletions(-) create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_ATrust.java create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_OwnTest.java create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyAuthConfig.java create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyOA.java create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/eIDDataVerifierTest.java create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/resources/SpringTest-context.xml create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_atrust.json create mode 100644 id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_own_test.json (limited to 'id') diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java index 832aa58c6..407454c2a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/validator/VerifyXMLSignatureResponseValidator.java @@ -57,12 +57,12 @@ import java.util.Set; import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; import at.gv.egovernment.moa.id.auth.exception.ValidateException; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; import at.gv.egovernment.moa.id.commons.utils.MOAIDMessageProvider; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.logging.Logger; import iaik.asn1.structures.Name; import iaik.security.ec.common.ECPublicKey; @@ -113,7 +113,8 @@ public class VerifyXMLSignatureResponseValidator { public void validate(IVerifiyXMLSignatureResponse verifyXMLSignatureResponse, List identityLinkSignersSubjectDNNames, String whatToCheck, - IOAAuthParameters oaParam) + IOAAuthParameters oaParam, + AuthConfiguration authConfig) throws ValidateException, ConfigurationException { if (verifyXMLSignatureResponse.getSignatureCheckCode() != 0) @@ -140,7 +141,7 @@ public class VerifyXMLSignatureResponseValidator { } //check QC - if (AuthConfigurationProviderFactory.getInstance().isCertifiacteQCActive() && + if (authConfig.isCertifiacteQCActive() && !whatToCheck.equals(CHECK_IDENTITY_LINK) && !verifyXMLSignatureResponse.isQualifiedCertificate()) { diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java index a24683545..e093ce1e2 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java @@ -317,9 +317,10 @@ public class AuthenticationManager extends MOAIDAuthConstants { * @param httpReqParam http parameter name, but never null */ public void addParameterNameToWhiteList(String httpReqParam) { - if (MiscUtil.isNotEmpty(httpReqParam)) - reqParameterWhiteListeForModules.add(httpReqParam); - + if (MiscUtil.isNotEmpty(httpReqParam)) { + if (!reqParameterWhiteListeForModules.contains(httpReqParam)) + reqParameterWhiteListeForModules.add(httpReqParam); + } } /** @@ -328,8 +329,11 @@ public class AuthenticationManager extends MOAIDAuthConstants { * @param httpReqParam http header name, but never null */ public void addHeaderNameToWhiteList(String httpReqParam) { - if (MiscUtil.isNotEmpty(httpReqParam)) - reqHeaderWhiteListeForModules.add(httpReqParam.toLowerCase()); + if (MiscUtil.isNotEmpty(httpReqParam)) { + if (!reqHeaderWhiteListeForModules.contains(httpReqParam.toLowerCase())) + reqHeaderWhiteListeForModules.add(httpReqParam.toLowerCase()); + + } } @@ -439,8 +443,8 @@ public class AuthenticationManager extends MOAIDAuthConstants { while(reqHeaderNames.hasMoreElements()) { String paramName = reqHeaderNames.nextElement(); if (MiscUtil.isNotEmpty(paramName) && reqHeaderWhiteListeForModules.contains(paramName.toLowerCase()) ) { - executionContext.put(paramName, - StringEscapeUtils.escapeHtml(httpReq.getHeader(paramName))); + executionContext.put(paramName.toLowerCase(), + StringEscapeUtils.escapeHtml(httpReq.getHeader(paramName.toLowerCase()))); } } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java index 5b1d952ff..4a0cec6e4 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/utils/AssertionAttributeExtractor.java @@ -309,7 +309,6 @@ public class AssertionAttributeExtractor { } private void internalInitialize() { - internalInitialize(); if (assertion.getAttributeStatements() != null && assertion.getAttributeStatements().size() > 0) { AttributeStatement attrStat = assertion.getAttributeStatements().get(0); diff --git a/id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java b/id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java index a67b27315..7ea4ee436 100644 --- a/id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java +++ b/id/server/modules/moa-id-modul-citizencard_authentication/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java @@ -311,7 +311,8 @@ public class AuthenticationServer extends BaseAuthenticationServer { verifyXMLSignatureResponse, authConfig.getIdentityLinkX509SubjectNames(), VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK, - oaParam); + oaParam, + authConfig); session.setIdentityLink(identityLink); // now validate the extended infoboxes @@ -1001,7 +1002,8 @@ public class AuthenticationServer extends BaseAuthenticationServer { // validates the VerifyXMLSignatureResponseValidator.getInstance().validate(vsresp, null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, - oaParam); + oaParam, + authConfig); // Compare AuthBlock Data with information stored in session, especially // date and time diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java index 0cef4cb41..853d1b6a4 100644 --- a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java @@ -45,7 +45,7 @@ import at.gv.egovernment.moa.util.MiscUtil; */ public class BKAMobileAuthModule implements AuthModule { - private int priority = 1; + private int priority = 2; @Autowired(required=true) protected AuthConfiguration authConfig; @Autowired(required=true) private AuthenticationManager authManager; @@ -67,7 +67,6 @@ public class BKAMobileAuthModule implements AuthModule { public void setPriority(int priority) { this.priority = priority; } - @PostConstruct public void initialDummyAuthWhiteList() { @@ -84,6 +83,8 @@ public class BKAMobileAuthModule implements AuthModule { //parameter to whiteList authManager.addParameterNameToWhiteList(FirstBKAMobileAuthTask.REQ_PARAM_eID_BLOW); +// authManager.addHeaderNameToWhiteList("SL2ClientType"); +// authManager.addHeaderNameToWhiteList("X-MOA-VDA"); } /* (non-Javadoc) @@ -92,12 +93,22 @@ public class BKAMobileAuthModule implements AuthModule { @Override public String selectProcess(ExecutionContext context) { String spEntityID = (String) context.get(MOAIDAuthConstants.PROCESSCONTEXT_UNIQUE_OA_IDENTFIER); - if (MiscUtil.isNotEmpty(spEntityID)) { - if (uniqueIDsDummyAuthEnabled.contains(spEntityID)) { + String sl20ClientTypeHeader = (String) context.get("SL2ClientType".toLowerCase()); + String sl20VDATypeHeader = (String) context.get("X-MOA-VDA".toLowerCase()); + if (MiscUtil.isNotEmpty(spEntityID)) { + Logger.trace("Check dummy-auth for SP: " + spEntityID); + + + if ( (uniqueIDsDummyAuthEnabled.contains(spEntityID))) { String eIDBlob = (String)context.get(FirstBKAMobileAuthTask.REQ_PARAM_eID_BLOW); if (eIDBlob != null && MiscUtil.isNotEmpty(eIDBlob.trim())) { return "BKAMobileAuthentication"; + } else if (MiscUtil.isNotEmpty(sl20ClientTypeHeader) + && MiscUtil.isNotEmpty(sl20VDATypeHeader) && sl20VDATypeHeader.equals("0")) { + Logger.info("Find dummy-auth request for oe.gv.at demos ... "); + return "BKAMobileAuthentication"; + } else { Logger.debug("Dummy-auth are enabled for " + spEntityID + " but no '" + FirstBKAMobileAuthTask.REQ_PARAM_eID_BLOW + "' req. parameter available."); diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java index 43043ddd6..15cf298f1 100644 --- a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java @@ -112,7 +112,7 @@ public class FirstBKAMobileAuthTask extends AbstractAuthServletTask { } parseDemoValuesIntoMOASession(pendingReq, pendingReq.getMOASession(), eIDBlobRawB64); - + } catch (MOAIDException e) { throw new TaskExecutionException(pendingReq, e.getMessage(), e); diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/BKAMobileAuth.process.xml b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/BKAMobileAuth.process.xml index 6f41f347a..07faeae88 100644 --- a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/BKAMobileAuth.process.xml +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/BKAMobileAuth.process.xml @@ -5,17 +5,17 @@ STORK authentication both with C-PEPS supporting xml signatures and with C-PEPS not supporting xml signatures. --> - - + + - - - - + + + + + diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/moaid_bka_mobileauth.beans.xml b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/moaid_bka_mobileauth.beans.xml index ef13b0348..79f29e08c 100644 --- a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/moaid_bka_mobileauth.beans.xml +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/moaid_bka_mobileauth.beans.xml @@ -10,7 +10,7 @@ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> - + diff --git a/id/server/modules/moa-id-module-sl20_authentication/pom.xml b/id/server/modules/moa-id-module-sl20_authentication/pom.xml index d08e0f0ec..5b682538c 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/pom.xml +++ b/id/server/modules/moa-id-module-sl20_authentication/pom.xml @@ -58,6 +58,11 @@ + + org.springframework + spring-test + test + junit junit diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java index a4044ce21..367e7b604 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/SL20AuthenticationModulImpl.java @@ -22,6 +22,9 @@ */ package at.gv.egovernment.moa.id.auth.modules.sl20_auth; +import java.util.Arrays; +import java.util.List; + import javax.annotation.PostConstruct; import org.apache.commons.lang3.StringUtils; @@ -38,10 +41,10 @@ import at.gv.egovernment.moa.logging.Logger; * @author tlenz * */ -public class SL20AuthenticationModulImpl implements AuthModule { - +public class SL20AuthenticationModulImpl implements AuthModule { private int priority = 3; - + public static final List VDA_TYPE_IDS = Arrays.asList("1", "2", "3", "4"); + @Autowired(required=true) protected AuthConfiguration authConfig; @Autowired(required=true) private AuthenticationManager authManager; @@ -62,6 +65,7 @@ public class SL20AuthenticationModulImpl implements AuthModule { protected void initalSL20Authentication() { //parameter to whiteList authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE); + authManager.addHeaderNameToWhiteList(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE); } @@ -71,17 +75,23 @@ public class SL20AuthenticationModulImpl implements AuthModule { */ @Override public String selectProcess(ExecutionContext context) { - if (StringUtils.isNotBlank((String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase())) || - StringUtils.isNotBlank((String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE))) { - Logger.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found"); + String sl20ClientTypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE.toLowerCase()); + String sl20VDATypeHeader = (String) context.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); + + if ( StringUtils.isNotBlank(sl20ClientTypeHeader) +// && ( +// StringUtils.isNotBlank(sl20VDATypeHeader) +// //&& VDA_TYPE_IDS.contains(sl20VDATypeHeader.trim()) +// ) + ) { + Logger.trace(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found"); return "SL20Authentication"; } else { Logger.trace("No '" + SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE + "' header found"); return null; - } - + } } /* (non-Javadoc) diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java index 2563c7f7d..c95e0b731 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/JsonSecurityUtils.java @@ -1,9 +1,11 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20; +import java.io.IOException; import java.security.Key; import java.security.KeyStore; import java.security.PrivateKey; import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; import java.util.Collections; @@ -36,6 +38,7 @@ import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoPars import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.utils.X509Utils; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.KeyStoreUtils; import at.gv.egovernment.moa.util.MiscUtil; @@ -143,8 +146,11 @@ public class JsonSecurityUtils implements IJOSETools{ //set signing information jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); jws.setKey(signPrivKey); - jws.setCertificateChainHeaderValue(signCertChain); - + + //TODO: + //jws.setCertificateChainHeaderValue(signCertChain); + jws.setX509CertSha256ThumbprintHeaderValue(signCertChain[0]); + return jws.getCompactSerialization(); } catch (JoseException e) { @@ -181,6 +187,11 @@ public class JsonSecurityUtils implements IJOSETools{ } else { Logger.info("Can NOT find JOSE certificate in truststore."); Logger.debug("JOSE certificate: " + sortedX5cCerts.get(0).toString()); + try { + Logger.debug("Cert: " + Base64Utils.encode(sortedX5cCerts.get(0).getEncoded())); + } catch (CertificateEncodingException | IOException e) { + e.printStackTrace(); + } } diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java index 33bb4fe36..658384578 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20Constants.java @@ -8,7 +8,7 @@ import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; import org.jose4j.jws.AlgorithmIdentifiers; public class SL20Constants { - public static final String CURRENT_SL20_VERSION = "10"; + public static final int CURRENT_SL20_VERSION = 10; //http binding parameters public static final String PARAM_SL20_REQ_COMMAND_PARAM = "slcommand"; @@ -18,6 +18,7 @@ public class SL20Constants { public static final String PARAM_SL20_REQ_TRANSACTIONID = "slTransactionID"; public static final String HTTP_HEADER_SL20_CLIENT_TYPE = "SL2ClientType"; + public static final String HTTP_HEADER_SL20_VDA_TYPE = "X-MOA-VDA"; public static final String HTTP_HEADER_VALUE_NATIVE = "nativeApp"; @@ -129,8 +130,9 @@ public class SL20Constants { public static final String SL20_COMMAND_PARAM_EID_DATAURL = SL20_COMMAND_PARAM_GENERAL_DATAURL; public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES = "attributes"; public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE = "MANDATE-REFERENCE-VALUE"; - public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-FRIENDLYNAME"; - public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-UNIQUEID"; + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID = "SP-UNIQUEID"; + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME = "SP-FRIENDLYNAME"; + public static final String SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE = "SP-COUNTRYCODE"; public static final String SL20_COMMAND_PARAM_EID_X5CENC = SL20_COMMAND_PARAM_GENERAL_RESPONSEENCRYPTIONCERTIFICATE; public static final String SL20_COMMAND_PARAM_EID_RESULT_IDL = "EID-IDENTITY-LINK"; public static final String SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK = "EID-AUTH-BLOCK"; diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java index cc7137a0f..169cb8e73 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20HttpBindingUtils.java @@ -2,7 +2,6 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20; import java.io.IOException; import java.io.StringWriter; -import java.io.UnsupportedEncodingException; import java.net.URISyntaxException; import javax.servlet.http.HttpServletRequest; @@ -10,6 +9,7 @@ import javax.servlet.http.HttpServletResponse; import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.ContentType; +import org.jose4j.base64url.Base64Url; import com.google.gson.JsonObject; @@ -33,7 +33,9 @@ public class SL20HttpBindingUtils { } else { Logger.debug("Client request containts is no native client ... "); URIBuilder clientRedirectURI = new URIBuilder(redirectURL); - clientRedirectURI.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, sl20Forward.toString()); + clientRedirectURI.addParameter( + SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, + Base64Url.encode(sl20Forward.toString().getBytes())); response.setStatus(307); response.setHeader("Location", clientRedirectURI.build().toString()); diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java index 52d7e1e67..d5dec1fe1 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONBuilderUtils.java @@ -387,7 +387,7 @@ public class SL20JSONBuilderUtils { */ public static JsonObject createGenericRequest(String reqId, String transactionId, JsonElement payLoad, String signedPayload) throws SLCommandoBuildException { JsonObject req = new JsonObject(); - addSingleStringElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); + addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); addSingleStringElement(req, SL20Constants.SL20_REQID, reqId, true); addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false); addOnlyOnceOfTwo(req, SL20Constants.SL20_PAYLOAD, SL20Constants.SL20_SIGNEDPAYLOAD, @@ -411,7 +411,7 @@ public class SL20JSONBuilderUtils { JsonElement payLoad, String signedPayload) throws SLCommandoBuildException { JsonObject req = new JsonObject(); - addSingleStringElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); + addSingleIntegerElement(req, SL20Constants.SL20_VERSION, SL20Constants.CURRENT_SL20_VERSION, true); addSingleStringElement(req, SL20Constants.SL20_RESPID, respId, true); addSingleStringElement(req, SL20Constants.SL20_INRESPTO, inResponseTo, true); addSingleStringElement(req, SL20Constants.SL20_TRANSACTIONID, transactionId, false); @@ -568,6 +568,17 @@ public class SL20JSONBuilderUtils { } + private static void addSingleIntegerElement(JsonObject parent, String keyId, Integer value, boolean isRequired) throws SLCommandoBuildException { + validateParentAndKey(parent, keyId); + + if (isRequired && value == null) + throw new SLCommandoBuildException(keyId + " has an empty value"); + + else if (value != null) + parent.addProperty(keyId, value); + + } + private static void addSingleJSONElement(JsonObject parent, String keyId, JsonElement element, boolean isRequired) throws SLCommandoBuildException { validateParentAndKey(parent, keyId); diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java index 6949b7a18..2e81d9c64 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/SL20JSONExtractorUtils.java @@ -1,7 +1,6 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20; import java.io.InputStreamReader; -import java.net.URLDecoder; import java.util.Base64; import java.util.HashMap; import java.util.Iterator; @@ -13,6 +12,7 @@ import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.utils.URIBuilder; import org.apache.log4j.Logger; +import org.jose4j.base64url.Base64Url; import com.google.gson.JsonElement; import com.google.gson.JsonObject; @@ -107,45 +107,64 @@ public class SL20JSONExtractorUtils { } /** - * Extract Map of Key/Value pairs from a JSON Array + * Extract Map of Key/Value pairs from a JSON Element * - * @param input - * @param keyID + * @param input parent JSON object + * @param keyID KeyId of the child that should be parsed * @param isRequired * @return * @throws SLCommandoParserException */ public static Map getMapOfStringElements(JsonObject input, String keyID, boolean isRequired) throws SLCommandoParserException { JsonElement internal = getAndCheck(input, keyID, isRequired); + return getMapOfStringElements(internal); + } + + /** + * Extract Map of Key/Value pairs from a JSON Element + * + * @param input + * @return + * @throws SLCommandoParserException + */ + public static Map getMapOfStringElements(JsonElement input) throws SLCommandoParserException { Map result = new HashMap(); - if (internal != null) { - if (!internal.isJsonArray()) - throw new SLCommandoParserException("JSON Element IS NOT a JSON array"); - - Iterator arrayIterator = internal.getAsJsonArray().iterator(); - while(arrayIterator.hasNext()) { - //JsonObject next = arrayIterator.next().getAsJsonObject(); - //result.put( - // next.get(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_KEY).getAsString(), - // next.get(SL20Constants.SL20_COMMAND_PARAM_GENERAL_REQPARAMETER_VALUE).getAsString()); - JsonElement next = arrayIterator.next(); - Iterator> entry = next.getAsJsonObject().entrySet().iterator(); - while (entry.hasNext()) { - Entry el = entry.next(); - if (result.containsKey(el.getKey())) - log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... "); - - result.put(el.getKey(), el.getValue().getAsString()); + if (input != null) { + if (input.isJsonArray()) { + Iterator arrayIterator = input.getAsJsonArray().iterator(); + while(arrayIterator.hasNext()) { + JsonElement next = arrayIterator.next(); + Iterator> entry = next.getAsJsonObject().entrySet().iterator(); + entitySetToMap(result, entry); - } - } + } + + } else if (input.isJsonObject()) { + Iterator> objectKeys = input.getAsJsonObject().entrySet().iterator(); + entitySetToMap(result, objectKeys); + + } else + throw new SLCommandoParserException("JSON Element IS NOT a JSON array or a JSON object"); + } return result; } + private static void entitySetToMap(Map result, Iterator> entry) { + while (entry.hasNext()) { + Entry el = entry.next(); + if (result.containsKey(el.getKey())) + log.info("Attr. Map already contains Element with Key: " + el.getKey() + ". Overwrite element ... "); + + result.put(el.getKey(), el.getValue().getAsString()); + + } + + } + public static JsonElement extractSL20Result(JsonObject command, IJOSETools decrypter, boolean mustBeEncrypted) throws SL20Exception { JsonElement result = command.get(SL20Constants.SL20_COMMAND_CONTAINER_RESULT); @@ -207,19 +226,21 @@ public class SL20JSONExtractorUtils { if (sl20Payload == null && sl20SignedPayload == null) throw new SLCommandoParserException("NO payLoad OR signedPayload FOUND."); - else if (sl20Payload == null && sl20SignedPayload == null) - throw new SLCommandoParserException("payLoad AND signedPayload FOUND. Can not used twice"); - + //TODO: + //else if (sl20Payload != null && sl20SignedPayload != null) { + //log.warn("Find 'signed' AND 'unsigned' SL2.0 payload"); + //throw new SLCommandoParserException("payLoad AND signedPayload FOUND. Can not used twice"); + //} else if (sl20SignedPayload == null && mustBeSigned) throw new SLCommandoParserException("payLoad MUST be signed."); + + else if (joseTools != null && sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) { + return joseTools.validateSignature(sl20SignedPayload.getAsString()); - else if (sl20Payload != null) + } else if (sl20Payload != null) return new VerificationResult(sl20Payload.getAsJsonObject()); - else if (sl20SignedPayload != null && sl20SignedPayload.isJsonPrimitive()) { - return joseTools.validateSignature(sl20SignedPayload.getAsString()); - - } else + else throw new SLCommandoParserException("Internal build error"); @@ -242,10 +263,10 @@ public class SL20JSONExtractorUtils { throw new SLCommandoParserException("Find Redirect statuscode but not Location header"); String sl20RespString = new URIBuilder(locationHeader[0].getValue()).getQueryParams().get(0).getValue(); - sl20Resp = new JsonParser().parse(URLDecoder.decode(sl20RespString)).getAsJsonObject(); + sl20Resp = new JsonParser().parse(Base64Url.encode((sl20RespString.getBytes()))).getAsJsonObject(); } else if (httpResp.getStatusLine().getStatusCode() == 200) { - if (!httpResp.getEntity().getContentType().getValue().equals("application/json;charset=UTF-8")) + if (!httpResp.getEntity().getContentType().getValue().startsWith("application/json")) throw new SLCommandoParserException("SL20 response with a wrong ContentType: " + httpResp.getEntity().getContentType().getValue()); sl20Resp = parseSL20ResultFromResponse(httpResp.getEntity()); diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java index d07d7a78a..a7253c2c6 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/sl20/verifier/QualifiedeIDVerifier.java @@ -1,14 +1,22 @@ package at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.verifier; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.util.Arrays; import java.util.Date; import java.util.List; import org.jaxen.SimpleNamespaceContext; +import org.opensaml.Configuration; +import org.opensaml.DefaultBootstrap; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.xml.XMLObject; +import org.opensaml.xml.io.Unmarshaller; +import org.opensaml.xml.io.UnmarshallerFactory; import org.w3c.dom.Element; +import org.xml.sax.SAXException; import at.gv.egovernment.moa.id.auth.builder.SignatureVerificationUtils; -import at.gv.egovernment.moa.id.auth.exception.ValidateException; import at.gv.egovernment.moa.id.auth.invoke.SignatureVerificationInvoker; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SL20eIDDataValidationException; import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants; @@ -22,10 +30,12 @@ import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AssertionAttributeExtractor; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.sig.tsl.utils.MiscUtil; import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; public class QualifiedeIDVerifier { @@ -69,21 +79,22 @@ public class QualifiedeIDVerifier { verifyXMLSignatureResponse, authConfig.getIdentityLinkX509SubjectNames(), VerifyXMLSignatureResponseValidator.CHECK_IDENTITY_LINK, - oaParam); + oaParam, + authConfig); } public static IVerifiyXMLSignatureResponse verifyAuthBlock(String authBlockB64, IOAAuthParameters oaParam, AuthConfiguration authConfig) throws MOAIDException, IOException { String trustProfileId = authConfig.getMoaSpAuthBlockTrustProfileID(oaParam.isUseAuthBlockTestTestStore()); - List verifyTransformsInfoProfileID = null; + List verifyTransformsInfoProfileID = Arrays.asList("SL20Authblock_v1.0"); SignatureVerificationUtils sigVerify = new SignatureVerificationUtils(); IVerifiyXMLSignatureResponse sigVerifyResult = sigVerify.verify(Base64Utils.decode(authBlockB64, false), trustProfileId , verifyTransformsInfoProfileID); // validates the VerifyXMLSignatureResponseValidator.getInstance().validate(sigVerifyResult, - null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, oaParam); + null, VerifyXMLSignatureResponseValidator.CHECK_AUTH_BLOCK, oaParam, authConfig); return sigVerifyResult; @@ -120,7 +131,7 @@ public class QualifiedeIDVerifier { // date and time validateSigningDateTime(sigVerifyResult, authBlockExtractor); - } catch ( ValidateException e) { + } catch ( Exception e) { Logger.warn("Validation of eID information FAILED. ", e); throw new SL20eIDDataValidationException(new Object[] { SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, @@ -134,6 +145,59 @@ public class QualifiedeIDVerifier { } + public static Assertion parseAuthBlockToSaml2Assertion(String authblockB64) throws SL20eIDDataValidationException { + try { + //parse authBlock into SAML2 Assertion + byte[] authBlockBytes = Base64Utils.decode(authblockB64, false); + Element authBlockDOM = DOMUtils.parseXmlValidating(new ByteArrayInputStream(authBlockBytes)); + + //A-Trust workarounda +// Element authBlockDOM = DOMUtils.parseXmlValidating(new ByteArrayInputStream(authblockB64.getBytes())); +// Element authBlockDOM = DOMUtils.parseXmlNonValidating(new ByteArrayInputStream(authblockB64.getBytes())); + + DefaultBootstrap.bootstrap(); + UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); + Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(authBlockDOM); + XMLObject samlAssertion = unmarshaller.unmarshall(authBlockDOM); + + //validate SAML2 Assertion + SAML2Utils.schemeValidation(samlAssertion); + + if (samlAssertion instanceof Assertion) + return (Assertion) samlAssertion; + else + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + "AuthBlock is NOT of type SAML2 Assertion" + }); + + } catch (SL20eIDDataValidationException e) { + throw e; + + } catch (SAXException e) { + Logger.info("Scheme validation of SAML2 AuthBlock FAILED. Reason: " + e.getMessage()); + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + e.getMessage() + }, + e); + + } catch (Exception e) { + Logger.info("Can not parse AuthBlock. Reason: " + e.getMessage()); + Logger.trace("FullAuthBlock: " + authblockB64); + throw new SL20eIDDataValidationException( + new Object[] { + SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, + e.getMessage() + }, + e); + + } + + } + private static void validateSigningDateTime( IVerifiyXMLSignatureResponse sigVerifyResult, AssertionAttributeExtractor authBlockExtractor) throws SL20eIDDataValidationException { Date signingDate = sigVerifyResult.getSigningDateTime(); Date notBefore = authBlockExtractor.getAssertionNotBefore(); @@ -163,7 +227,7 @@ public class QualifiedeIDVerifier { + " NotBefore:" + notBefore.toString() + " NotOrNotAfter:" + notOrNotAfter.toString()); - if (signingDate.after(notBefore) || signingDate.before(notOrNotAfter)) + if (signingDate.after(notBefore) && signingDate.before(notOrNotAfter)) Logger.debug("Signing date validation successfull"); else { diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java index 763454639..26283cab2 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/CreateQualeIDRequestTask.java @@ -4,7 +4,6 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Map.Entry; import javax.net.ssl.SSLSocketFactory; import javax.servlet.http.HttpServletRequest; @@ -17,6 +16,7 @@ import org.apache.http.client.methods.HttpPost; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.message.BasicNameValuePair; +import org.jose4j.base64url.Base64Url; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -39,7 +39,6 @@ import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.commons.utils.HttpClientWithProxySupport; -import at.gv.egovernment.moa.id.commons.utils.KeyValueUtils; import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.SSLUtils; @@ -62,7 +61,7 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { IOAAuthParameters oaConfig = pendingReq.getOnlineApplicationConfiguration(); //get basic configuration parameters - String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig); + String vdaQualeIDUrl = extractVDAURLForSpecificOA(oaConfig, executionContext); if (MiscUtil.isEmpty(vdaQualeIDUrl)) { Logger.error("NO VDA URL for qualified eID (" + Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT + ")"); throw new SL20Exception("sl20.03", new Object[]{"NO VDA URL for qualified eID"}); @@ -83,17 +82,21 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { //build qualifiedeID command Map qualifiedeIDParams = new HashMap(); qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPUNIQUEID, oaConfig.getPublicURLPrefix()); - qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName()); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPFRIENDLYNAME, oaConfig.getFriendlyName()); + qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_SPCOUNTRYCODE, "AT"); //qualifiedeIDParams.put(SL20Constants.SL20_COMMAND_PARAM_EID_ATTRIBUTES_MANDATEREFVALUE, UUID.randomUUID().toString()); + //TODO: JsonObject qualeIDCommandParams = SL20JSONBuilderUtils.createQualifiedeIDCommandParameters( authBlockId, dataURL, qualifiedeIDParams, - joseTools.getEncryptionCertificate()); + //joseTools.getEncryptionCertificate()); + null); //String qualeIDReqId = UUID.randomUUID().toString(); - String qualeIDReqId = SAML2Utils.getSecureIdentifier(); + //TODO: work-Around for A-trust + String qualeIDReqId = SAML2Utils.getSecureIdentifier().substring(0, 12); String signedQualeIDCommand = SL20JSONBuilderUtils.createSignedCommand(SL20Constants.SL20_COMMAND_IDENTIFIER_QUALIFIEDEID, qualeIDCommandParams, joseTools); JsonObject sl20Req = SL20JSONBuilderUtils.createGenericRequest(qualeIDReqId, null, null, signedQualeIDCommand); @@ -105,19 +108,21 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { sslFactory, authConfig.getBasicMOAIDConfigurationBoolean(AuthConfiguration.PROP_KEY_OVS_SSL_HOSTNAME_VALIDATION, true)); - //build post request + //build http POST request HttpPost httpReq = new HttpPost(new URIBuilder(vdaQualeIDUrl).build()); - httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); List parameters = new ArrayList();; - - //correct one - //parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()))); - - //A-Trust current version - parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM_OLD, sl20Req.toString())); + parameters.add(new BasicNameValuePair(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes()))); httpReq.setEntity(new UrlEncodedFormEntity(parameters )); + //build http GET request +// URIBuilder sl20ReqUri = new URIBuilder(vdaQualeIDUrl); +// sl20ReqUri.addParameter(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM, Base64Url.encode(sl20Req.toString().getBytes())); +// HttpGet httpReq = new HttpGet(sl20ReqUri.build()); + //set native client header + httpReq.addHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE, SL20Constants.HTTP_HEADER_VALUE_NATIVE); + + Logger.trace("Request VDA via SL20 with: " + Base64Url.encode(sl20Req.toString().getBytes())); //request VDA HttpResponse httpResp = httpClient.execute(httpReq); @@ -190,26 +195,40 @@ public class CreateQualeIDRequestTask extends AbstractAuthServletTask { } - private String extractVDAURLForSpecificOA(IOAAuthParameters oaConfig) { - Map listOfVDAs = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST); - Map listOfSPs = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_SP_LIST); + private String extractVDAURLForSpecificOA(IOAAuthParameters oaConfig, ExecutionContext executionContext) { - for (Entry el : listOfSPs.entrySet()) { - List spEntityIds = KeyValueUtils.getListOfCSVValues(el.getValue()); - if (spEntityIds.contains(oaConfig.getPublicURLPrefix())) { - Logger.trace("Select VDA endPoint with Id: " + el.getKey()); - if (listOfVDAs.containsKey(el.getKey())) - return listOfVDAs.get(el.getKey()); - - else - Logger.info("No VDA endPoint with Id: " + el.getKey()); - - } else - Logger.trace("SP list: " + el.getKey() + " does not contain OAIdentifier: " + oaConfig.getPublicURLPrefix()); + //selection based on EntityID +// Map listOfVDAs = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST); +// Map listOfSPs = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONFIG_PROP_SP_LIST); +// +// for (Entry el : listOfSPs.entrySet()) { +// List spEntityIds = KeyValueUtils.getListOfCSVValues(el.getValue()); +// if (spEntityIds.contains(oaConfig.getPublicURLPrefix())) { +// Logger.trace("Select VDA endPoint with Id: " + el.getKey()); +// if (listOfVDAs.containsKey(el.getKey())) +// return listOfVDAs.get(el.getKey()); +// +// else +// Logger.info("No VDA endPoint with Id: " + el.getKey()); +// +// } else +// Logger.trace("SP list: " + el.getKey() + " does not contain OAIdentifier: " + oaConfig.getPublicURLPrefix()); +// +// } + + //selection based on request Header + String sl20VDATypeHeader = (String) executionContext.get(SL20Constants.HTTP_HEADER_SL20_VDA_TYPE.toLowerCase()); + if (MiscUtil.isNotEmpty(sl20VDATypeHeader)) { + String vdaURL = authConfig.getBasicMOAIDConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_LIST + sl20VDATypeHeader); + if (MiscUtil.isNotEmpty(vdaURL)) + return vdaURL.trim(); + else + Logger.info("Can NOT find VDA with Id: " + sl20VDATypeHeader + ". Use default VDA"); + } - Logger.debug("NO SP specific VDA endpoint found. Use default VDA"); + Logger.info("NO SP specific VDA endpoint found. Use default VDA"); return authConfig.getBasicMOAIDConfiguration(Constants.CONFIG_PROP_VDA_ENDPOINT_QUALeID_DEFAULT); } diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java index b7fe579a3..357ecb6ec 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/ReceiveQualeIDTask.java @@ -12,6 +12,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.http.entity.ContentType; +import org.jose4j.base64url.Base64Url; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -37,6 +38,7 @@ import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moa.util.StreamUtils; import at.gv.egovernment.moaspss.logging.Logger; @@ -55,17 +57,30 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { try { //get SL2.0 command or result from HTTP request Map reqParams = getParameters(request); - String sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); + String sl20Result = reqParams.get(SL20Constants.PARAM_SL20_REQ_COMMAND_PARAM); + if (MiscUtil.isEmpty(sl20Result)) { - Logger.info("NO SL2.0 commando or result FOUND."); - throw new SL20Exception("sl20.04", null); + + //TODO: remove + //Workaround for SIC Handy-Signature, because it sends result in InputStream + String test = StreamUtils.readStream(request.getInputStream(), "UTF-8"); + if (MiscUtil.isNotEmpty(test)) { + Logger.info("Use SIC Handy-Signature work-around!"); + sl20Result = test.substring("slcommand=".length()); + + } else { + Logger.info("NO SL2.0 commando or result FOUND."); + throw new SL20Exception("sl20.04", null); + } } - + + Logger.trace("Received SL2.0 result: " + sl20Result); + //parse SL2.0 command/result into JSON try { JsonParser jsonParser = new JsonParser(); - JsonElement sl20Req = jsonParser.parse(sl20Result); + JsonElement sl20Req = jsonParser.parse(Base64Url.decodeToUtf8String(sl20Result)); sl20ReqObj = sl20Req.getAsJsonObject(); } catch (JsonSyntaxException e) { @@ -111,16 +126,13 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { JsonElement qualeIDResult = SL20JSONExtractorUtils.extractSL20Result( payLoad, joseTools, authConfig.getBasicMOAIDConfigurationBoolean(Constants.CONFIG_PROP_DISABLE_EID_ENCRYPTION, true)); - + //extract attributes from result - String idlB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL, true); - String authBlockB64 = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, true); - String ccsURL = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL, true); - String LoA = SL20JSONExtractorUtils.getStringValue(qualeIDResult.getAsJsonObject(), - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA, true); + Map eIDData = SL20JSONExtractorUtils.getMapOfStringElements(qualeIDResult); + String idlB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL); + String authBlockB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK); + String ccsURL = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_CCSURL); + String LoA = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_LOA); //cache qualified eID data into pending request pendingReq.setGenericDataToSession( @@ -233,6 +245,7 @@ public class ReceiveQualeIDTask extends AbstractAuthServletTask { redirectTwoCommand, null); + //workaround for SIC VDA if (request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE) != null && request.getHeader(SL20Constants.HTTP_HEADER_SL20_CLIENT_TYPE).equals(SL20Constants.HTTP_HEADER_VALUE_NATIVE)) { Logger.debug("Client request containts 'native client' header ... "); diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java index b5c84d315..cc74bb11a 100644 --- a/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java +++ b/id/server/modules/moa-id-module-sl20_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/tasks/VerifyQualifiedeIDTask.java @@ -6,14 +6,8 @@ import java.util.Calendar; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.opensaml.Configuration; import org.opensaml.saml2.core.Assertion; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.io.Unmarshaller; -import org.opensaml.xml.io.UnmarshallerFactory; import org.springframework.stereotype.Component; -import org.w3c.dom.Element; -import org.xml.sax.SAXException; import at.gv.egovernment.moa.id.advancedlogging.TransactionIDUtils; import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; @@ -28,9 +22,7 @@ import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; 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.AssertionAttributeExtractor; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.DOMUtils; import at.gv.egovernment.moa.util.DateTimeUtils; import at.gv.egovernment.moaspss.logging.Logger; @@ -75,7 +67,7 @@ public class VerifyQualifiedeIDTask extends AbstractAuthServletTask { IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink(); IVerifiyXMLSignatureResponse authBlockVerificationResult = null; try { - Assertion authBlock = parseAuthBlockToSaml2Assertion(authBlockB64); + Assertion authBlock = QualifiedeIDVerifier.parseAuthBlockToSaml2Assertion(authBlockB64); AssertionAttributeExtractor authBlockExtractor = new AssertionAttributeExtractor(authBlock); @@ -126,55 +118,5 @@ public class VerifyQualifiedeIDTask extends AbstractAuthServletTask { TransactionIDUtils.removeSessionId(); } - } - - private Assertion parseAuthBlockToSaml2Assertion(String authblockB64) throws SL20eIDDataValidationException { - try { - //parse authBlock into SAML2 Assertion - byte[] authBlockBytes = Base64Utils.decode(authblockB64, false); - Element authBlockDOM = DOMUtils.parseXmlValidating(new ByteArrayInputStream(authBlockBytes)); - UnmarshallerFactory unmarshallerFactory = Configuration.getUnmarshallerFactory(); - Unmarshaller unmarshaller = unmarshallerFactory.getUnmarshaller(authBlockDOM); - XMLObject samlAssertion = unmarshaller.unmarshall(authBlockDOM); - - //validate SAML2 Assertion - SAML2Utils.schemeValidation(samlAssertion); - - if (samlAssertion instanceof Assertion) - return (Assertion) samlAssertion; - else - throw new SL20eIDDataValidationException( - new Object[] { - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, - "AuthBlock is NOT of type SAML2 Assertion" - }); - - } catch (SL20eIDDataValidationException e) { - throw e; - - } catch (SAXException e) { - Logger.info("Scheme validation of SAML2 AuthBlock FAILED. Reason: " + e.getMessage()); - throw new SL20eIDDataValidationException( - new Object[] { - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, - e.getMessage() - }, - e); - - } catch (Exception e) { - Logger.info("Can not parse AuthBlock. Reason: " + e.getMessage()); - Logger.trace("FullAuthBlock: " + authblockB64); - throw new SL20eIDDataValidationException( - new Object[] { - SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK, - e.getMessage() - }, - e); - - } - - } - - - + } } diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_ATrust.java b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_ATrust.java new file mode 100644 index 000000000..49c11ea05 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_ATrust.java @@ -0,0 +1,42 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth; + +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration("/SpringTest-context.xml") +public class EIDDataVerifier_ATrust extends eIDDataVerifierTest { + + @Before + public void init() throws SLCommandoParserException, IOException { + String eIDDataString = IOUtils.toString(new InputStreamReader(this.getClass().getResourceAsStream("/tests/eIDdata_atrust.json"))); + JsonParser jsonParser = new JsonParser(); + JsonObject qualeIDResult = jsonParser.parse(eIDDataString).getAsJsonObject(); + + JsonObject payLoad = SL20JSONExtractorUtils.getJSONObjectValue(qualeIDResult, "payload", true); + JsonObject result = SL20JSONExtractorUtils.getJSONObjectValue(payLoad, "result", true); + + + eIDData = SL20JSONExtractorUtils.getMapOfStringElements(result); + if (eIDData == null || eIDData.isEmpty()) + throw new SLCommandoParserException("Can not load eID data"); + + } + + @Override + protected String getSl20ReqId() { + return "_28ab8536d068a153e1a"; + } +} diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_OwnTest.java b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_OwnTest.java new file mode 100644 index 000000000..65460439e --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/EIDDataVerifier_OwnTest.java @@ -0,0 +1,41 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth; + +import java.io.IOException; +import java.io.InputStreamReader; + +import org.apache.commons.io.IOUtils; +import org.junit.Before; +import org.junit.runner.RunWith; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; + +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.exceptions.SLCommandoParserException; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20JSONExtractorUtils; + +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration({ "/SpringTest-context.xml" }) +public class EIDDataVerifier_OwnTest extends eIDDataVerifierTest { + + @Before + public void init() throws SLCommandoParserException, IOException { + String eIDDataString = IOUtils.toString(new InputStreamReader(this.getClass().getResourceAsStream("/tests/eIDdata_own_test.json"))); + JsonParser jsonParser = new JsonParser(); + JsonElement payLoad = jsonParser.parse(eIDDataString).getAsJsonObject(); + JsonObject result = SL20JSONExtractorUtils.getJSONObjectValue(payLoad.getAsJsonObject(), "result", true); + + eIDData = SL20JSONExtractorUtils.getMapOfStringElements(result); + if (eIDData == null || eIDData.isEmpty()) + throw new SLCommandoParserException("Can not load eID data"); + + } + + @Override + protected String getSl20ReqId() { + return "_57010b7fcc93cc4cf3f2b764389137c2"; + } + +} diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyAuthConfig.java b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyAuthConfig.java new file mode 100644 index 000000000..93e046797 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyAuthConfig.java @@ -0,0 +1,376 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.dummydata; + +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.api.ConnectionParameterInterface; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.IStorkConfig; +import at.gv.egovernment.moa.id.commons.api.data.ProtocolAllowed; +import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; +import at.gv.util.config.EgovUtilPropertiesConfiguration; + +public class DummyAuthConfig implements AuthConfiguration { + + @Override + public String getRootConfigFileDir() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDefaultChainingMode() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getTrustedCACertificates() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isTrustmanagerrevoationchecking() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String[] getActiveProfiles() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Properties getGeneralPVP2ProperiesConfig() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Properties getGeneralOAuth20ProperiesConfig() { + // TODO Auto-generated method stub + return null; + } + + @Override + public ProtocolAllowed getAllowedProtocols() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getConfigurationWithPrefix(String Prefix) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getConfigurationWithKey(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBasicMOAIDConfiguration(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBasicMOAIDConfiguration(String key, String defaultValue) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Map getBasicMOAIDConfigurationWithPrefix(String prefix) { + // TODO Auto-generated method stub + return null; + } + + @Override + public int getTransactionTimeOut() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int getSSOCreatedTimeOut() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public int getSSOUpdatedTimeOut() { + // TODO Auto-generated method stub + return 0; + } + + @Override + public String getAlternativeSourceID() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getLegacyAllowedProtocols() { + // TODO Auto-generated method stub + return null; + } + + @Override + public IOAAuthParameters getOnlineApplicationParameter(String oaURL) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMoaSpAuthBlockTrustProfileID(boolean useTestTrustStore) throws ConfigurationException { + if (useTestTrustStore) + return "MOAIDBuergerkarteAuthentisierungsDatenMitTestkarten"; + else + return "MOAIDBuergerkarteAuthentisierungsDaten"; + } + + @Override + public List getMoaSpAuthBlockVerifyTransformsInfoIDs() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConnectionParameterInterface getMoaSpConnectionParameter() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConnectionParameterInterface getForeignIDConnectionParameter(IOAAuthParameters oaParameters) + throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public ConnectionParameterInterface getOnlineMandatesConnectionParameter(IOAAuthParameters oaParameters) + throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMoaSpIdentityLinkTrustProfileID(boolean useTestTrustStore) throws ConfigurationException { + if (useTestTrustStore) + return "MOAIDBuergerkartePersonenbindungMitTestkarten"; + else + return "MOAIDBuergerkartePersonenbindung"; + } + + @Override + public List getTransformsInfos() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getIdentityLinkX509SubjectNames() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getSLRequestTemplates() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSLRequestTemplates(String type) throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getDefaultBKUURLs() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDefaultBKUURL(String type) throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSSOTagetIdentifier() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSSOFriendlyName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getSSOSpecialText() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMOASessionEncryptionKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMOAConfigurationEncryptionKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isIdentityLinkResigning() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String getIdentityLinkResigningKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isMonitoringActive() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String getMonitoringTestIdentityLinkURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getMonitoringMessageSuccess() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isAdvancedLoggingActive() { + // TODO Auto-generated method stub + return false; + } + + @Override + public List getPublicURLPrefix() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isVirtualIDPsEnabled() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isPVP2AssertionEncryptionActive() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isCertifiacteQCActive() { + return true; + } + + @Override + public IStorkConfig getStorkConfig() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public EgovUtilPropertiesConfiguration geteGovUtilsConfig() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getDocumentServiceUrl() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isStorkFakeIdLActive() { + // TODO Auto-generated method stub + return false; + } + + @Override + public List getStorkFakeIdLCountries() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getStorkNoSignatureCountries() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getStorkFakeIdLResigningKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isPVPSchemaValidationActive() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Map getConfigurationWithWildCard(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getDefaultRevisionsLogEventCodes() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isHTTPAuthAllowed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String[] getRevocationMethodOrder() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean getBasicMOAIDConfigurationBoolean(String key, boolean defaultValue) { + // TODO Auto-generated method stub + return false; + } + +} diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyOA.java b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyOA.java new file mode 100644 index 000000000..2df20edb4 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/dummydata/DummyOA.java @@ -0,0 +1,264 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth.dummydata; + +import java.security.PrivateKey; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.data.CPEPS; +import at.gv.egovernment.moa.id.commons.api.data.SAML1ConfigurationParameters; +import at.gv.egovernment.moa.id.commons.api.data.StorkAttribute; +import at.gv.egovernment.moa.id.commons.api.data.StorkAttributeProviderPlugin; +import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; + +public class DummyOA implements IOAAuthParameters { + + @Override + public Map getFullConfiguration() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getConfigurationValue(String key) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getFriendlyName() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getPublicURLPrefix() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean hasBaseIdInternalProcessingRestriction() throws ConfigurationException { + return false; + } + + @Override + public boolean hasBaseIdTransferRestriction() throws ConfigurationException { + return false; + } + + @Override + public String getAreaSpecificTargetIdentifier() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAreaSpecificTargetIdentifierFriendlyName() throws ConfigurationException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isInderfederationIDP() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isSTORKPVPGateway() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isRemovePBKFromAuthBlock() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String getKeyBoxIdentifier() { + // TODO Auto-generated method stub + return null; + } + + @Override + public SAML1ConfigurationParameters getSAML1Parameter() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getTemplateURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getAditionalAuthBlockText() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getBKUURL(String bkutype) { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getBKUURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean useSSO() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean useSSOQuestion() { + // TODO Auto-generated method stub + return false; + } + + @Override + public List getMandateProfiles() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isShowMandateCheckBox() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isOnlyMandateAllowed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isShowStorkLogin() { + // TODO Auto-generated method stub + return false; + } + + @Override + public String getQaaLevel() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isRequireConsentForStorkAttributes() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Collection getRequestedSTORKAttributes() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getBKUSelectionTemplate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public byte[] getSendAssertionTemplate() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection getPepsList() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getIDPAttributQueryServiceURL() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isInboundSSOInterfederationAllowed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isInterfederationSSOStorageAllowed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isOutboundSSOInterfederationAllowed() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isTestCredentialEnabled() { + return true; + } + + @Override + public List getTestCredentialOIDs() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isUseIDLTestTrustStore() { + return true; + } + + @Override + public boolean isUseAuthBlockTestTestStore() { + return true; + } + + @Override + public PrivateKey getBPKDecBpkDecryptionKey() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isPassivRequestUsedForInterfederation() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isPerformLocalAuthenticationOnInterfederationError() { + // TODO Auto-generated method stub + return false; + } + + @Override + public Collection getStorkAPs() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getReversionsLoggingEventCodes() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/eIDDataVerifierTest.java b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/eIDDataVerifierTest.java new file mode 100644 index 000000000..52743c9da --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/java/at/gv/egovernment/moa/id/auth/modules/sl20_auth/eIDDataVerifierTest.java @@ -0,0 +1,105 @@ +package at.gv.egovernment.moa.id.auth.modules.sl20_auth; + +import java.io.ByteArrayInputStream; +import java.util.Map; + +import org.junit.Test; +import org.opensaml.saml2.core.Assertion; + +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.dummydata.DummyAuthConfig; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.dummydata.DummyOA; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.SL20Constants; +import at.gv.egovernment.moa.id.auth.modules.sl20_auth.sl20.verifier.QualifiedeIDVerifier; +import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; +import at.gv.egovernment.moa.id.commons.api.data.IVerifiyXMLSignatureResponse; +import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AssertionAttributeExtractor; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.MOAException; +import at.gv.egovernment.moa.spss.api.Configurator; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moaspss.logging.LoggingContext; +import at.gv.egovernment.moaspss.logging.LoggingContextManager; +import iaik.security.ec.provider.ECCelerate; +import iaik.security.provider.IAIK; + +public abstract class eIDDataVerifierTest { + + protected Map eIDData = null; + + @Test + public void dummyTest() throws Exception { + + + } + + @Test + public void parseIdl() throws Exception { + String idlB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL); + if (MiscUtil.isEmpty(idlB64)) + throw new Exception("NO IDL found"); + + IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink(); + + if (idl == null) + throw new Exception("IDL parsing FAILED"); + + } + + @Test + public void parseAuthBlock() throws Exception { + String authBlockB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK); + if (MiscUtil.isEmpty(authBlockB64)) + throw new Exception("NO AuthBlock found"); + + Assertion authBlock = QualifiedeIDVerifier.parseAuthBlockToSaml2Assertion(authBlockB64); + new AssertionAttributeExtractor(authBlock); + + } + + @Test + public void checkIDLAgainstAuthblock() throws Exception { + String authBlockB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_AUTHBLOCK); + String idlB64 = eIDData.get(SL20Constants.SL20_COMMAND_PARAM_EID_RESULT_IDL); + if (MiscUtil.isEmpty(idlB64)) + throw new Exception("NO IDL found"); + if (MiscUtil.isEmpty(authBlockB64)) + throw new Exception("NO AuthBlock found"); + + IIdentityLink idl = new IdentityLinkAssertionParser(new ByteArrayInputStream(Base64Utils.decode(idlB64, false))).parseIdentityLink(); + Assertion authBlock = QualifiedeIDVerifier.parseAuthBlockToSaml2Assertion(authBlockB64); + AssertionAttributeExtractor authBlockExtractor = new AssertionAttributeExtractor(authBlock); + + IOAAuthParameters dummyOA = new DummyOA(); + AuthConfiguration dummyAuthConfig = new DummyAuthConfig(); + + Logger.info("Loading Java security providers."); + System.setProperty("moa.spss.server.configuration", "F:\\Projekte\\configs\\moa-spss\\MOASPSSConfiguration.xml"); + + IAIK.addAsProvider(); + ECCelerate.addAsProvider(); + try { + LoggingContextManager.getInstance().setLoggingContext( + new LoggingContext("startup")); + Logger.debug("Starting MOA-SPSS initialization process ... "); + Configurator.getInstance().init(); + Logger.info("MOA-SPSS initialization complete "); + + } catch (MOAException e) { + Logger.error("MOA-SP initialization FAILED!", e.getWrapped()); + throw new ConfigurationException("config.10", new Object[] { e + .toString() }, e); + } + + QualifiedeIDVerifier.verifyIdentityLink(idl, dummyOA , dummyAuthConfig); + IVerifiyXMLSignatureResponse authBlockVerificationResult = QualifiedeIDVerifier.verifyAuthBlock(authBlockB64, dummyOA , dummyAuthConfig); + QualifiedeIDVerifier.checkConsistencyOfeIDData(getSl20ReqId(), idl, authBlockExtractor, authBlockVerificationResult); + + } + + protected abstract String getSl20ReqId(); +} diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/SpringTest-context.xml b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/SpringTest-context.xml new file mode 100644 index 000000000..011d1ed64 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/SpringTest-context.xml @@ -0,0 +1,13 @@ + + + + + diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_atrust.json b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_atrust.json new file mode 100644 index 000000000..09190574d --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_atrust.json @@ -0,0 +1,14 @@ +{ + "v": 10, + "respID": "Cl6uQjZlOWFjUEbtyXb0", + "inResponseTo": "_28ab8536d068a153e1a", + "payload": { + "name": "qualifiedeID", + "result": { + "EID-IDENTITY-LINK": "PHNhbWw6QXNzZXJ0aW9uIEFzc2VydGlvbklEPSJzenIuYm1pLmd2LmF0LUFzc2VydGlvbklEMTUyNzY2OTEwMDU5MTI3NDQiIElzc3VlSW5zdGFudD0iMjAxOC0wNS0zMFQxMDozMTo0MCswMTowMCIgSXNzdWVyPSJodHRwOi8vcG9ydGFsLmJtaS5ndi5hdC9yZWYvc3pyL2lzc3VlciIgTWFqb3JWZXJzaW9uPSIxIiBNaW5vclZlcnNpb249IjAiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMDphc3NlcnRpb24iIHhtbG5zOnByPSJodHRwOi8vcmVmZXJlbmNlLmUtZ292ZXJubWVudC5ndi5hdC9uYW1lc3BhY2UvcGVyc29uZGF0YS8yMDAyMDIyOCMiIHhtbG5zOmRzaWc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIHhtbG5zOmVjZHNhPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSMiIHhtbG5zOnNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSI+Cgk8c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+CgkJPHNhbWw6U3ViamVjdD4KCQkJPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj4KCQkJCTxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206c2VuZGVyLXZvdWNoZXM8L3NhbWw6Q29uZmlybWF0aW9uTWV0aG9kPgoJCQkJPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbkRhdGE+CgkJCQkJPHByOlBlcnNvbiBzaTp0eXBlPSJwcjpQaHlzaWNhbFBlcnNvblR5cGUiPjxwcjpJZGVudGlmaWNhdGlvbj48cHI6VmFsdWU+dHFDUUVDNytBcUdFZWVMMzkwVjVKZz09PC9wcjpWYWx1ZT48cHI6VHlwZT51cm46cHVibGljaWQ6Z3YuYXQ6YmFzZWlkPC9wcjpUeXBlPjwvcHI6SWRlbnRpZmljYXRpb24+PHByOk5hbWU+PHByOkdpdmVuTmFtZT5NYXg8L3ByOkdpdmVuTmFtZT48cHI6RmFtaWx5TmFtZSBwcmltYXJ5PSJ1bmRlZmluZWQiPk11c3Rlcm1hbm48L3ByOkZhbWlseU5hbWU+PC9wcjpOYW1lPjxwcjpEYXRlT2ZCaXJ0aD4xOTQwLTAxLTAxPC9wcjpEYXRlT2ZCaXJ0aD48L3ByOlBlcnNvbj4KCQkJCTwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YT4KCQkJPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+CgkJPC9zYW1sOlN1YmplY3Q+Cgk8c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iQ2l0aXplblB1YmxpY0tleSIgQXR0cmlidXRlTmFtZXNwYWNlPSJ1cm46cHVibGljaWQ6Z3YuYXQ6bmFtZXNwYWNlczppZGVudGl0eWxpbms6MS4yIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT48ZHNpZzpSU0FLZXlWYWx1ZT48ZHNpZzpNb2R1bHVzPnMwWmhkR2E4REgwSW1iTlU3aTRxdDRtR25CUEFlTDk5Q0dkZmRCOEhWWE5CNWd3d2VMY1o5WE1TWUJvUHFHdFVqemh6S29zRkN5M0sNCmpsSEVrejB0L3JQemhOVGRsVjJRN0FGWEZlT2g3M3dPajQ3R1B2T2lVNzdwQjE3WnJaOHlObW1JTTEyUVE5MVN0RGFWRkUra0dxUEkNCmNFZHZiZk94blU4aGNpa3lYcWVheFZVV3oxbVdXTnRveUwyWG5wa1U0QkZVQnU1NWg5S2tYVEFQcnBUbEFMZjkvRDFKamZWb05tamwNCnBLWXh6Q3JBSmE4Sno4Ui9sNis0U0U3YXc3dGZuazNZUXkxcFVmNWZmellkeXZQS2ZxVTBUTUVKLzdpOW1ORHFCZlVwcVhBRWowdWUNCkpvRWs0UC9pa2Q5UnZuVUlsU0V1NzFHMyt1VEluSXBaaTd2UG93PT08L2RzaWc6TW9kdWx1cz48ZHNpZzpFeHBvbmVudD5BUUFCPC9kc2lnOkV4cG9uZW50PjwvZHNpZzpSU0FLZXlWYWx1ZT48L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50PgoJPGRzaWc6U2lnbmF0dXJlPgoJCTxkc2lnOlNpZ25lZEluZm8+CgkJCTxkc2lnOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8+CgkJCTxkc2lnOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIgLz4KCQkJPGRzaWc6UmVmZXJlbmNlIFVSST0iIj4KCQkJCTxkc2lnOlRyYW5zZm9ybXM+CgkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvVFIvMTk5OS9SRUMteHBhdGgtMTk5OTExMTYiPgoJCQkJCQk8ZHNpZzpYUGF0aD5ub3QoYW5jZXN0b3Itb3Itc2VsZjo6cHI6SWRlbnRpZmljYXRpb24pPC9kc2lnOlhQYXRoPgoJCQkJCTwvZHNpZzpUcmFuc2Zvcm0+CgkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiIC8+CgkJCQk8L2RzaWc6VHJhbnNmb3Jtcz4KCQkJCTxkc2lnOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIiAvPgoJCQkJPGRzaWc6RGlnZXN0VmFsdWU+QmVIdUFyYXUzSFVQcXg5dHV3QTRGaDNOSDB3PTwvZHNpZzpEaWdlc3RWYWx1ZT4KCQkJPC9kc2lnOlJlZmVyZW5jZT4KCQkJPGRzaWc6UmVmZXJlbmNlIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNNYW5pZmVzdCIgVVJJPSIjbWFuaWZlc3QiPgoJCQkJPGRzaWc6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiIC8+CgkJCQk8ZHNpZzpEaWdlc3RWYWx1ZT5mVEUrMjRnRHlkUlgvd0p2QlAxOUlucU54Rkk9PC9kc2lnOkRpZ2VzdFZhbHVlPgoJCQk8L2RzaWc6UmVmZXJlbmNlPgoJCTwvZHNpZzpTaWduZWRJbmZvPgoJCTxkc2lnOlNpZ25hdHVyZVZhbHVlPgogICAgUHpLMWR2N2JFMGhQcGxlc1ZaRFhHSWxhbTlUK0JxWkd4ZWs5RHVuYkhNK21GWWI3a1NaZTN2eEszUmhRZjNBV3djbXFtVWZPRlJObg0KWndxYnovNGRZd2hJRld6VGdMelVmMlZkR0JsN2szbS8wSmJXSkV1bEtobE5vV2ZSTkRrdTRZcmI2THVrWjdaQzJFcWd2UXYxa1BRTg0Kb1BvQ1I5d3hUc1RKWFNCaHdLc0lERG9vZHY3aUVpWGFCM0xmVHQrQWdYdEdvbWRRaktjby9WamJSSzRUUEkvQUVNVU1KWm9zZlJYMg0KdmE2U1BaUnV4QjBlWkwwVGVzYittRjlFaUlOVnNTSU9nbTVSRE95V1ZRZkJnVG9nYjNoWmlLVmh0a1IvaWlSNmhZNlA2b1cwTDh4ag0KMG5ZVldPRHAxSlJML3Z0ZDFhUklVYzNCQTJQaFkrRmdJR1FHTUE9PQogIDwvZHNpZzpTaWduYXR1cmVWYWx1ZT48ZHNpZzpLZXlJbmZvPjxkc2lnOlg1MDlEYXRhPjxkc2lnOlg1MDlDZXJ0aWZpY2F0ZT5NSUlGdXpDQ0JLT2dBd0lCQWdJREdTa2VNQTBHQ1NxR1NJYjNEUUVCQlFVQU1JR2ZNUXN3Q1FZRFZRUUdFd0pCDQpWREZJTUVZR0ExVUVDZ3cvUVMxVWNuVnpkQ0JIWlhNdUlHWXVJRk5wWTJobGNtaGxhWFJ6YzNsemRHVnRaU0JwDQpiU0JsYkdWcmRISXVJRVJoZEdWdWRtVnlhMlZvY2lCSGJXSklNU0l3SUFZRFZRUUxEQmxoTFhOcFoyNHRZMjl5DQpjRzl5WVhSbExXeHBaMmgwTFRBeU1TSXdJQVlEVlFRRERCbGhMWE5wWjI0dFkyOXljRzl5WVhSbExXeHBaMmgwDQpMVEF5TUI0WERURTFNRGN5T0RFMU5Ea3dOVm9YRFRJd01EY3lPREV6TkRrd05Wb3dnYll4Q3pBSkJnTlZCQVlUDQpBa0ZVTVI0d0hBWURWUVFLREJWRVlYUmxibk5qYUhWMGVtdHZiVzFwYzNOcGIyNHhJakFnQmdOVkJBc01HVk4wDQpZVzF0ZW1Gb2JISmxaMmx6ZEdWeVltVm9iMlZ5WkdVeExqQXNCZ05WQkFNTUpWTnBaMjVoZEhWeWMyVnlkbWxqDQpaU0JFWVhSbGJuTmphSFYwZW10dmJXMXBjM05wYjI0eEZUQVRCZ05WQkFVVERETXlOVGt5T0RNeU16azVPREVjDQpNQm9HQ1NxR1NJYjNEUUVKQVF3TlpITnJRR1J6YXk1bmRpNWhkRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEDQpnZ0VQQURDQ0FRb0NnZ0VCQU4rZEJTRUJHajJqVVhJSzFNcDNsVnhjL1phK3BKTWl5S3JYM0cxWnhnWC9pa3g3DQpEOXNjc1BZTXQ0NzNMbEFXbDljbUNiSGJKSytQVjJYTk5kVVJMTVVDSVgrNHZVTnMyTUhlRFRRdFg4QlhqSkZwDQp3SllTb2FSSlEzOUZWUy8xcjVzV2NyYTlIaGRtN3c1R3R4LzJ1a3lEWDBrZGt4YXdraFA0RVFFemkvU0krRnVnDQpuK1dxZ1ExbkFkbGJ4Yi9kY0J3NXcxaDliM2xtdXdVZjR6M29vUVdVRDJEZ0Eva0tkMUtlak5SNDNtTFVzbXZTDQp6ZXZQeFQ5enM3OHBPUjFPYWNCN0lzelRWSlBYZU9FYWFOWkhubkIvVWVPM2c4TEVWLzNPa1hjVWdjTWtiSUlpDQphQkhsbGw3MVBxMENPajlrcWpYb2U3T3JSakxZNWkzS3dPcGE2VE1DQXdFQUFhT0NBZVV3Z2dIaE1CRUdBMVVkDQpEZ1FLQkFoTUNBNmVHdlMxdWpBT0JnTlZIUThCQWY4RUJBTUNCTEF3RGdZSEtpZ0FDZ0VIQVFRREFRSC9NQk1HDQpBMVVkSXdRTU1BcUFDRWtjV0RwUDZBMERNQWtHQTFVZEV3UUNNQUF3RkFZSEtpZ0FDZ0VCQVFRSkRBZENVMEl0DQpSRk5MTUg4R0NDc0dBUVVGQndFQkJITXdjVEJHQmdnckJnRUZCUWN3QW9ZNmFIUjBjRG92TDNkM2R5NWhMWFJ5DQpkWE4wTG1GMEwyTmxjblJ6TDJFdGMybG5iaTFqYjNKd2IzSmhkR1V0YkdsbmFIUXRNREpoTG1OeWREQW5CZ2dyDQpCZ0VGQlFjd0FZWWJhSFIwY0RvdkwyOWpjM0F1WVMxMGNuVnpkQzVoZEM5dlkzTndNRlFHQTFVZElBUk5NRXN3DQpTUVlHS2lnQUVRRVNNRDh3UFFZSUt3WUJCUVVIQWdFV01XaDBkSEE2THk5M2QzY3VZUzEwY25WemRDNWhkQzlrDQpiMk56TDJOd0wyRXRjMmxuYmkxQmJYUnpjMmxuYm1GMGRYSXdnWjRHQTFVZEh3U0JsakNCa3pDQmtLQ0JqYUNCDQppb2FCaDJ4a1lYQTZMeTlzWkdGd0xtRXRkSEoxYzNRdVlYUXZiM1U5WVMxemFXZHVMV052Y25CdmNtRjBaUzFzDQphV2RvZEMwd01peHZQVUV0VkhKMWMzUXNZejFCVkQ5alpYSjBhV1pwWTJGMFpYSmxkbTlqWVhScGIyNXNhWE4wDQpQMkpoYzJVL2IySnFaV04wWTJ4aGMzTTlaV2xrUTJWeWRHbG1hV05oZEdsdmJrRjFkR2h2Y21sMGVUQU5CZ2txDQpoa2lHOXcwQkFRVUZBQU9DQVFFQUhRM1pDTXRBYmF6ZU1IbVdBMnpoWWxIcUhnS1ZvY1ZYRURnbU5tV0xHcUZlDQo4RUFERklzOHVHcmt0Qm1XQ1VJWGJYczdUSGNmeHMySjQ3dkh1Y29wc2RrYWJObFhFanpuZFJmbmMrMVZJbmJvDQp6TXJZZDdqZUROVEsvdElqaU9FWWRyeUlwZWtWOUNmYXc3eXU2bWVmTXpldTFhQXdmN0JuSy9odWl3SlduZW5wDQpCN2lEL1B2WittenVDN1JOZkpmRisrU3RpQlR4aTNWWXhOR01qTTFjVThHdzlWV2MwUjNFdWpPYVhXZ0NDOGk1DQpGR2hWdk9ZaE5YZnN4SlhiTnhld0VDanBBTHZEbEZMTCtpQzQ5RytBRFNvUnYwU2s5MU9QdStjSW1DajNyczNRDQp0YXNJL3A5TFlhY0c2Yy9nSTN0RTBpaHFnOVJic0tIWFFsM1BPdkVSSkE9PTwvZHNpZzpYNTA5Q2VydGlmaWNhdGU+PC9kc2lnOlg1MDlEYXRhPjwvZHNpZzpLZXlJbmZvPgoJCTxkc2lnOk9iamVjdD4KCQkJPGRzaWc6TWFuaWZlc3QgSWQ9Im1hbmlmZXN0Ij4KCQkJCTxkc2lnOlJlZmVyZW5jZSBVUkk9IiI+CgkJCQkJPGRzaWc6VHJhbnNmb3Jtcz4KCQkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvVFIvMTk5OS9SRUMteHBhdGgtMTk5OTExMTYiPgoJCQkJCQkJPGRzaWc6WFBhdGg+bm90KGFuY2VzdG9yLW9yLXNlbGY6OmRzaWc6U2lnbmF0dXJlKTwvZHNpZzpYUGF0aD4KCQkJCQkJPC9kc2lnOlRyYW5zZm9ybT4KCQkJCQk8L2RzaWc6VHJhbnNmb3Jtcz4KCQkJCQk8ZHNpZzpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgLz4KCQkJCQk8ZHNpZzpEaWdlc3RWYWx1ZT5wM1pwS1BvK0ZYT3ZXdEhidFJzR2VLWm9lSTQ9PC9kc2lnOkRpZ2VzdFZhbHVlPgoJCQkJPC9kc2lnOlJlZmVyZW5jZT4KCQkJPC9kc2lnOk1hbmlmZXN0PgoJCTwvZHNpZzpPYmplY3Q+Cgk8L2RzaWc6U2lnbmF0dXJlPgo8L3NhbWw6QXNzZXJ0aW9uPg==", + "EID-CITIZEN-QAA-LEVEL": "substantial", + "EID-CCS-URL": "https://www.a-trust.at/todo", + "EID-AUTH-BLOCK": "https://www.a-trust.at/todohttps://demo.egiz.gv.at/demoportal_moaid-2.0/sl20/dataUrl?pendingid=862482318004000902Signatur der Anmeldedaten

Anmeldedaten:

Daten zur Person

Vorname:
Nachname:
Geburtsdatum:
Vollmacht: Ich melde mich in Vertretung an. Im nächsten Schritt wird mir eine Liste der für mich verfügbaren Vertretungsverhältnisse angezeigt, aus denen ich eines auswählen werde.

Daten zur Anwendung

Identifikator:
Name:
Staat:

Technische Parameter

Datum:..
Uhrzeit:::
TransaktionsTokken:
\n\t\t\t\t\t\t\t\t\t\t\tVollmachten-Referenz:
DataURL:
AuthBlockValidTo:
9YAYcxkIWv1Zzdhli5Mjk6Nz8ZJjVQTxU/u71fF5StA=
F7ye8qqVpognWOY8JAZVHk7X+AzH/5OStZWYSSbKgH4=
WVqZ8I9HaPIerCh1DIh6FnNQODSmWkxSecxTrcSL79ooWPYRB8DPbNoMT39rT+eRgYPjcAxjiNegbo0+lE51ZauWNr3jq2USaVY3nBpnmVDfBlnkFMdovaVVJPyegtGTYMMeN3+EQaZRSy13bvJS1U36bFUgv2i8KeXdftFzxeNheJqyXvrGzvmVuJV4dB8fOUm2VXgKepvelpRQZ+U6Jpyq1yVE9gz4frqVLetdUSGQhKJ0VRgYVVqa4FQ+YpyFgWwJQF/lOuUWli0jZ73HC7rIuVZ5Y0LEqaB+GUwthQk4qM3BsIfxPAxeh7a1Z915h0Ilzjkbk9kwt5Z2yZ8qXQ==MIIF1jCCBL6gAwIBAgIEfgS3/TANBgkqhkiG9w0BAQsFADCBoTELMAkGA1UEBgwCQVQxSDBGBgNVBAoMP0EtVHJ1c3QgR2VzLiBmLiBTaWNoZXJoZWl0c3N5c3RlbWUgaW0gZWxla3RyLiBEYXRlbnZlcmtlaHIgR21iSDEjMCEGA1UECwwaYS1zaWduLVByZW1pdW0tVGVzdC1TaWctMDIxIzAhBgNVBAMMGmEtc2lnbi1QcmVtaXVtLVRlc3QtU2lnLTAyMB4XDTE4MDUzMDA4MzIyOVoXDTIzMDUzMDA4MzIyOVowYDELMAkGA1UEBgwCQVQxFzAVBgNVBAMMDk1heCBNdXN0ZXJtYW5uMRMwEQYDVQQEDApNdXN0ZXJtYW5uMQwwCgYDVQQqDANNYXgxFTATBgNVBAUMDDUxNzY2MDcxODk5MzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALNGYXRmvAx9CJmzVO4uKreJhpwTwHi/fQhnX3QfB1VzQeYMMHi3GfVzEmAaD6hrVI84cyqLBQstyo5RxJM9Lf6z84TU3ZVdkOwBVxXjoe98Do+Oxj7zolO+6Qde2a2fMjZpiDNdkEPdUrQ2lRRPpBqjyHBHb23zsZ1PIXIpMl6nmsVVFs9ZlljbaMi9l56ZFOARVAbueYfSpF0wD66U5QC3/fw9SY31aDZo5aSmMcwqwCWvCc/Ef5evuEhO2sO7X55N2EMtaVH+X382Hcrzyn6lNEzBCf+4vZjQ6gX1KalwBI9LniaBJOD/4pHfUb51CJUhLu9Rt/rkyJyKWYu7z6MCAwEAAaOCAlQwggJQMIGDBggrBgEFBQcBAQR3MHUwRQYIKwYBBQUHMAKGOWh0dHA6Ly93d3cuYS10cnVzdC5hdC9jZXJ0cy9hLXNpZ24tcHJlbWl1bS1tb2JpbGUtMDNhLmNydDAsBggrBgEFBQcwAYYgaHR0cDovL29jc3AtdGVzdC5hLXRydXN0LmF0L29jc3AwEwYDVR0jBAwwCoAIRgafjkGOFb0wcgYIKwYBBQUHAQMEZjBkMAoGCCsGAQUFBwsCMAgGBgQAjkYBATAIBgYEAI5GAQQwEwYGBACORgEGMAkGBwQAjkYBBgEwLQYGBACORgEFMCMwIRYbaHR0cHM6Ly93d3cuYS10cnVzdC5hdC9wZHMvEwJFTjARBgNVHQ4ECgQIQWyS5dXk/tYwDgYDVR0PAQH/BAQDAgbAMAkGA1UdEwQCMAAwYAYDVR0gBFkwVzAIBgYEAIswAQEwSwYGKigAEQEUMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly93d3cuYS10cnVzdC5hdC9kb2NzL2NwL2Etc2lnbi1wcmVtaXVtLW1vYmlsZTCBrgYDVR0fBIGmMIGjMIGgoIGdoIGahoGXbGRhcDovL2xkYXAtdGVzdC5hLXRydXN0LmF0L291PWEtc2lnbi1QcmVtaXVtLVRlc3QtU2lnLTAyIChTSEEtMjU2KSxvPUEtVHJ1c3QsYz1BVD9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0P2Jhc2U/b2JqZWN0Y2xhc3M9ZWlkQ2VydGlmaWNhdGlvbkF1dGhvcml0eTANBgkqhkiG9w0BAQsFAAOCAQEAyEmgODt02xaxHb4E+O9XgImEC0AoH4Q97Pq7Bd4v+Pqqd6i5RodvwfTgIaW1J+fvH8KUTzI0XX9wpUWwImVEGMH63VAJcXVH0y9ifEWIHdhOLtRYVif0SQK9YRachvJDmF5hLwAQREeGsX2iNmP7dYe4xiNKAtQn0phvlPqgha6oKDGMQ8FNAfRz3kAtXJwPbFg6QE4kIhkTgd32uOiAJW7G2TaJZXWfK9TpV5LQ13+11FJ2S3KQc8ub/+1GdgirKSW4J1zhsfT+WCr/OayU2MzQXKv8OWb0SxWIJHiMTexH7r9muGk/ZLkaQQV2CtSOYqTAN8AweCiJ11uVFHeLpQ==2018-06-04T15:20:13Z6aTkha/Y9xYS4bQMZbwIX8TFsD2CezdhuqHpTtCI3f0=CN=a-sign-Premium-Test-Sig-02,OU=a-sign-Premium-Test-Sig-02,O=A-Trust Ges. f. Sicherheitssysteme im elektr. Datenverkehr GmbH,C=AT2114238461application/xhtml+xml
2.1MustermannMax1940-01-01labda - Developmenthttps://labda.iaik.tugraz.at:5553/demologin/AT
" + } + } +} \ No newline at end of file diff --git a/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_own_test.json b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_own_test.json new file mode 100644 index 000000000..a75535da1 --- /dev/null +++ b/id/server/modules/moa-id-module-sl20_authentication/src/test/resources/tests/eIDdata_own_test.json @@ -0,0 +1,8 @@ +{"result": + { + "EID-IDENTITY-LINK": "PHNhbWw6QXNzZXJ0aW9uIEFzc2VydGlvbklEPSJzenIuYm1pLmd2LmF0LUFzc2VydGlvbklEMTUyNzY2OTEwMDU5MTI3NDQiIElzc3VlSW5zdGFudD0iMjAxOC0wNS0zMFQxMDozMTo0MCswMTowMCIgSXNzdWVyPSJodHRwOi8vcG9ydGFsLmJtaS5ndi5hdC9yZWYvc3pyL2lzc3VlciIgTWFqb3JWZXJzaW9uPSIxIiBNaW5vclZlcnNpb249IjAiIHhtbG5zOnNhbWw9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjEuMDphc3NlcnRpb24iIHhtbG5zOnByPSJodHRwOi8vcmVmZXJlbmNlLmUtZ292ZXJubWVudC5ndi5hdC9uYW1lc3BhY2UvcGVyc29uZGF0YS8yMDAyMDIyOCMiIHhtbG5zOmRzaWc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIHhtbG5zOmVjZHNhPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSMiIHhtbG5zOnNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSI+Cgk8c2FtbDpBdHRyaWJ1dGVTdGF0ZW1lbnQ+CgkJPHNhbWw6U3ViamVjdD4KCQkJPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbj4KCQkJCTxzYW1sOkNvbmZpcm1hdGlvbk1ldGhvZD51cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoxLjA6Y206c2VuZGVyLXZvdWNoZXM8L3NhbWw6Q29uZmlybWF0aW9uTWV0aG9kPgoJCQkJPHNhbWw6U3ViamVjdENvbmZpcm1hdGlvbkRhdGE+CgkJCQkJPHByOlBlcnNvbiBzaTp0eXBlPSJwcjpQaHlzaWNhbFBlcnNvblR5cGUiPjxwcjpJZGVudGlmaWNhdGlvbj48cHI6VmFsdWU+dHFDUUVDNytBcUdFZWVMMzkwVjVKZz09PC9wcjpWYWx1ZT48cHI6VHlwZT51cm46cHVibGljaWQ6Z3YuYXQ6YmFzZWlkPC9wcjpUeXBlPjwvcHI6SWRlbnRpZmljYXRpb24+PHByOk5hbWU+PHByOkdpdmVuTmFtZT5NYXg8L3ByOkdpdmVuTmFtZT48cHI6RmFtaWx5TmFtZSBwcmltYXJ5PSJ1bmRlZmluZWQiPk11c3Rlcm1hbm48L3ByOkZhbWlseU5hbWU+PC9wcjpOYW1lPjxwcjpEYXRlT2ZCaXJ0aD4xOTQwLTAxLTAxPC9wcjpEYXRlT2ZCaXJ0aD48L3ByOlBlcnNvbj4KCQkJCTwvc2FtbDpTdWJqZWN0Q29uZmlybWF0aW9uRGF0YT4KCQkJPC9zYW1sOlN1YmplY3RDb25maXJtYXRpb24+CgkJPC9zYW1sOlN1YmplY3Q+Cgk8c2FtbDpBdHRyaWJ1dGUgQXR0cmlidXRlTmFtZT0iQ2l0aXplblB1YmxpY0tleSIgQXR0cmlidXRlTmFtZXNwYWNlPSJ1cm46cHVibGljaWQ6Z3YuYXQ6bmFtZXNwYWNlczppZGVudGl0eWxpbms6MS4yIj48c2FtbDpBdHRyaWJ1dGVWYWx1ZT48ZHNpZzpSU0FLZXlWYWx1ZT48ZHNpZzpNb2R1bHVzPnMwWmhkR2E4REgwSW1iTlU3aTRxdDRtR25CUEFlTDk5Q0dkZmRCOEhWWE5CNWd3d2VMY1o5WE1TWUJvUHFHdFVqemh6S29zRkN5M0sNCmpsSEVrejB0L3JQemhOVGRsVjJRN0FGWEZlT2g3M3dPajQ3R1B2T2lVNzdwQjE3WnJaOHlObW1JTTEyUVE5MVN0RGFWRkUra0dxUEkNCmNFZHZiZk94blU4aGNpa3lYcWVheFZVV3oxbVdXTnRveUwyWG5wa1U0QkZVQnU1NWg5S2tYVEFQcnBUbEFMZjkvRDFKamZWb05tamwNCnBLWXh6Q3JBSmE4Sno4Ui9sNis0U0U3YXc3dGZuazNZUXkxcFVmNWZmellkeXZQS2ZxVTBUTUVKLzdpOW1ORHFCZlVwcVhBRWowdWUNCkpvRWs0UC9pa2Q5UnZuVUlsU0V1NzFHMyt1VEluSXBaaTd2UG93PT08L2RzaWc6TW9kdWx1cz48ZHNpZzpFeHBvbmVudD5BUUFCPC9kc2lnOkV4cG9uZW50PjwvZHNpZzpSU0FLZXlWYWx1ZT48L3NhbWw6QXR0cmlidXRlVmFsdWU+PC9zYW1sOkF0dHJpYnV0ZT48L3NhbWw6QXR0cmlidXRlU3RhdGVtZW50PgoJPGRzaWc6U2lnbmF0dXJlPgoJCTxkc2lnOlNpZ25lZEluZm8+CgkJCTxkc2lnOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzEwL3htbC1leGMtYzE0biMiIC8+CgkJCTxkc2lnOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNyc2Etc2hhMSIgLz4KCQkJPGRzaWc6UmVmZXJlbmNlIFVSST0iIj4KCQkJCTxkc2lnOlRyYW5zZm9ybXM+CgkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvVFIvMTk5OS9SRUMteHBhdGgtMTk5OTExMTYiPgoJCQkJCQk8ZHNpZzpYUGF0aD5ub3QoYW5jZXN0b3Itb3Itc2VsZjo6cHI6SWRlbnRpZmljYXRpb24pPC9kc2lnOlhQYXRoPgoJCQkJCTwvZHNpZzpUcmFuc2Zvcm0+CgkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI2VudmVsb3BlZC1zaWduYXR1cmUiIC8+CgkJCQk8L2RzaWc6VHJhbnNmb3Jtcz4KCQkJCTxkc2lnOkRpZ2VzdE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNzaGExIiAvPgoJCQkJPGRzaWc6RGlnZXN0VmFsdWU+QmVIdUFyYXUzSFVQcXg5dHV3QTRGaDNOSDB3PTwvZHNpZzpEaWdlc3RWYWx1ZT4KCQkJPC9kc2lnOlJlZmVyZW5jZT4KCQkJPGRzaWc6UmVmZXJlbmNlIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyNNYW5pZmVzdCIgVVJJPSIjbWFuaWZlc3QiPgoJCQkJPGRzaWc6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiIC8+CgkJCQk8ZHNpZzpEaWdlc3RWYWx1ZT5mVEUrMjRnRHlkUlgvd0p2QlAxOUlucU54Rkk9PC9kc2lnOkRpZ2VzdFZhbHVlPgoJCQk8L2RzaWc6UmVmZXJlbmNlPgoJCTwvZHNpZzpTaWduZWRJbmZvPgoJCTxkc2lnOlNpZ25hdHVyZVZhbHVlPgogICAgUHpLMWR2N2JFMGhQcGxlc1ZaRFhHSWxhbTlUK0JxWkd4ZWs5RHVuYkhNK21GWWI3a1NaZTN2eEszUmhRZjNBV3djbXFtVWZPRlJObg0KWndxYnovNGRZd2hJRld6VGdMelVmMlZkR0JsN2szbS8wSmJXSkV1bEtobE5vV2ZSTkRrdTRZcmI2THVrWjdaQzJFcWd2UXYxa1BRTg0Kb1BvQ1I5d3hUc1RKWFNCaHdLc0lERG9vZHY3aUVpWGFCM0xmVHQrQWdYdEdvbWRRaktjby9WamJSSzRUUEkvQUVNVU1KWm9zZlJYMg0KdmE2U1BaUnV4QjBlWkwwVGVzYittRjlFaUlOVnNTSU9nbTVSRE95V1ZRZkJnVG9nYjNoWmlLVmh0a1IvaWlSNmhZNlA2b1cwTDh4ag0KMG5ZVldPRHAxSlJML3Z0ZDFhUklVYzNCQTJQaFkrRmdJR1FHTUE9PQogIDwvZHNpZzpTaWduYXR1cmVWYWx1ZT48ZHNpZzpLZXlJbmZvPjxkc2lnOlg1MDlEYXRhPjxkc2lnOlg1MDlDZXJ0aWZpY2F0ZT5NSUlGdXpDQ0JLT2dBd0lCQWdJREdTa2VNQTBHQ1NxR1NJYjNEUUVCQlFVQU1JR2ZNUXN3Q1FZRFZRUUdFd0pCDQpWREZJTUVZR0ExVUVDZ3cvUVMxVWNuVnpkQ0JIWlhNdUlHWXVJRk5wWTJobGNtaGxhWFJ6YzNsemRHVnRaU0JwDQpiU0JsYkdWcmRISXVJRVJoZEdWdWRtVnlhMlZvY2lCSGJXSklNU0l3SUFZRFZRUUxEQmxoTFhOcFoyNHRZMjl5DQpjRzl5WVhSbExXeHBaMmgwTFRBeU1TSXdJQVlEVlFRRERCbGhMWE5wWjI0dFkyOXljRzl5WVhSbExXeHBaMmgwDQpMVEF5TUI0WERURTFNRGN5T0RFMU5Ea3dOVm9YRFRJd01EY3lPREV6TkRrd05Wb3dnYll4Q3pBSkJnTlZCQVlUDQpBa0ZVTVI0d0hBWURWUVFLREJWRVlYUmxibk5qYUhWMGVtdHZiVzFwYzNOcGIyNHhJakFnQmdOVkJBc01HVk4wDQpZVzF0ZW1Gb2JISmxaMmx6ZEdWeVltVm9iMlZ5WkdVeExqQXNCZ05WQkFNTUpWTnBaMjVoZEhWeWMyVnlkbWxqDQpaU0JFWVhSbGJuTmphSFYwZW10dmJXMXBjM05wYjI0eEZUQVRCZ05WQkFVVERETXlOVGt5T0RNeU16azVPREVjDQpNQm9HQ1NxR1NJYjNEUUVKQVF3TlpITnJRR1J6YXk1bmRpNWhkRENDQVNJd0RRWUpLb1pJaHZjTkFRRUJCUUFEDQpnZ0VQQURDQ0FRb0NnZ0VCQU4rZEJTRUJHajJqVVhJSzFNcDNsVnhjL1phK3BKTWl5S3JYM0cxWnhnWC9pa3g3DQpEOXNjc1BZTXQ0NzNMbEFXbDljbUNiSGJKSytQVjJYTk5kVVJMTVVDSVgrNHZVTnMyTUhlRFRRdFg4QlhqSkZwDQp3SllTb2FSSlEzOUZWUy8xcjVzV2NyYTlIaGRtN3c1R3R4LzJ1a3lEWDBrZGt4YXdraFA0RVFFemkvU0krRnVnDQpuK1dxZ1ExbkFkbGJ4Yi9kY0J3NXcxaDliM2xtdXdVZjR6M29vUVdVRDJEZ0Eva0tkMUtlak5SNDNtTFVzbXZTDQp6ZXZQeFQ5enM3OHBPUjFPYWNCN0lzelRWSlBYZU9FYWFOWkhubkIvVWVPM2c4TEVWLzNPa1hjVWdjTWtiSUlpDQphQkhsbGw3MVBxMENPajlrcWpYb2U3T3JSakxZNWkzS3dPcGE2VE1DQXdFQUFhT0NBZVV3Z2dIaE1CRUdBMVVkDQpEZ1FLQkFoTUNBNmVHdlMxdWpBT0JnTlZIUThCQWY4RUJBTUNCTEF3RGdZSEtpZ0FDZ0VIQVFRREFRSC9NQk1HDQpBMVVkSXdRTU1BcUFDRWtjV0RwUDZBMERNQWtHQTFVZEV3UUNNQUF3RkFZSEtpZ0FDZ0VCQVFRSkRBZENVMEl0DQpSRk5MTUg4R0NDc0dBUVVGQndFQkJITXdjVEJHQmdnckJnRUZCUWN3QW9ZNmFIUjBjRG92TDNkM2R5NWhMWFJ5DQpkWE4wTG1GMEwyTmxjblJ6TDJFdGMybG5iaTFqYjNKd2IzSmhkR1V0YkdsbmFIUXRNREpoTG1OeWREQW5CZ2dyDQpCZ0VGQlFjd0FZWWJhSFIwY0RvdkwyOWpjM0F1WVMxMGNuVnpkQzVoZEM5dlkzTndNRlFHQTFVZElBUk5NRXN3DQpTUVlHS2lnQUVRRVNNRDh3UFFZSUt3WUJCUVVIQWdFV01XaDBkSEE2THk5M2QzY3VZUzEwY25WemRDNWhkQzlrDQpiMk56TDJOd0wyRXRjMmxuYmkxQmJYUnpjMmxuYm1GMGRYSXdnWjRHQTFVZEh3U0JsakNCa3pDQmtLQ0JqYUNCDQppb2FCaDJ4a1lYQTZMeTlzWkdGd0xtRXRkSEoxYzNRdVlYUXZiM1U5WVMxemFXZHVMV052Y25CdmNtRjBaUzFzDQphV2RvZEMwd01peHZQVUV0VkhKMWMzUXNZejFCVkQ5alpYSjBhV1pwWTJGMFpYSmxkbTlqWVhScGIyNXNhWE4wDQpQMkpoYzJVL2IySnFaV04wWTJ4aGMzTTlaV2xrUTJWeWRHbG1hV05oZEdsdmJrRjFkR2h2Y21sMGVUQU5CZ2txDQpoa2lHOXcwQkFRVUZBQU9DQVFFQUhRM1pDTXRBYmF6ZU1IbVdBMnpoWWxIcUhnS1ZvY1ZYRURnbU5tV0xHcUZlDQo4RUFERklzOHVHcmt0Qm1XQ1VJWGJYczdUSGNmeHMySjQ3dkh1Y29wc2RrYWJObFhFanpuZFJmbmMrMVZJbmJvDQp6TXJZZDdqZUROVEsvdElqaU9FWWRyeUlwZWtWOUNmYXc3eXU2bWVmTXpldTFhQXdmN0JuSy9odWl3SlduZW5wDQpCN2lEL1B2WittenVDN1JOZkpmRisrU3RpQlR4aTNWWXhOR01qTTFjVThHdzlWV2MwUjNFdWpPYVhXZ0NDOGk1DQpGR2hWdk9ZaE5YZnN4SlhiTnhld0VDanBBTHZEbEZMTCtpQzQ5RytBRFNvUnYwU2s5MU9QdStjSW1DajNyczNRDQp0YXNJL3A5TFlhY0c2Yy9nSTN0RTBpaHFnOVJic0tIWFFsM1BPdkVSSkE9PTwvZHNpZzpYNTA5Q2VydGlmaWNhdGU+PC9kc2lnOlg1MDlEYXRhPjwvZHNpZzpLZXlJbmZvPgoJCTxkc2lnOk9iamVjdD4KCQkJPGRzaWc6TWFuaWZlc3QgSWQ9Im1hbmlmZXN0Ij4KCQkJCTxkc2lnOlJlZmVyZW5jZSBVUkk9IiI+CgkJCQkJPGRzaWc6VHJhbnNmb3Jtcz4KCQkJCQkJPGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvVFIvMTk5OS9SRUMteHBhdGgtMTk5OTExMTYiPgoJCQkJCQkJPGRzaWc6WFBhdGg+bm90KGFuY2VzdG9yLW9yLXNlbGY6OmRzaWc6U2lnbmF0dXJlKTwvZHNpZzpYUGF0aD4KCQkJCQkJPC9kc2lnOlRyYW5zZm9ybT4KCQkJCQk8L2RzaWc6VHJhbnNmb3Jtcz4KCQkJCQk8ZHNpZzpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIgLz4KCQkJCQk8ZHNpZzpEaWdlc3RWYWx1ZT5wM1pwS1BvK0ZYT3ZXdEhidFJzR2VLWm9lSTQ9PC9kc2lnOkRpZ2VzdFZhbHVlPgoJCQkJPC9kc2lnOlJlZmVyZW5jZT4KCQkJPC9kc2lnOk1hbmlmZXN0PgoJCTwvZHNpZzpPYmplY3Q+Cgk8L2RzaWc6U2lnbmF0dXJlPgo8L3NhbWw6QXNzZXJ0aW9uPg==", + "EID-CITIZEN-QAA-LEVEL": "substantial", + "EID-CCS-URL": "https://www.a-trust.at/todo", + "EID-AUTH-BLOCK": "PHNhbWwyOkFzc2VydGlvbiB4bWxuczpzYW1sMj0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOmFzc2VydGlvbiIgSUQ9Il81NzAxMGI3ZmNjOTNjYzRjZjNmMmI3NjQzODkxMzdjMiIgSXNzdWVJbnN0YW50PSIyMDE2LTAzLTI5VDA4OjUwOjU2LjQ1MFoiIFZlcnNpb249IjIuMCIgeG1sbnM6eHM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hIj4NCgk8c2FtbDI6SXNzdWVyIEZvcm1hdD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4wOm5hbWVpZC1mb3JtYXQ6ZW50aXR5Ij5odHRwczovL2RlbW8tdmRhLmF0L3ZkYS1zZXJ2aWNlPC9zYW1sMjpJc3N1ZXI+PGRzaWc6U2lnbmF0dXJlIHhtbG5zOmRzaWc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvMDkveG1sZHNpZyMiIElkPSJzaWduYXR1cmUtMS0xIj48ZHNpZzpTaWduZWRJbmZvPjxkc2lnOkNhbm9uaWNhbGl6YXRpb25NZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy14bWwtYzE0bi0yMDAxMDMxNSIvPjxkc2lnOlNpZ25hdHVyZU1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZHNpZy1tb3JlI2VjZHNhLXNoYTI1NiIvPjxkc2lnOlJlZmVyZW5jZSBJZD0icmVmZXJlbmNlLTEtMSIgVVJJPSIiPjxkc2lnOlRyYW5zZm9ybXM+PGRzaWc6VHJhbnNmb3JtIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvVFIvMTk5OS9SRUMteHNsdC0xOTk5MTExNiI+PHhzbDpzdHlsZXNoZWV0IHhtbG5zOnhzbD0iaHR0cDovL3d3dy53My5vcmcvMTk5OS9YU0wvVHJhbnNmb3JtIiBleGNsdWRlLXJlc3VsdC1wcmVmaXhlcz0ic2FtbDIiIHZlcnNpb249IjEuMCIgeG1sbnM6c2FtbDI9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphc3NlcnRpb24iPjx4c2w6b3V0cHV0IG1ldGhvZD0ieG1sIiB4bWw6c3BhY2U9ImRlZmF1bHQiLz48eHNsOnRlbXBsYXRlIG1hdGNoPSIvIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCI+PGh0bWwgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwiPjxoZWFkPjx0aXRsZT5TaWduYXR1ciBkZXIgQW5tZWxkZWRhdGVuPC90aXRsZT48c3R5bGUgbWVkaWE9InNjcmVlbiIgdHlwZT0idGV4dC9jc3MiPg0KICAgICAgICAgICAgICAJCQkJCS5ub3JtYWxzdHlsZSB7IGZvbnQtc2l6ZTogbWVkaXVtOyB9IA0KICAgICAgICAgICAgICAJCQkJCS5pdGFsaWNzdHlsZSB7IGZvbnQtc2l6ZTogbWVkaXVtOyBmb250LXN0eWxlOiBpdGFsaWM7IH0NCgkJCQkJCQkJLnRpdGxlc3R5bGUgeyB0ZXh0LWRlY29yYXRpb246dW5kZXJsaW5lOyBmb250LXdlaWdodDpib2xkOyBmb250LXNpemU6IG1lZGl1bTsgfSANCgkJCQkJCQkJLmg0c3R5bGUgeyBmb250LXNpemU6IGxhcmdlOyB9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICANCgkJCQkJCQkJLmhpZGRlbiB7ZGlzcGxheTogbm9uZTsgfSANCiAgICAgICAgICAgICAgCQkJCTwvc3R5bGU+PC9oZWFkPjxib2R5PjxoNCBjbGFzcz0iaDRzdHlsZSI+QW5tZWxkZWRhdGVuOjwvaDQ+PHAgY2xhc3M9InRpdGxlc3R5bGUiPkRhdGVuIHp1ciBQZXJzb248L3A+PHRhYmxlIGNsYXNzPSJwYXJhbWV0ZXJzIj48eHNsOmlmIHRlc3Q9InN0cmluZygvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudC9zYW1sMjpBdHRyaWJ1dGVbQE5hbWU9J3VybjpvaWQ6Mi41LjQuNDInXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSkiPjx0cj48dGQgY2xhc3M9Iml0YWxpY3N0eWxlIj5Wb3JuYW1lOiA8L3RkPjx0ZCBjbGFzcz0ibm9ybWFsc3R5bGUiPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSIvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudC9zYW1sMjpBdHRyaWJ1dGVbQE5hbWU9J3VybjpvaWQ6Mi41LjQuNDInXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSIvPjwvdGQ+PC90cj48L3hzbDppZj48eHNsOmlmIHRlc3Q9InN0cmluZygvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudC9zYW1sMjpBdHRyaWJ1dGVbQE5hbWU9J3VybjpvaWQ6MS4yLjQwLjAuMTAuMi4xLjEuMjYxLjIwJ10vc2FtbDI6QXR0cmlidXRlVmFsdWUpIj48dHI+PHRkIGNsYXNzPSJpdGFsaWNzdHlsZSI+TmFjaG5hbWU6IDwvdGQ+PHRkIGNsYXNzPSJub3JtYWxzdHlsZSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0ndXJuOm9pZDoxLjIuNDAuMC4xMC4yLjEuMS4yNjEuMjAnXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSIvPjwvdGQ+PC90cj48L3hzbDppZj48eHNsOmlmIHRlc3Q9InN0cmluZygvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudC9zYW1sMjpBdHRyaWJ1dGVbQE5hbWU9J3VybjpvaWQ6MS4yLjQwLjAuMTAuMi4xLjEuNTUnXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSkiPjx0cj48dGQgY2xhc3M9Iml0YWxpY3N0eWxlIj5HZWJ1cnRzZGF0dW06IDwvdGQ+PHRkIGNsYXNzPSJub3JtYWxzdHlsZSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0ndXJuOm9pZDoxLjIuNDAuMC4xMC4yLjEuMS41NSddL3NhbWwyOkF0dHJpYnV0ZVZhbHVlIi8+PC90ZD48L3RyPjwveHNsOmlmPjx4c2w6aWYgdGVzdD0iL3NhbWwyOkFzc2VydGlvbi9zYW1sMjpBdHRyaWJ1dGVTdGF0ZW1lbnQvc2FtbDI6QXR0cmlidXRlW0BOYW1lPSd1cm46b2lkOjEuMi40MC4wLjEwLjIuMS4xLjI2MS45MCddL3NhbWwyOkF0dHJpYnV0ZVZhbHVlIj48dHI+PHRkIGNsYXNzPSJpdGFsaWNzdHlsZSI+Vm9sbG1hY2h0OiA8L3RkPjx0ZCBjbGFzcz0ibm9ybWFsc3R5bGUiPjx4c2w6dGV4dD5JY2ggbWVsZGUgbWljaCBpbiBWZXJ0cmV0dW5nIGFuLiBJbSBuw6RjaHN0ZW4gU2Nocml0dCB3aXJkIG1pciBlaW5lIExpc3RlIGRlciBmw7xyIG1pY2ggdmVyZsO8Z2JhcmVuIFZlcnRyZXR1bmdzdmVyaMOkbHRuaXNzZSBhbmdlemVpZ3QsIGF1cyBkZW5lbiBpY2ggZWluZXMgYXVzd8OkaGxlbiB3ZXJkZS48L3hzbDp0ZXh0PjwvdGQ+PC90cj48L3hzbDppZj48L3RhYmxlPjxwIGNsYXNzPSJ0aXRsZXN0eWxlIj5EYXRlbiB6dXIgQW53ZW5kdW5nPC9wPjx0YWJsZSBjbGFzcz0icGFyYW1ldGVycyI+PHRyPjx0ZCBjbGFzcz0iaXRhbGljc3R5bGUiPklkZW50aWZpa2F0b3I6IDwvdGQ+PHRkIGNsYXNzPSJub3JtYWxzdHlsZSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0naHR0cDovL2VpZC5ndi5hdC9lSUQvYXR0cmlidXRlcy9TZXJ2aWNlUHJvdmlkZXJVbmlxdWVJZCddL3NhbWwyOkF0dHJpYnV0ZVZhbHVlIi8+PC90ZD48L3RyPjx4c2w6aWYgdGVzdD0ic3RyaW5nKC9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0naHR0cDovL2VpZC5ndi5hdC9lSUQvYXR0cmlidXRlcy9TZXJ2aWNlUHJvdmlkZXJGcmllbmRseU5hbWUnXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSkiPjx0cj48dGQgY2xhc3M9Iml0YWxpY3N0eWxlIj5OYW1lOiA8L3RkPjx0ZCBjbGFzcz0ibm9ybWFsc3R5bGUiPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSIvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkF0dHJpYnV0ZVN0YXRlbWVudC9zYW1sMjpBdHRyaWJ1dGVbQE5hbWU9J2h0dHA6Ly9laWQuZ3YuYXQvZUlEL2F0dHJpYnV0ZXMvU2VydmljZVByb3ZpZGVyRnJpZW5kbHlOYW1lJ10vc2FtbDI6QXR0cmlidXRlVmFsdWUiLz48L3RkPjwvdHI+PC94c2w6aWY+PHhzbDppZiB0ZXN0PSJzdHJpbmcoL3NhbWwyOkFzc2VydGlvbi9zYW1sMjpBdHRyaWJ1dGVTdGF0ZW1lbnQvc2FtbDI6QXR0cmlidXRlW0BOYW1lPSdodHRwOi8vZWlkLmd2LmF0L2VJRC9hdHRyaWJ1dGVzL1NlcnZpY2VQcm92aWRlckNvdW50cnlDb2RlJ10vc2FtbDI6QXR0cmlidXRlVmFsdWUpIj48dHI+PHRkIGNsYXNzPSJpdGFsaWNzdHlsZSI+U3RhYXQ6IDwvdGQ+PHRkIGNsYXNzPSJub3JtYWxzdHlsZSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0naHR0cDovL2VpZC5ndi5hdC9lSUQvYXR0cmlidXRlcy9TZXJ2aWNlUHJvdmlkZXJDb3VudHJ5Q29kZSddL3NhbWwyOkF0dHJpYnV0ZVZhbHVlIi8+PC90ZD48L3RyPjwveHNsOmlmPjwvdGFibGU+PHAgY2xhc3M9InRpdGxlc3R5bGUiPlRlY2huaXNjaGUgUGFyYW1ldGVyPC9wPjx0YWJsZSBjbGFzcz0icGFyYW1ldGVycyI+PHRyPjx0ZCBjbGFzcz0iaXRhbGljc3R5bGUiPkRhdHVtOjwvdGQ+PHRkIGNsYXNzPSJub3JtYWxzdHlsZSI+PHhzbDp2YWx1ZS1vZiBzZWxlY3Q9InN1YnN0cmluZygvc2FtbDI6QXNzZXJ0aW9uL0BJc3N1ZUluc3RhbnQsOSwyKSIvPjx4c2w6dGV4dD4uPC94c2w6dGV4dD48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic3Vic3RyaW5nKC9zYW1sMjpBc3NlcnRpb24vQElzc3VlSW5zdGFudCw2LDIpIi8+PHhzbDp0ZXh0Pi48L3hzbDp0ZXh0Pjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSJzdWJzdHJpbmcoL3NhbWwyOkFzc2VydGlvbi9ASXNzdWVJbnN0YW50LDEsNCkiLz48L3RkPjwvdHI+PHRyPjx0ZCBjbGFzcz0iaXRhbGljc3R5bGUiPlVocnplaXQ6PC90ZD48dGQgY2xhc3M9Im5vcm1hbHN0eWxlIj48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic3Vic3RyaW5nKC9zYW1sMjpBc3NlcnRpb24vQElzc3VlSW5zdGFudCwxMiwyKSIvPjx4c2w6dGV4dD46PC94c2w6dGV4dD48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic3Vic3RyaW5nKC9zYW1sMjpBc3NlcnRpb24vQElzc3VlSW5zdGFudCwxNSwyKSIvPjx4c2w6dGV4dD46PC94c2w6dGV4dD48eHNsOnZhbHVlLW9mIHNlbGVjdD0ic3Vic3RyaW5nKC9zYW1sMjpBc3NlcnRpb24vQElzc3VlSW5zdGFudCwxOCwyKSIvPjwvdGQ+PC90cj48dHI+PHRkIGNsYXNzPSJpdGFsaWNzdHlsZSI+VHJhbnNha3Rpb25zVG9ra2VuOiA8L3RkPjx0ZCBjbGFzcz0ibm9ybWFsc3R5bGUiPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSIvc2FtbDI6QXNzZXJ0aW9uL0BJRCIvPjwvdGQ+PC90cj48eHNsOmlmIHRlc3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50L3NhbWwyOkF0dHJpYnV0ZVtATmFtZT0ndXJuOm9pZDoxLjIuNDAuMC4xMC4yLjEuMS4yNjEuOTAnXS9zYW1sMjpBdHRyaWJ1dGVWYWx1ZSI+PHRyPjx0ZCBjbGFzcz0iaXRhbGljc3R5bGUiPg0KCQkJCQkJCQkJCQlWb2xsbWFjaHRlbi1SZWZlcmVuejogPC90ZD48dGQgY2xhc3M9Im5vcm1hbHN0eWxlIj48eHNsOnZhbHVlLW9mIHNlbGVjdD0iL3NhbWwyOkFzc2VydGlvbi9zYW1sMjpBdHRyaWJ1dGVTdGF0ZW1lbnQvc2FtbDI6QXR0cmlidXRlW0BOYW1lPSd1cm46b2lkOjEuMi40MC4wLjEwLjIuMS4xLjI2MS45MCddL3NhbWwyOkF0dHJpYnV0ZVZhbHVlIi8+PC90ZD48L3RyPjwveHNsOmlmPjx0ciBjbGFzcz0iaGlkZGVuIj48dGQgY2xhc3M9Iml0YWxpY3N0eWxlIj5EYXRhVVJMOiA8L3RkPjx0ZCBjbGFzcz0ibm9ybWFsc3R5bGUiPjx4c2w6dmFsdWUtb2Ygc2VsZWN0PSIvc2FtbDI6QXNzZXJ0aW9uL3NhbWwyOkNvbmRpdGlvbnMvc2FtbDI6QXVkaWVuY2VSZXN0cmljdGlvbi9zYW1sMjpBdWRpZW5jZSIvPjwvdGQ+PC90cj48eHNsOmlmIHRlc3Q9Ii9zYW1sMjpBc3NlcnRpb24vc2FtbDI6Q29uZGl0aW9ucy9ATm90T25PckFmdGVyIj48dHIgY2xhc3M9ImhpZGRlbiI+PHRkIGNsYXNzPSJpdGFsaWNzdHlsZSI+QXV0aEJsb2NrVmFsaWRUbzogPC90ZD48dGQgY2xhc3M9Im5vcm1hbHN0eWxlIj48eHNsOnZhbHVlLW9mIHNlbGVjdD0iL3NhbWwyOkFzc2VydGlvbi9zYW1sMjpDb25kaXRpb25zL0BOb3RPbk9yQWZ0ZXIiLz48L3RkPjwvdHI+PC94c2w6aWY+PC90YWJsZT48L2JvZHk+PC9odG1sPjwveHNsOnRlbXBsYXRlPjwveHNsOnN0eWxlc2hlZXQ+PC9kc2lnOlRyYW5zZm9ybT48ZHNpZzpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy9UUi8yMDAxL1JFQy14bWwtYzE0bi0yMDAxMDMxNSNXaXRoQ29tbWVudHMiLz48L2RzaWc6VHJhbnNmb3Jtcz48ZHNpZzpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHNpZzpEaWdlc3RWYWx1ZT5tY0xFdXNpMmMySFZsZWJXZWJnK1VUVVVCVDRHSUxIVDdhN1ZGaDFNZ1YwPTwvZHNpZzpEaWdlc3RWYWx1ZT48L2RzaWc6UmVmZXJlbmNlPjxkc2lnOlJlZmVyZW5jZSBJZD0iZXRzaS1kYXRhLXJlZmVyZW5jZS0xLTEiIFR5cGU9Imh0dHA6Ly91cmkuZXRzaS5vcmcvMDE5MDMvdjEuMS4xI1NpZ25lZFByb3BlcnRpZXMiIFVSST0iIj48ZHNpZzpUcmFuc2Zvcm1zPjxkc2lnOlRyYW5zZm9ybSBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDIvMDYveG1sZHNpZy1maWx0ZXIyIj48eHBmOlhQYXRoIHhtbG5zOnhwZj0iaHR0cDovL3d3dy53My5vcmcvMjAwMi8wNi94bWxkc2lnLWZpbHRlcjIiIEZpbHRlcj0iaW50ZXJzZWN0IiB4bWxuczpldHNpPSJodHRwOi8vdXJpLmV0c2kub3JnLzAxOTAzL3YxLjEuMSMiPi8vKltASWQ9J2V0c2ktc2lnbmVkLTEtMSddL2V0c2k6UXVhbGlmeWluZ1Byb3BlcnRpZXMvZXRzaTpTaWduZWRQcm9wZXJ0aWVzPC94cGY6WFBhdGg+PC9kc2lnOlRyYW5zZm9ybT48L2RzaWc6VHJhbnNmb3Jtcz48ZHNpZzpEaWdlc3RNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxLzA0L3htbGVuYyNzaGEyNTYiLz48ZHNpZzpEaWdlc3RWYWx1ZT5xMWdMWm9lTDZLOVZaZHkzM3lPdVRFaTJGVDFTaDBqRDJSZGMzRXJ0WmNvPTwvZHNpZzpEaWdlc3RWYWx1ZT48L2RzaWc6UmVmZXJlbmNlPjwvZHNpZzpTaWduZWRJbmZvPjxkc2lnOlNpZ25hdHVyZVZhbHVlPmpjV2YrejljckIvVU1COTVPR2ZlMys5U2pESXRrMUZWSGRFZWNGSnhnbVJndWRjMWxmc1V2Z21BTzhxYlBHcGpEMDJhMi9pNmowTlJFR1l4dU5aVGtBPT08L2RzaWc6U2lnbmF0dXJlVmFsdWU+PGRzaWc6S2V5SW5mbz48ZHNpZzpYNTA5RGF0YT48ZHNpZzpYNTA5Q2VydGlmaWNhdGU+TUlJRm1qQ0NBNEtnQXdJQkFnSUVPTkd1bWpBTkJna3Foa2lHOXcwQkFRc0ZBRENCblRFTE1Ba0dBMVVFQmhNQ1FWUXhTREJHQmdOVkJBb01QMEV0VkhKMWMzUWdSMlZ6TGlCbUxpQlRhV05vWlhKb1pXbDBjM041YzNSbGJXVWdhVzBnWld4bGEzUnlMaUJFWVhSbGJuWmxjbXRsYUhJZ1IyMWlTREVoTUI4R0ExVUVDd3dZWVMxemFXZHVMWEJ5WlcxcGRXMHRiVzlpYVd4bExUQTFNU0V3SHdZRFZRUUREQmhoTFhOcFoyNHRjSEpsYldsMWJTMXRiMkpwYkdVdE1EVXdIaGNOTVRnd05ERXlNRFl4T0RVd1doY05Nak13TkRFeU1EWXhPRFV3V2pCbU1Rc3dDUVlEVlFRR0V3SkJWREVhTUJnR0ExVUVBd3dSVkdodmJXRnpJRWRsYjNKbklFeGxibm94RFRBTEJnTlZCQVFNQkV4bGJub3hGVEFUQmdOVkJDb01ERlJvYjIxaGN5QkhaVzl5WnpFVk1CTUdBMVVFQlJNTU9ESXdNVGd3TnpjM01qZzNNRmt3RXdZSEtvWkl6ajBDQVFZSUtvWkl6ajBEQVFjRFFnQUVmMmFZaTM5UlRPd3VHbHZqbWwwNms0eEdnSUZIOU8rajUrdms0bDdjbzVYRVNkYUYvK1FFQmJpcUIxQjlIcGZFOVJIZjdiYkc2WjdlZjh4VXhkdjMzYU9DQWVFd2dnSGRNSDBHQ0NzR0FRVUZCd0VCQkhFd2J6QkVCZ2dyQmdFRkJRY3dBb1k0YUhSMGNEb3ZMM2QzZHk1aExYUnlkWE4wTG1GMEwyTmxjblJ6TDJFdGMybG5iaTF3Y21WdGFYVnRMVzF2WW1sc1pTMHdOUzVqY25Rd0p3WUlLd1lCQlFVSE1BR0dHMmgwZEhBNkx5OXZZM053TG1FdGRISjFjM1F1WVhRdmIyTnpjREFUQmdOVkhTTUVEREFLZ0FoSTgvMmNJdzZIZHpCeUJnZ3JCZ0VGQlFjQkF3Um1NR1F3Q2dZSUt3WUJCUVVIQ3dJd0NBWUdCQUNPUmdFQk1BZ0dCZ1FBamtZQkJEQVRCZ1lFQUk1R0FRWXdDUVlIQkFDT1JnRUdBVEF0QmdZRUFJNUdBUVV3SXpBaEZodG9kSFJ3Y3pvdkwzZDNkeTVoTFhSeWRYTjBMbUYwTDNCa2N5OFRBa1ZPTUJFR0ExVWREZ1FLQkFoS1F2Z2VFZTdPaURBT0JnTlZIUThCQWY4RUJBTUNCc0F3Q1FZRFZSMFRCQUl3QURCZ0JnTlZIU0FFV1RCWE1BZ0dCZ1FBaXpBQkFUQkxCZ1lxS0FBUkFSUXdRVEEvQmdnckJnRUZCUWNDQVJZemFIUjBjRG92TDNkM2R5NWhMWFJ5ZFhOMExtRjBMMlJ2WTNNdlkzQXZZUzF6YVdkdUxYQnlaVzFwZFcwdGJXOWlhV3hsTUVNR0ExVWRId1E4TURvd09LQTJvRFNHTW1oMGRIQTZMeTlqY213dVlTMTBjblZ6ZEM1aGRDOWpjbXd2WVMxemFXZHVMWEJ5WlcxcGRXMHRiVzlpYVd4bExUQTFNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUNBUUFyL1Z0T3hVaU5aTVVjeHJISG9yM0FYWnlqcVVmdTRWTTFkbkt3Zjl1d1hRa3NVcnF2b1Jzc3AyakhDbnpIM2FaV2plQ3U5UFVDSmV3NXgxUnBNeEUwaFZZanEzNzVrdjM4d1ZXUjM4WmE3eVl5ME45cTBVbjBOSmlTUHpuaklUa3RweWZkcHNGSkluTDIrM1h5Z2FZZU51dGU5NjA0WTMwK3JGSCtKck85UjgzWmFwbTZjdGs4ai8xSHBxb0c0NXlJbTZtS3AvWGhndGJnVk13OHptUjBQWGpBaW5FaTYrUmEzL1Z0cUV4ZVlHaUt5WS9SdWU1TWZQRGhiMmRBQjByd1ozVWtRakU0TWFyMFRDVzR0cHZKR0hiakhuQkwyMVY4SVNMZkUxb1NYcGJZWVNqTFh4TENmcmJrZUdSbkhTUTVENUUwU1ZqTzdsU3NQazFtaVErcExGR1FTNTZKS3VFWTBoVzRKYzlkUGRRc29Qc2FEVCtQZW1WQXIzcVZGTEQ1QSt0cm5GMFpqQ3A2RHVhYVdnT0hQajFweE05V0tVRFpXa1hUQWdDZVZhN3RLMlFjMlZWUUUvc3ZGS1I1OWlGTWlSdGpZQXpjTS9OZ215bE9DYUc1a01UZmlXOWhnbGo5QjNSdVVackZHWFNhY0ptcGM4ZWppRTl4a3B5UTVadDlpK3FDVE40ajdIOWdpRHMydkNnMDFwYnp3b0txc05zWGlFc2JzM3NVeTVTUFYyRzg4a055Vm9DTkVKVVZka0ZBZXBqQkcwbDJ5SkxaVkRtdHBucjlFbzc2LzRWSGhGeWJIYU84aWxabXJaQTRqMitMaGRBSFg3a3ZhVE1YbHQxSVphaWdOZE9YYVAwT3d2d3BWUGtSTG9LOHJ1UDRObzE4VGRvQVc0MTVpUT09PC9kc2lnOlg1MDlDZXJ0aWZpY2F0ZT48L2RzaWc6WDUwOURhdGE+PC9kc2lnOktleUluZm8+PGRzaWc6T2JqZWN0IElkPSJldHNpLXNpZ25lZC0xLTEiPjxldHNpOlF1YWxpZnlpbmdQcm9wZXJ0aWVzIHhtbG5zOmV0c2k9Imh0dHA6Ly91cmkuZXRzaS5vcmcvMDE5MDMvdjEuMS4xIyIgVGFyZ2V0PSIjc2lnbmF0dXJlLTEtMSI+PGV0c2k6U2lnbmVkUHJvcGVydGllcz48ZXRzaTpTaWduZWRTaWduYXR1cmVQcm9wZXJ0aWVzPjxldHNpOlNpZ25pbmdUaW1lPjIwMTgtMDYtMDVUMDY6MzI6MjZaPC9ldHNpOlNpZ25pbmdUaW1lPjxldHNpOlNpZ25pbmdDZXJ0aWZpY2F0ZT48ZXRzaTpDZXJ0PjxldHNpOkNlcnREaWdlc3Q+PGV0c2k6RGlnZXN0TWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnI3NoYTEiLz48ZXRzaTpEaWdlc3RWYWx1ZT5JZE1yc2VxMHNXczl5UStFRDN3UWpIOHcxeDg9PC9ldHNpOkRpZ2VzdFZhbHVlPjwvZXRzaTpDZXJ0RGlnZXN0PjxldHNpOklzc3VlclNlcmlhbD48ZHNpZzpYNTA5SXNzdWVyTmFtZT5DTj1hLXNpZ24tcHJlbWl1bS1tb2JpbGUtMDUsT1U9YS1zaWduLXByZW1pdW0tbW9iaWxlLTA1LE89QS1UcnVzdCBHZXMuIGYuIFNpY2hlcmhlaXRzc3lzdGVtZSBpbSBlbGVrdHIuIERhdGVudmVya2VociBHbWJILEM9QVQ8L2RzaWc6WDUwOUlzc3Vlck5hbWU+PGRzaWc6WDUwOVNlcmlhbE51bWJlcj45NTMyNjU4MTg8L2RzaWc6WDUwOVNlcmlhbE51bWJlcj48L2V0c2k6SXNzdWVyU2VyaWFsPjwvZXRzaTpDZXJ0PjwvZXRzaTpTaWduaW5nQ2VydGlmaWNhdGU+PGV0c2k6U2lnbmF0dXJlUG9saWN5SWRlbnRpZmllcj48ZXRzaTpTaWduYXR1cmVQb2xpY3lJbXBsaWVkLz48L2V0c2k6U2lnbmF0dXJlUG9saWN5SWRlbnRpZmllcj48L2V0c2k6U2lnbmVkU2lnbmF0dXJlUHJvcGVydGllcz48ZXRzaTpTaWduZWREYXRhT2JqZWN0UHJvcGVydGllcz48ZXRzaTpEYXRhT2JqZWN0Rm9ybWF0IE9iamVjdFJlZmVyZW5jZT0iI3JlZmVyZW5jZS0xLTEiPjxldHNpOk1pbWVUeXBlPmFwcGxpY2F0aW9uL3hodG1sK3htbDwvZXRzaTpNaW1lVHlwZT48L2V0c2k6RGF0YU9iamVjdEZvcm1hdD48L2V0c2k6U2lnbmVkRGF0YU9iamVjdFByb3BlcnRpZXM+PC9ldHNpOlNpZ25lZFByb3BlcnRpZXM+PC9ldHNpOlF1YWxpZnlpbmdQcm9wZXJ0aWVzPjwvZHNpZzpPYmplY3Q+PC9kc2lnOlNpZ25hdHVyZT4NCgk8c2FtbDI6Q29uZGl0aW9ucyBOb3RCZWZvcmU9IjIwMTYtMDMtMjlUMDg6NTA6NTYuNDUwWiIgTm90T25PckFmdGVyPSIyMDE2LTAzLTI5VDA4OjU1OjU2LjQ1MFoiPg0KCQk8c2FtbDI6QXVkaWVuY2VSZXN0cmljdGlvbj4NCgkJCTxzYW1sMjpBdWRpZW5jZT5odHRwczovL2RlbW8uZWdpei5ndi5hdC9kZW1vLVNQL3B2cC9wb3N0PC9zYW1sMjpBdWRpZW5jZT4NCgkJPC9zYW1sMjpBdWRpZW5jZVJlc3RyaWN0aW9uPg0KCTwvc2FtbDI6Q29uZGl0aW9ucz4NCgk8c2FtbDI6QXR0cmlidXRlU3RhdGVtZW50Pg0KCQk8c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iUFZQLVZFUlNJT04iIE5hbWU9InVybjpvaWQ6MS4yLjQwLjAuMTAuMi4xLjEuMjYxLjEwIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+DQoJCQk8c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+Mi4xPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCgkJPC9zYW1sMjpBdHRyaWJ1dGU+DQoJCTxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJQUklOQ0lQQUwtTkFNRSIgTmFtZT0idXJuOm9pZDoxLjIuNDAuMC4xMC4yLjEuMS4yNjEuMjAiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj4NCgkJCTxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5NdXN0ZXJtYW5uPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCgkJPC9zYW1sMjpBdHRyaWJ1dGU+DQoJCTxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJHSVZFTi1OQU1FIiBOYW1lPSJ1cm46b2lkOjIuNS40LjQyIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+DQoJCQk8c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+TWF4PC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCgkJPC9zYW1sMjpBdHRyaWJ1dGU+DQoJCTxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJCSVJUSERBVEUiIE5hbWU9InVybjpvaWQ6MS4yLjQwLjAuMTAuMi4xLjEuNTUiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj4NCgkJCTxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj4wMS4wMy4xOTk4PC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCgkJPC9zYW1sMjpBdHRyaWJ1dGU+DQoJCTxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJTZXJ2aWNlUHJvdmlkZXItVW5pcXVlSWQiIE5hbWU9Imh0dHA6Ly9laWQuZ3YuYXQvZUlEL2F0dHJpYnV0ZXMvU2VydmljZVByb3ZpZGVyVW5pcXVlSWQiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj4NCgkJCTxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5odHRwczovL2RlbW8uZWdpei5ndi5hdC9kZW1vLVNQL3B2cC9tZXRhZGF0YTwvc2FtbDI6QXR0cmlidXRlVmFsdWU+DQoJCTwvc2FtbDI6QXR0cmlidXRlPg0KCQk8c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iU2VydmljZVByb3ZpZGVyLUZyaWVuZGx5TmFtZSIgTmFtZT0iaHR0cDovL2VpZC5ndi5hdC9lSUQvYXR0cmlidXRlcy9TZXJ2aWNlUHJvdmlkZXJGcmllbmRseU5hbWUiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj4NCgkJCTxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5EZW1vbG9naW4gU2VydmljZSBwcm92aWRlZCBieSBFR0laPC9zYW1sMjpBdHRyaWJ1dGVWYWx1ZT4NCgkJPC9zYW1sMjpBdHRyaWJ1dGU+DQoJCTxzYW1sMjpBdHRyaWJ1dGUgRnJpZW5kbHlOYW1lPSJTZXJ2aWNlUHJvdmlkZXItQ291bnRyeUNvZGUiIE5hbWU9Imh0dHA6Ly9laWQuZ3YuYXQvZUlEL2F0dHJpYnV0ZXMvU2VydmljZVByb3ZpZGVyQ291bnRyeUNvZGUiIE5hbWVGb3JtYXQ9InVybjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDphdHRybmFtZS1mb3JtYXQ6dXJpIj4NCgkJCTxzYW1sMjpBdHRyaWJ1dGVWYWx1ZSB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiB4c2k6dHlwZT0ieHM6c3RyaW5nIj5BVDwvc2FtbDI6QXR0cmlidXRlVmFsdWU+DQoJCTwvc2FtbDI6QXR0cmlidXRlPg0KCQk8c2FtbDI6QXR0cmlidXRlIEZyaWVuZGx5TmFtZT0iTUFOREFURS1SRUZFUkVOQ0UtVkFMVUUiIE5hbWU9InVybjpvaWQ6MS4yLjQwLjAuMTAuMi4xLjEuMjYxLjkwIiBOYW1lRm9ybWF0PSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXR0cm5hbWUtZm9ybWF0OnVyaSI+DQoJCQk8c2FtbDI6QXR0cmlidXRlVmFsdWUgeG1sbnM6eHNpPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNjaGVtYS1pbnN0YW5jZSIgeHNpOnR5cGU9InhzOnN0cmluZyI+X2FzZGZhZGZhc2Zhc2Zhc2Zhc2Zhc2Zhc2Zhc2Zhc2Zhc2Zhc2Zhczwvc2FtbDI6QXR0cmlidXRlVmFsdWU+DQoJCTwvc2FtbDI6QXR0cmlidXRlPg0KCTwvc2FtbDI6QXR0cmlidXRlU3RhdGVtZW50Pg0KPC9zYW1sMjpBc3NlcnRpb24+" + } +} \ No newline at end of file -- cgit v1.2.3