diff options
author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2017-09-08 14:37:54 +0200 |
---|---|---|
committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2017-09-08 14:37:54 +0200 |
commit | 698a0066e84dee07f0f8de8aa408d9744f755660 (patch) | |
tree | 17085c61b97cef37b7d2443513622c1d02553710 /id/server | |
parent | b754f06150f8a8b6235bc3a138ab403175036171 (diff) | |
parent | a512ce06caa134ea978ca54a87a8b78d5c10bf1c (diff) | |
download | moa-id-spss-698a0066e84dee07f0f8de8aa408d9744f755660.tar.gz moa-id-spss-698a0066e84dee07f0f8de8aa408d9744f755660.tar.bz2 moa-id-spss-698a0066e84dee07f0f8de8aa408d9744f755660.zip |
Merge tag 'MOA-ID-3.2.3' into development_previewMOA-ID-3.2.3
JoinUp Release
# Conflicts:
# pom.xml
Diffstat (limited to 'id/server')
74 files changed, 3728 insertions, 1227 deletions
diff --git a/id/server/auth-edu/pom.xml b/id/server/auth-edu/pom.xml index 4e01c6260..b8bdad311 100644 --- a/id/server/auth-edu/pom.xml +++ b/id/server/auth-edu/pom.xml @@ -202,6 +202,13 @@ <artifactId>moa-id-module-ssoTransfer</artifactId> <version>${moa-id-version}</version> </dependency> + + <dependency> + <groupId>MOA.id.server.modules</groupId> + <artifactId>moa-id-module-bkaMobilaAuthSAML2Test</artifactId> + <version>${moa-id-version}</version> + </dependency> + <!-- <dependency> <groupId>org.apache.santuario</groupId> diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/css_template.css b/id/server/data/deploy/conf/moa-id/htmlTemplates/css_template.css index aa1242371..691166911 100644 --- a/id/server/data/deploy/conf/moa-id/htmlTemplates/css_template.css +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/css_template.css @@ -23,7 +23,7 @@ /*border-radius: 5px;*/ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit]{ font-size: 0.85em; /*border-radius: 7px;*/ margin-bottom: 25px; @@ -69,7 +69,10 @@ margin-bottom: 25px; margin-top: 25px; } - + #alert_area { + width: 500px; + padding-left: 80px; + } #leftcontent { /*float:left; */ width:250px; @@ -168,7 +171,7 @@ /* border-radius: 5px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit]{ font-size: 0.7em; min-width: 55px; /*min-height: 1.1em; @@ -207,7 +210,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.75em; min-width: 60px; /* min-height: 0.95em; @@ -245,7 +248,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.85em; /* min-height: 1.05em; border-radius: 7px; */ @@ -277,7 +280,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.9em; /* min-height: 1.2em; border-radius: 8px; */ @@ -310,7 +313,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 1.0em; /* min-height: 1.3em; border-radius: 10px; */ @@ -368,7 +371,16 @@ font-size: 0pt; visibility: hidden; } - + + #alert_area { + visibility: visible; + width: 250px; + } + #alert_area > p:first-child { + display: none; + visibility: hidden; + } + #leftcontent { visibility: visible; margin-bottom: 0px; @@ -411,7 +423,7 @@ height: 25px; } - input[type=button] { + input[type=button],input[type=submit] { /* height: 11%; */ width: 70%; } @@ -452,9 +464,14 @@ text-align: right; } + #ssoSessionTransferBlock { + clear: both; + } + #stork { /*margin-bottom: 10px;*/ /* margin-top: 5px; */ + clear: both; } #mandateLogin { @@ -563,6 +580,7 @@ } + .selectTextHeader{ } @@ -620,12 +638,6 @@ margin-left: 5px; margin-bottom: 5px; } - - #alert_area { - width: 500px; - padding-left: 80px; - } - #processInfoArea { margin-bottom: 15px; margin-top: 15px; diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js b/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js index a463bae65..0c1f6a561 100644 --- a/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/javascript_tempalte.js @@ -33,7 +33,11 @@ function isIE() { function bkuOnlineClicked() { if (isMetro()) document.getElementById("metroDetected").style.display="block"; - document.getElementById("localBKU").style.display="block"; + + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="block"; + /* if (checkMandateSSO()) return; */ @@ -49,7 +53,10 @@ function isIE() { generateIFrame(iFrameURL); } function bkuHandyClicked() { - document.getElementById("localBKU").style.display="none"; + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="block"; + /* if (checkMandateSSO()) return; */ @@ -65,7 +72,10 @@ function isIE() { generateIFrame(iFrameURL); } function storkClicked() { - document.getElementById("localBKU").style.display="none"; + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="none"; + /* if (checkMandateSSO()) return; */ @@ -129,12 +139,14 @@ function isIE() { console.log("Browser is Chrome: "+checkIfBrowserIsChrome()); console.log("Browser is Safari: "+checkIfBrowserIsSafari()); console.log("Browser is Edge: "+checkIfBrowserIsEdge()); + console.log("Browser is Firefox(>51): " +checkIfBrowserIsFirefox()) var cnt = 0; if(checkIfBrowserIsChrome())cnt++; if(checkIfBrowserIsEdge())cnt++; if(checkIfBrowserIsSafari())cnt++; + if(checkIfBrowserIsFirefox())cnt++; if(cnt==0 || cnt>1)//cnt>1 means perhaps wrong detection return true; @@ -149,11 +161,25 @@ function isIE() { var button = document.getElementsByName("bkuButtonOnline")[0]; button.setAttribute("class","browserInfoButton"); button.setAttribute("title","Java wird nicht unterstützt, klicken für mehr Informationen."); - button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von Firefox und MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); + button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); return false; } + function checkIfBrowserIsFirefox() { + var firefoxMarkerPos = navigator.userAgent.toLowerCase().indexOf('firefox'); + if (firefoxMarkerPos > -1) { + if (navigator.userAgent.toLowerCase().length >= (firefoxMarkerPos + 'firefox/'.length)) { + var ffversion = navigator.userAgent.toLowerCase().substring(firefoxMarkerPos + 8); + if (ffversion > 51) { + return true; + } + } else { + console.log("Browser looks like Firefox but has suspect userAgent string: " + navigator.userAgent.toLowerCase()); + } + } + return false; + } function checkIfBrowserIsChrome(){ var chrome_defined = !!window.chrome;//chrome object defined var webstore_defined = false; @@ -173,7 +199,44 @@ function isIE() { function checkIfBrowserIsSafari(){ var cond1 = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; return cond1; - } + } + function setBKUAvailable(available) { + //login = document.getElementById("localBKU"); + //active = (login.className.indexOf("lokalebkuaktiv") != -1); + try { + if (available) { + console.log("Local BKU available") + //login.className = login.className.replace("lokalebkuinaktiv", "lokalebkuaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.removeAttribute("class");; + button.setAttribute("title","Bürgerkarte mit localer Bürgerkartenumgebung."); + + var image = document.getElementById("bkuimage"); + var srcatt = image.getAttribute("src"); + var last = srcatt.substring(srcatt.lastIndexOf('/')+1); + srcatt = srcatt.replace(last,'karte.png'); + image.setAttribute("src",srcatt); + + } else if (!available) { + //login.className = login.className.replace("lokalebkuaktiv", "lokalebkuinaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.setAttribute("class","browserInfoButton"); + button.setAttribute("title","Es wurde keine Bürgerkartenumgebung gefunden. Sollte es sich hierbei um einen Fehler handeln können Sie den Prozess durch einen Klick auf den Button denoch fortsetzen."); + + var image = document.getElementById("bkuimage"); + var srcatt = image.getAttribute("src"); + var last = srcatt.substring(srcatt.lastIndexOf('/')+1); + srcatt = srcatt.replace(last,'karte_deactivated.png'); + image.setAttribute("src",srcatt); + + console.log("Local BKU NOT available") + } + } catch(e) {console.log("Local BKU detection is not possible! Msg: "+e);} + + } + /* function setSSOSelection() { document.getElementById("useSSO").value = "false"; var checkbox = document.getElementById("SSOCheckBox"); diff --git a/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html b/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html index 32f0a7d4d..53c4f0d5d 100644 --- a/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html +++ b/id/server/data/deploy/conf/moa-id/htmlTemplates/loginFormFull.html @@ -12,7 +12,8 @@ <title>Anmeldung mittels Bürgerkarte oder Handy-Signatur</title> </head> -<body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"> +<!--body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"--> +<body onload="onChangeChecks();" onresize="onChangeChecks();"> <div id="page"> <div id="page1" class="case selected-case" role="main"> <h2 class="OA_header" role="heading">Anmeldung an: $OAName</h2> @@ -37,19 +38,28 @@ </div> <div id="bkuselectionarea"> <div id="bkukarte"> - <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" - alt="OnlineBKU" /> <input name="bkuButtonOnline" type="button" - onClick="bkuOnlineClicked();" tabindex="2" role="button" - value="Karte" /> + <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" alt="OnlineBKU" /> + + <!-- Remove support for Online BKU and swith the card button to local BKU--> + <!--input name="bkuButtonOnline" type="button" onClick="bkuOnlineClicked();" tabindex="2" role="button" value="Karte" /--> + + <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> + <input type="hidden" name="bkuURI" value="$bkuLocal" /> + <input type="hidden" name="useMandate" id="useMandate" /> + <input type="hidden" name="SSO" id="useSSO" /> + <input type="hidden" name="ccc" id="ccc" /> + <input type="hidden" name="pendingid" value="$pendingReqID" /> + <input type="submit" value=" Karte " tabindex="4" role="button" onclick="setMandateSelection();"> + </form> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"></iframe> + </div> <div id="bkuhandy"> - <img class="bkuimage" src="$contextPath/img/handysign.png" - alt="HandyBKU" /> <input name="bkuButtonHandy" type="button" - onClick="bkuHandyClicked();" tabindex="3" role="button" - value="HANDY" /> + <img class="bkuimage" src="$contextPath/img/handysign.png" alt="HandyBKU" /> + <input name="bkuButtonHandy" type="button" onClick="bkuHandyClicked();" tabindex="3" role="button" value="HANDY" /> </div> </div> - <div id="localBKU"> + <!--div id="localBKU"> <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> <input type="hidden" name="bkuURI" value="$bkuLocal" /> @@ -60,7 +70,8 @@ <input type="submit" value=" Lokale Bürgerkartenumgebung " tabindex="4" role="button" onclick="setMandateSelection();"> </form> - </div> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"><\/iframe> + </div--> <!-- Single Sign-On Session transfer functionality --> <!--div id="ssoSessionTransferBlock"> diff --git a/id/server/data/deploy/conf/moa-spss/SampleMOASPSSConfiguration.xml b/id/server/data/deploy/conf/moa-spss/SampleMOASPSSConfiguration.xml index d2facbd1a..31fc8a16c 100644 --- a/id/server/data/deploy/conf/moa-spss/SampleMOASPSSConfiguration.xml +++ b/id/server/data/deploy/conf/moa-spss/SampleMOASPSSConfiguration.xml @@ -3,6 +3,8 @@ <cfg:MOAConfiguration xmlns:cfg="http://reference.e-government.gv.at/namespace/moaconfig/20021122#" xmlns:dsig="http://www.w3.org/2000/09/xmldsig#"> <cfg:SignatureVerification> <cfg:CertificateValidation> + <!-- ReadTimeout in seconds--> + <cfg:ReadTimeout>30</cfg:ReadTimeout> <cfg:PathConstruction> <cfg:AutoAddCertificates>true</cfg:AutoAddCertificates> <cfg:UseAuthorityInformationAccess>true</cfg:UseAuthorityInformationAccess> @@ -42,6 +44,13 @@ <cfg:TrustProfile> <cfg:Id>C-PEPS-Test</cfg:Id> <cfg:TrustAnchorsLocation>trustProfiles/C-PEPS-Test</cfg:TrustAnchorsLocation> + <!--cfg:EUTSL--> + <!-- Optional kann eine Länderliste mit zweistelligen Länderkürzeln angegeben werden (d.h. nur die --> + <!-- Vertrauensanker der angegeben Länder werden importiert) --> + <!--cfg:CountrySelection>AT,BE</cfg:CountrySelection> + <cfg:AllowedTSPStatus></cfg:AllowedTSPStatus> + <cfg:AllowedTSPServiceTypes></cfg:AllowedTSPServiceTypes> + </cfg:EUTSL--> </cfg:TrustProfile> <cfg:TrustProfile> <cfg:Id>C-PEPS</cfg:Id> @@ -86,6 +95,19 @@ </cfg:CA> </cfg:CrlRetentionIntervals> </cfg:RevocationChecking> + <!-- Optionale Angabe einer TSL Konfiguration--> + <!-- Wichtig: Das WorkingDirectory muss jedenfalls den Unterordner „trust“ aus der Beispielkonfiguration beinhalten. --> + <!-- <cfg:TSLConfiguration> + <cfg:UpdateSchedule> + <cfg:StartTime>02:00:00</cfg:StartTime> + <cfg:Period>86400000</cfg:Period> + </cfg:UpdateSchedule> + <cfg:WorkingDirectory>tslworking</cfg:WorkingDirectory> + <cfg:Evaluation> + <cfg:QCQualifier>http://uri.etsi.org/TrstSvc/Svctype/CA/QC,http://uri.etsi.org/TrstSvc/Svctype/TSA/QTST</cfg:QCQualifier> + <cfg:SSCDQualifier>http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCWithSSCD,http://uri.etsi.org/TrstSvc/TrustedList/SvcInfoExt/QCWithQSCD</cfg:SSCDQualifier> + </cfg:Evaluation> + </cfg:TSLConfiguration>--> </cfg:CertificateValidation> <cfg:VerifyTransformsInfoProfile> <cfg:Id>MOAIDTransformAuthBlockTable_DE_2.0</cfg:Id> diff --git a/id/server/doc/htmlTemplates/BKU-selection.html b/id/server/doc/htmlTemplates/BKU-selection.html index 32f0a7d4d..53c4f0d5d 100644 --- a/id/server/doc/htmlTemplates/BKU-selection.html +++ b/id/server/doc/htmlTemplates/BKU-selection.html @@ -12,7 +12,8 @@ <title>Anmeldung mittels Bürgerkarte oder Handy-Signatur</title> </head> -<body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"> +<!--body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"--> +<body onload="onChangeChecks();" onresize="onChangeChecks();"> <div id="page"> <div id="page1" class="case selected-case" role="main"> <h2 class="OA_header" role="heading">Anmeldung an: $OAName</h2> @@ -37,19 +38,28 @@ </div> <div id="bkuselectionarea"> <div id="bkukarte"> - <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" - alt="OnlineBKU" /> <input name="bkuButtonOnline" type="button" - onClick="bkuOnlineClicked();" tabindex="2" role="button" - value="Karte" /> + <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" alt="OnlineBKU" /> + + <!-- Remove support for Online BKU and swith the card button to local BKU--> + <!--input name="bkuButtonOnline" type="button" onClick="bkuOnlineClicked();" tabindex="2" role="button" value="Karte" /--> + + <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> + <input type="hidden" name="bkuURI" value="$bkuLocal" /> + <input type="hidden" name="useMandate" id="useMandate" /> + <input type="hidden" name="SSO" id="useSSO" /> + <input type="hidden" name="ccc" id="ccc" /> + <input type="hidden" name="pendingid" value="$pendingReqID" /> + <input type="submit" value=" Karte " tabindex="4" role="button" onclick="setMandateSelection();"> + </form> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"></iframe> + </div> <div id="bkuhandy"> - <img class="bkuimage" src="$contextPath/img/handysign.png" - alt="HandyBKU" /> <input name="bkuButtonHandy" type="button" - onClick="bkuHandyClicked();" tabindex="3" role="button" - value="HANDY" /> + <img class="bkuimage" src="$contextPath/img/handysign.png" alt="HandyBKU" /> + <input name="bkuButtonHandy" type="button" onClick="bkuHandyClicked();" tabindex="3" role="button" value="HANDY" /> </div> </div> - <div id="localBKU"> + <!--div id="localBKU"> <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> <input type="hidden" name="bkuURI" value="$bkuLocal" /> @@ -60,7 +70,8 @@ <input type="submit" value=" Lokale Bürgerkartenumgebung " tabindex="4" role="button" onclick="setMandateSelection();"> </form> - </div> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"><\/iframe> + </div--> <!-- Single Sign-On Session transfer functionality --> <!--div id="ssoSessionTransferBlock"> diff --git a/id/server/doc/htmlTemplates/BKU-selection_with_OnlineBKU.html b/id/server/doc/htmlTemplates/BKU-selection_with_OnlineBKU.html new file mode 100644 index 000000000..32f0a7d4d --- /dev/null +++ b/id/server/doc/htmlTemplates/BKU-selection_with_OnlineBKU.html @@ -0,0 +1,92 @@ +<!DOCTYPE html> +<html> +<head> +<meta content="text/html; charset=utf-8" http-equiv="Content-Type"> + + <!-- MOA-ID 2.x BKUSelection Layout CSS --> + <link rel="stylesheet" href="$contextPath/css/buildCSS?pendingid=$pendingReqID" /> + + <!-- MOA-ID 2.x BKUSelection JavaScript fucnctions--> + <script src="$contextPath/js/buildJS?pendingid=$pendingReqID"></script> + + +<title>Anmeldung mittels Bürgerkarte oder Handy-Signatur</title> +</head> +<body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"> + <div id="page"> + <div id="page1" class="case selected-case" role="main"> + <h2 class="OA_header" role="heading">Anmeldung an: $OAName</h2> + <div id="main"> + <div id="leftcontent" class="hell" role="application"> + <div id="bku_header" class="dunkel"> + <h2 id="tabheader" class="dunkel" role="heading">$HEADER_TEXT</h2> + </div> + <div id="bkulogin" class="hell" role="form"> + <div id="mandateLogin" style="$MANDATEVISIBLE"> + <div> + <input tabindex="1" type="checkbox" name="Mandate" + id="mandateCheckBox" class="verticalcenter" role="checkbox" + onClick='document.getElementById("mandateCheckBox").setAttribute("aria-checked", document.getElementById("mandateCheckBox").checked);'$MANDATECHECKED> + <label for="mandateCheckBox" class="verticalcenter">in + Vertretung anmelden</label> + <!--a href="info_mandates.html" + target="_blank" + class="infobutton verticalcenter" + tabindex="5">i</a--> + </div> + </div> + <div id="bkuselectionarea"> + <div id="bkukarte"> + <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" + alt="OnlineBKU" /> <input name="bkuButtonOnline" type="button" + onClick="bkuOnlineClicked();" tabindex="2" role="button" + value="Karte" /> + </div> + <div id="bkuhandy"> + <img class="bkuimage" src="$contextPath/img/handysign.png" + alt="HandyBKU" /> <input name="bkuButtonHandy" type="button" + onClick="bkuHandyClicked();" tabindex="3" role="button" + value="HANDY" /> + </div> + </div> + <div id="localBKU"> + <form method="get" id="moaidform" action="$contextPath$submitEndpoint" + class="verticalcenter" target="_parent"> + <input type="hidden" name="bkuURI" value="$bkuLocal" /> + <input type="hidden" name="useMandate" id="useMandate" /> + <input type="hidden" name="SSO" id="useSSO" /> + <input type="hidden" name="ccc" id="ccc" /> + <input type="hidden" name="pendingid" value="$pendingReqID" /> + <input type="submit" value=" Lokale Bürgerkartenumgebung " tabindex="4" + role="button" onclick="setMandateSelection();"> + </form> + </div> + + <!-- Single Sign-On Session transfer functionality --> + <!--div id="ssoSessionTransferBlock"> + <a href="$contextPath$submitEndpoint?pendingid=$pendingReqID&restoreSSOSession=true">>Restore SSO Session from Smartphone</a> + </div--> + + <div id="stork" align="center" style="$STORKVISIBLE"> + <h2 id="tabheader" class="dunkel">Home Country Selection</h2> + <p> + <select name="cccSelection" id="cccSelection" size="1" style="width: 120px; margin-right: 5px;" > + $countryList + </select> + <button name="bkuButton" type="button" onClick="storkClicked();">Proceed</button> + <a href="info_stork.html" target="_blank" class="infobutton" style="color:#FFF">i</a> + </p> + </div> + + <div id="metroDetected" style="display: none"> + <p>Anscheinend verwenden Sie Internet Explorer im + Metro-Modus. Wählen Sie bitte "Auf dem Desktop anzeigen" aus den + Optionen um die Karten-Anmeldung starten zu können.</p> + </div> + </div> + </div> + </div> + </div> + </div> +</body> +</html> diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/advancedlogging/StatisticLogger.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/advancedlogging/StatisticLogger.java index 6f700d1cb..55b1a7c9a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/advancedlogging/StatisticLogger.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/advancedlogging/StatisticLogger.java @@ -69,6 +69,7 @@ public class StatisticLogger implements IStatisticLogger{ private static final String GENERIC_LOCALBKU = ":3496/https-security-layer-request"; private static final String GENERIC_HANDYBKU = "https://www.handy-signatur.at/"; + private static final String GENERIC_ONLINE_BKU = "bkuonline"; private static final String MANTATORTYPE_JUR = "jur"; private static final String MANTATORTYPE_NAT = "nat"; @@ -289,7 +290,11 @@ public class StatisticLogger implements IStatisticLogger{ if (moasession != null) { if (MiscUtil.isNotEmpty(moasession.getBkuURL())) { dblog.setBkuurl(moasession.getBkuURL()); - dblog.setBkutype(findBKUType(moasession.getBkuURL(), dbOA)); + if (moasession.isForeigner()) { + dblog.setBkutype(IOAAuthParameters.EIDAS); + + } else + dblog.setBkutype(findBKUType(moasession.getBkuURL(), dbOA)); } dblog.setMandatelogin(moasession.isMandateUsed()); @@ -418,8 +423,13 @@ public class StatisticLogger implements IStatisticLogger{ return IOAAuthParameters.HANDYBKU; } - Logger.debug("BKUURL " + bkuURL + " is mapped to " + IOAAuthParameters.ONLINEBKU); - return IOAAuthParameters.ONLINEBKU; + if (bkuURL.contains(GENERIC_ONLINE_BKU)) { + Logger.debug("BKUURL " + bkuURL + " is mapped to " + IOAAuthParameters.ONLINEBKU); + return IOAAuthParameters.ONLINEBKU; + } + + Logger.debug("BKUURL " + bkuURL + " is mapped to " + IOAAuthParameters.AUTHTYPE_OTHERS); + return IOAAuthParameters.AUTHTYPE_OTHERS; } } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/IPostStartupInitializable.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/IPostStartupInitializable.java new file mode 100644 index 000000000..d918be463 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/IPostStartupInitializable.java @@ -0,0 +1,41 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth; + + +/** + * + * @author tlenz + * + * Interface initialize a Object when the MOA-ID-Auth start-up process is fully completed + * + */ +public interface IPostStartupInitializable { + + /** + * This method is called once when MOA-ID-Auth start-up process is fully completed + * + */ + public void executeAfterStartup(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java index 5769d99df..3d45e2468 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthInitializer.java @@ -44,6 +44,7 @@ import at.gv.egovernment.moa.spss.api.Configurator; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moaspss.logging.LoggingContext; import at.gv.egovernment.moaspss.logging.LoggingContextManager; +import iaik.asn1.structures.AlgorithmID; import iaik.pki.PKIException; import iaik.security.ec.provider.ECCelerate; import iaik.security.provider.IAIK; @@ -126,7 +127,7 @@ public class MOAIDAuthInitializer { Random.seedRandom(); Logger.debug("Random-number generator is seeded."); - // Initialize configuration provider + // Initialize configuration provider for non-spring managed parts AuthConfiguration authConf = AuthConfigurationProviderFactory.reload(rootContext); //test, if MOA-ID is already configured @@ -160,6 +161,8 @@ public class MOAIDAuthInitializer { Security.addProvider(new ECCelerate()); + fixJava8_141ProblemWithSSLAlgorithms(); + if (Logger.isDebugEnabled()) { Logger.debug("Loaded Security Provider:"); Provider[] providerList = Security.getProviders(); @@ -167,5 +170,24 @@ public class MOAIDAuthInitializer { Logger.debug(i + ": " + providerList[i].getName() + " Version " + providerList[i].getVersion()); } + } + + private static void fixJava8_141ProblemWithSSLAlgorithms() { + Logger.info("Change AlgorithmIDs to fix problems with Java8 >= 141 ..."); + //new AlgorithmID("1.2.840.113549.1.1.4", "md5WithRSAEncryption", new String[] { "MD5withRSA", "MD5/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.5", "sha1WithRSAEncryption", + new String[] { "SHA1withRSA" , "SHA1/RSA", "SHA-1/RSA", "SHA/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.14", "sha224WithRSAEncryption", + new String[] { "SHA224withRSA", "SHA224/RSA", "SHA-224/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.11", "sha256WithRSAEncryption", + new String[] { "SHA256withRSA", "SHA256/RSA", "SHA-256/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.12", "sha384WithRSAEncryption", + new String[] { "SHA384withRSA", "SHA384/RSA", "SHA-384/RSA", }, null, true); + new AlgorithmID("1.2.840.113549.1.1.13", "sha512WithRSAEncryption", + new String[] { "SHA512withRSA", "SHA512/RSA", "SHA-512/RSA" }, null, true); + + Logger.info("Change AlgorithmIDs finished"); + } + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/PropertyBasedAuthConfigurationProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/PropertyBasedAuthConfigurationProvider.java index 7e0f48744..35d052acd 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/PropertyBasedAuthConfigurationProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/auth/PropertyBasedAuthConfigurationProvider.java @@ -235,6 +235,11 @@ public class PropertyBasedAuthConfigurationProvider extends ConfigurationProvide return properties.getProperty(key, defaultValue); } + + public Map<String, String> getBasicMOAIDConfigurationWithPrefix(final String prefix) { + return KeyValueUtils.getSubSetWithPrefix(KeyValueUtils.concertPropertiesToMap(properties), prefix); + + } /* (non-Javadoc) 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 f718777b0..ab0a1ec40 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 @@ -366,6 +366,10 @@ public class AuthenticationManager extends MOAIDAuthConstants { //create authentication process execution context ExecutionContext executionContext = new ExecutionContextImpl(); + + //set oaIdentifeir + executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_UNIQUE_OA_IDENTFIER, + pendingReq.getOnlineApplicationConfiguration().getPublicURLPrefix()); //set interfederation authentication flag executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_INTERFEDERATION_AUTH, diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java index 0d51818f8..ecd67db64 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/builder/attributes/IAttributeGenerator.java @@ -23,6 +23,13 @@ package at.gv.egovernment.moa.id.protocols.builder.attributes; public interface IAttributeGenerator<ATT> { + /** + * + * @param friendlyName FriendlyName + * @param name Name + * @param value value + * @return + */ public abstract ATT buildStringAttribute(final String friendlyName, final String name, final String value); public abstract ATT buildIntegerAttribute(final String friendlyName, final String name, final int value); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java index e2f8664d8..e2ac50e5e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/builder/PVPMetadataBuilder.java @@ -71,6 +71,7 @@ import org.w3c.dom.Document; import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPMetadataBuilderConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.MOADefaultBootstrap; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.AbstractCredentialProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; @@ -153,8 +154,7 @@ public class PVPMetadataBuilder { Credential metadataSignCred = config.getMetadataSigningCredentials(); Signature signature = AbstractCredentialProvider.getIDPSignature(metadataSignCred); SecurityHelper.prepareSignatureParams(signature, metadataSignCred, null, null); - - + //initialize XML document builder DocumentBuilder builder; DocumentBuilderFactory factory = DocumentBuilderFactory @@ -173,8 +173,11 @@ public class PVPMetadataBuilder { entitiesDescriptor.setValidUntil(date.plusHours(config.getMetadataValidUntil())); entitiesDescriptor.getEntityDescriptors().add(entityDescriptor); + //load default PVP security configurations + MOADefaultBootstrap.initializeDefaultPVPConfiguration(); entitiesDescriptor.setSignature(signature); + //marshall document Marshaller out = Configuration.getMarshallerFactory() .getMarshaller(entitiesDescriptor); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java index b2597c3cb..5380d7f53 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/MOAMetadataProvider.java @@ -38,6 +38,7 @@ import javax.xml.namespace.QName; import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.RoleDescriptor; +import org.opensaml.saml2.metadata.provider.BaseMetadataProvider; import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider; import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataFilter; @@ -45,6 +46,7 @@ import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.saml2.metadata.provider.ObservableMetadataProvider; import org.opensaml.xml.XMLObject; +import org.opensaml.xml.parse.BasicParserPool; import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.IDestroyableObject; @@ -52,7 +54,6 @@ import at.gv.egovernment.moa.id.auth.IGarbageCollectorProcessing; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException; import at.gv.egovernment.moa.id.commons.config.MOAIDConfigurationConstants; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.InterfederatedIDPPublicServiceFilter; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.PVPMetadataFilterChain; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.SchemaValidationFilter; @@ -154,7 +155,7 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider //reload metadata provider IOAAuthParameters oaParam = - AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(entityID); + authConfig.getOnlineApplicationParameter(entityID); if (oaParam != null) { String metadataURL = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_URL); if (MiscUtil.isNotEmpty(metadataURL)) { @@ -178,10 +179,11 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider timer = new Timer(true); ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - HTTPMetadataProvider newMetadataProvider = createNewHTTPMetaDataProvider(metadataURL, + MetadataProvider newMetadataProvider = createNewMoaMetadataProvider(metadataURL, buildMetadataFilterChain(oaParam, metadataURL, cert), oaFriendlyName, - timer); + timer, + new BasicParserPool()); chainProvider.addMetadataProvider(newMetadataProvider); @@ -203,9 +205,6 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider Logger.debug("Can not refresh PVP2X metadata: NO onlineApplication with Id: " + entityID); - } catch (ConfigurationException e) { - Logger.warn("Access MOA-ID configuration FAILED.", e); - } catch (MetadataProviderException e) { Logger.warn("Refresh PVP2X metadata for onlineApplication: " + entityID + " FAILED.", e); @@ -268,7 +267,7 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider //load all PVP2 OAs form ConfigurationDatabase and //compare actually loaded Providers with configured PVP2 OAs - Map<String, String> allOAs = AuthConfigurationProviderFactory.getInstance().getConfigurationWithWildCard( + Map<String, String> allOAs = authConfig.getConfigurationWithWildCard( MOAIDConfigurationConstants.PREFIX_MOAID_SERVICES + ".%." + MOAIDConfigurationConstants.SERVICE_UNIQUEIDENTIFIER); @@ -279,7 +278,7 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider Entry<String, String> oaKeyPair = oaInterator.next(); IOAAuthParameters oaParam = - AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(oaKeyPair.getValue()); + authConfig.getOnlineApplicationParameter(oaKeyPair.getValue()); if (oaParam != null) { String metadataurl = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_URL); @@ -409,83 +408,79 @@ public class MOAMetadataProvider extends SimpleMOAMetadataProvider ChainingMetadataProvider chainProvider = new ChainingMetadataProvider(); Logger.info("Loading metadata"); Map<String, MetadataProvider> providersinuse = new HashMap<String, MetadataProvider>(); - try { - Map<String, String> allOAs = AuthConfigurationProviderFactory.getInstance().getConfigurationWithWildCard( - MOAIDConfigurationConstants.PREFIX_MOAID_SERVICES - + ".%." - + MOAIDConfigurationConstants.SERVICE_UNIQUEIDENTIFIER); - - if (allOAs != null) { - Iterator<Entry<String, String>> oaInterator = allOAs.entrySet().iterator(); - while (oaInterator.hasNext()) { - Entry<String, String> oaKeyPair = oaInterator.next(); - - IOAAuthParameters oaParam = - AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(oaKeyPair.getValue()); - if (oaParam != null) { - String metadataurl = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_URL); - String oaFriendlyName = oaParam.getFriendlyName(); - HTTPMetadataProvider httpProvider = null; + Map<String, String> allOAs = authConfig.getConfigurationWithWildCard( + MOAIDConfigurationConstants.PREFIX_MOAID_SERVICES + + ".%." + + MOAIDConfigurationConstants.SERVICE_UNIQUEIDENTIFIER); + + if (allOAs != null) { + Iterator<Entry<String, String>> oaInterator = allOAs.entrySet().iterator(); + while (oaInterator.hasNext()) { + Entry<String, String> oaKeyPair = oaInterator.next(); - try { - String certBase64 = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_CERTIFICATE); - if (MiscUtil.isNotEmpty(certBase64) && MiscUtil.isNotEmpty(metadataurl)) { - byte[] cert = Base64Utils.decode(certBase64, false); - - - if (timer == null) - timer = new Timer(true); - - Logger.info("Loading metadata for: " + oaFriendlyName); - if (!providersinuse.containsKey(metadataurl)) { - httpProvider = createNewHTTPMetaDataProvider( - metadataurl, - buildMetadataFilterChain(oaParam, metadataurl, cert), - oaFriendlyName, - timer); - - if (httpProvider != null) - providersinuse.put(metadataurl, httpProvider); + IOAAuthParameters oaParam = + authConfig.getOnlineApplicationParameter(oaKeyPair.getValue()); + if (oaParam != null) { + String metadataurl = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_URL); + String oaFriendlyName = oaParam.getFriendlyName(); + MetadataProvider httpProvider = null; + + try { + String certBase64 = oaParam.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_CERTIFICATE); + if (MiscUtil.isNotEmpty(certBase64) && MiscUtil.isNotEmpty(metadataurl)) { + byte[] cert = Base64Utils.decode(certBase64, false); - } else { - Logger.info(metadataurl + " are already added."); - } + + if (timer == null) + timer = new Timer(true); + + Logger.info("Loading metadata for: " + oaFriendlyName); + if (!providersinuse.containsKey(metadataurl)) { + httpProvider = createNewMoaMetadataProvider( + metadataurl, + buildMetadataFilterChain(oaParam, metadataurl, cert), + oaFriendlyName, + timer, + new BasicParserPool()); + + if (httpProvider != null) + providersinuse.put(metadataurl, httpProvider); } else { - Logger.info(oaFriendlyName - + " is not a PVP2 Application skipping"); + Logger.info(metadataurl + " are already added."); } - } catch (Throwable e) { - Logger.error( - "Failed to add Metadata (unhandled reason: " - + e.getMessage(), e); - if (httpProvider != null) { - Logger.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } - } - } - } + } else { + Logger.info(oaFriendlyName + + " is not a PVP2 Application skipping"); + } + } catch (Throwable e) { + Logger.error( + "Failed to add Metadata (unhandled reason: " + + e.getMessage(), e); - } else - Logger.info("No Online-Application configuration found. PVP 2.1 metadata provider initialization failed!"); - - try { - chainProvider.setProviders(new ArrayList<MetadataProvider>(providersinuse.values())); - - } catch (MetadataProviderException e) { - Logger.error( - "Failed to add Metadata (unhandled reason: " - + e.getMessage(), e); + if (httpProvider != null && httpProvider instanceof BaseMetadataProvider) { + Logger.debug("Destroy failed Metadata provider"); + ((BaseMetadataProvider)httpProvider).destroy(); + + } + } + } } - internalProvider = chainProvider; - - } catch (ConfigurationException e) { - Logger.error("Access MOA-ID configuration FAILED.", e); + } else + Logger.info("No Online-Application configuration found. PVP 2.1 metadata provider initialization failed!"); + + try { + chainProvider.setProviders(new ArrayList<MetadataProvider>(providersinuse.values())); + } catch (MetadataProviderException e) { + Logger.error( + "Failed to add Metadata (unhandled reason: " + + e.getMessage(), e); } + + internalProvider = chainProvider; } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/SimpleMOAMetadataProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/SimpleMOAMetadataProvider.java index d5c7d9100..6c2235654 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/SimpleMOAMetadataProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/metadata/SimpleMOAMetadataProvider.java @@ -22,24 +22,28 @@ */ package at.gv.egovernment.moa.id.protocols.pvp2x.metadata; +import java.io.File; import java.util.Timer; import javax.net.ssl.SSLHandshakeException; import org.apache.commons.httpclient.MOAHttpClient; +import org.apache.commons.httpclient.params.HttpClientParams; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataFilter; import org.opensaml.saml2.metadata.provider.MetadataProvider; -import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.parse.ParserPool; +import org.springframework.beans.factory.annotation.Autowired; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SchemaValidationException; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SignatureValidationException; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; /** * @author tlenz @@ -47,6 +51,104 @@ import at.gv.egovernment.moa.logging.Logger; */ public abstract class SimpleMOAMetadataProvider implements MetadataProvider{ + private static final String URI_PREFIX_HTTP = "http:"; + private static final String URI_PREFIX_HTTPS = "https:"; + private static final String URI_PREFIX_FILE = "file:"; + + + @Autowired + protected AuthConfiguration authConfig; + + /** + * Create a single SAML2 MOA specific metadata provider + * + * @param metadataLocation where the metadata should be loaded, but never null. If the location starts with http(s):, than a http + * based metadata provider is used. If the location starts with file:, than a filesystem based metadata provider is used + * @param filter Filters, which should be used to validate the metadata + * @param IdForLogging Id, which is used for Logging + * @param timer {@link Timer} which is used to schedule metadata refresh operations + * + * @return SAML2 Metadata Provider, or null if the metadata provider can not initialized + */ + protected MetadataProvider createNewMoaMetadataProvider(String metadataLocation, MetadataFilter filter, + String IdForLogging, Timer timer, ParserPool pool) { + if (metadataLocation.startsWith(URI_PREFIX_HTTP) || metadataLocation.startsWith(URI_PREFIX_HTTPS)) + return createNewHTTPMetaDataProvider(metadataLocation, filter, IdForLogging, timer, pool); + + else { + String absoluteMetadataLocation = FileUtils.makeAbsoluteURL( + metadataLocation, + authConfig.getRootConfigFileDir()); + + if (absoluteMetadataLocation.startsWith(URI_PREFIX_FILE)) { + File metadataFile = new File(absoluteMetadataLocation); + if (metadataFile.exists()) + return createNewFileSystemMetaDataProvider(metadataFile, filter, IdForLogging, timer, pool); + + else { + Logger.warn("SAML2 metadata file: " + absoluteMetadataLocation + " not found or not exist"); + return null; + } + + } + } + + Logger.warn("SAML2 metadata has an unsupported metadata location prefix: " + metadataLocation); + return null; + + } + + + /** + * Create a single SAML2 filesystem based metadata provider + * + * @param metadataFile File, where the metadata should be loaded + * @param filter Filters, which should be used to validate the metadata + * @param IdForLogging Id, which is used for Logging + * @param timer {@link Timer} which is used to schedule metadata refresh operations + * @param pool + * + * @return SAML2 Metadata Provider + */ + private MetadataProvider createNewFileSystemMetaDataProvider(File metadataFile, MetadataFilter filter, String IdForLogging, Timer timer, ParserPool pool) { + FilesystemMetadataProvider fileSystemProvider = null; + try { + fileSystemProvider = new FilesystemMetadataProvider(timer, metadataFile); + fileSystemProvider.setParserPool(pool); + fileSystemProvider.setRequireValidMetadata(true); + fileSystemProvider.setMinRefreshDelay(1000*60*15); //15 minutes + fileSystemProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours + //httpProvider.setRefreshDelayFactor(0.1F); + + fileSystemProvider.setMetadataFilter(filter); + fileSystemProvider.initialize(); + + fileSystemProvider.setRequireValidMetadata(true); + + return fileSystemProvider; + + } catch (Exception e) { + Logger.warn( + "Failed to load Metadata file for " + + IdForLogging + "[ " + + "File: " + metadataFile.getAbsolutePath() + + " Msg: " + e.getMessage() + " ]", e); + + + Logger.warn("Can not initialize SAML2 metadata provider from filesystem: " + metadataFile.getAbsolutePath() + + " Reason: " + e.getMessage(), e); + + if (fileSystemProvider != null) + fileSystemProvider.destroy(); + + } + + return null; + + } + + + /** * Create a single SAML2 HTTP metadata provider * @@ -54,27 +156,32 @@ public abstract class SimpleMOAMetadataProvider implements MetadataProvider{ * @param filter Filters, which should be used to validate the metadata * @param IdForLogging Id, which is used for Logging * @param timer {@link Timer} which is used to schedule metadata refresh operations + * @param pool * * @return SAML2 Metadata Provider */ - protected HTTPMetadataProvider createNewHTTPMetaDataProvider(String metadataURL, MetadataFilter filter, String IdForLogging, Timer timer) { + private MetadataProvider createNewHTTPMetaDataProvider(String metadataURL, MetadataFilter filter, String IdForLogging, Timer timer, ParserPool pool) { HTTPMetadataProvider httpProvider = null; //Timer timer= null; MOAHttpClient httpClient = null; try { httpClient = new MOAHttpClient(); + HttpClientParams httpClientParams = new HttpClientParams(); + httpClientParams.setSoTimeout(AuthConfiguration.CONFIG_PROPS_METADATA_SOCKED_TIMEOUT); + httpClient.setParams(httpClientParams); + if (metadataURL.startsWith("https:")) { try { //FIX: change hostname validation default flag to true when httpClient is updated to > 4.4 MOAHttpProtocolSocketFactory protoSocketFactory = new MOAHttpProtocolSocketFactory( PVPConstants.SSLSOCKETFACTORYNAME, - AuthConfigurationProviderFactory.getInstance().getTrustedCACertificates(), + authConfig.getTrustedCACertificates(), null, AuthConfiguration.DEFAULT_X509_CHAININGMODE, - AuthConfigurationProviderFactory.getInstance().isTrustmanagerrevoationchecking(), - AuthConfigurationProviderFactory.getInstance().getRevocationMethodOrder(), - AuthConfigurationProviderFactory.getInstance().getBasicMOAIDConfigurationBoolean( + authConfig.isTrustmanagerrevoationchecking(), + authConfig.getRevocationMethodOrder(), + authConfig.getBasicMOAIDConfigurationBoolean( AuthConfiguration.PROP_KEY_SSL_HOSTNAME_VALIDATION, false)); httpClient.setCustomSSLTrustStore(metadataURL, protoSocketFactory); @@ -88,7 +195,7 @@ public abstract class SimpleMOAMetadataProvider implements MetadataProvider{ // timer = new Timer(true); httpProvider = new HTTPMetadataProvider(timer, httpClient, metadataURL); - httpProvider.setParserPool(new BasicParserPool()); + httpProvider.setParserPool(pool); httpProvider.setRequireValidMetadata(true); httpProvider.setMinRefreshDelay(1000*60*15); //15 minutes httpProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours @@ -115,7 +222,7 @@ public abstract class SimpleMOAMetadataProvider implements MetadataProvider{ + metadataURL + " FAILED.", e); } - Logger.error( + Logger.warn( "Failed to load Metadata file for " + IdForLogging + "[ " + e.getMessage() + " ]", e); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java index df4866c30..af9ba0180 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/signer/AbstractCredentialProvider.java @@ -200,7 +200,7 @@ public abstract class AbstractCredentialProvider { signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256); } else if (privatekey instanceof ECPrivateKey) { - signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA1); + signer.setSignatureAlgorithm(SignatureConstants.ALGO_ID_SIGNATURE_ECDSA_SHA256); } else { Logger.warn("Could NOT evaluate the Private-Key type from " + credentials.getEntityId() + " credential."); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java index 2ded32bac..d05d180e1 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/verification/EntityVerifier.java @@ -55,6 +55,12 @@ public class EntityVerifier { try { IOAAuthParameters oa = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(entityID); + if (oa == null) { + Logger.debug("No OnlineApplication with EntityID: " + entityID); + return null; + + } + String certBase64 = oa.getConfigurationValue(MOAIDConfigurationConstants.SERVICE_PROTOCOLS_PVP2X_CERTIFICATE); if (MiscUtil.isNotEmpty(certBase64)) { return Base64Utils.decode(certBase64, false); diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/util/ECDSAKeyValueConverter.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/util/ECDSAKeyValueConverter.java index f37ae0b0b..d30ce4924 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/util/ECDSAKeyValueConverter.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/util/ECDSAKeyValueConverter.java @@ -44,9 +44,9 @@ import iaik.security.ec.common.ECParameterSpec; import iaik.security.ec.common.ECPublicKey; import iaik.security.ec.common.ECStandardizedParameterFactory; import iaik.security.ec.common.EllipticCurve; +import iaik.security.ec.math.field.AbstractPrimeField; import iaik.security.ec.math.field.Field; import iaik.security.ec.math.field.FieldElement; -import iaik.security.ec.math.field.PrimeField; public class ECDSAKeyValueConverter { @@ -221,7 +221,7 @@ public class ECDSAKeyValueConverter // Value xValue = FieldFactory.getInstance().getPrimeFieldValue(new BigInteger(publicKeyXStr, 10)); // publicKeyPointX = field.newElement(xValue); - PrimeField pf = (PrimeField) field; + AbstractPrimeField pf = (AbstractPrimeField) field; publicKeyPointX = pf.newElement(new BigInteger(publicKeyXStr, 10)); // Value yValue = FieldFactory.getInstance().getPrimeFieldValue(new BigInteger(publicKeyYStr, 10)); // publicKeyPointY = field.newElement(yValue); diff --git a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties index 1a2f0d1d3..50b2c5ece 100644 --- a/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties +++ b/id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties @@ -53,7 +53,7 @@ auth.32=Federated authentication FAILED. No configuration for IDP {0} auth.33=Federated authentication FAILED. Configuration of IDP {0} does not allow inbound messages.
auth.34=Federated authentication FAILED. Configuration of IDP {0} is marked as BusinessService-IDP, but Public-Service attributes are requested.
-init.00=MOA ID Authentisierung wurde erfolgreich gestartet
+init.00=MOA-ID-Auth wurde erfolgreich gestartet
init.01=Fehler beim Aktivieren des IAIK-JCE/JSSE/JDK1.3 Workaround\: SSL ist m\u00F6glicherweise nicht verf\u00FCgbar
init.02=Fehler beim Starten des Service MOA-ID-Auth
init.04=Fehler beim Datenbankzugriff mit der SessionID {0}
diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDAuthConstants.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDAuthConstants.java index 8d893be9d..b16941f51 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDAuthConstants.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/MOAIDAuthConstants.java @@ -181,6 +181,7 @@ public class MOAIDAuthConstants extends MOAIDConstants{ public static final String PROCESSCONTEXT_REQUIRELOCALAUTHENTICATION = "requireLocalAuthentication"; public static final String PROCESSCONTEXT_PERFORM_BKUSELECTION = "performBKUSelection"; public static final String PROCESSCONTEXT_ISLEGACYREQUEST = "isLegacyRequest"; + public static final String PROCESSCONTEXT_UNIQUE_OA_IDENTFIER = "uniqueSPId"; //General protocol-request data-store keys public static final String AUTHPROCESS_DATA_TARGET = "authProces_Target"; @@ -189,5 +190,5 @@ public class MOAIDAuthConstants extends MOAIDConstants{ //General MOASession data-store keys public static final String MOASESSION_DATA_HOLDEROFKEY_CERTIFICATE = "holderofkey_cert"; - + } diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/AuthConfiguration.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/AuthConfiguration.java index fcf4c3ffa..07b07d980 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/AuthConfiguration.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/AuthConfiguration.java @@ -16,7 +16,8 @@ public interface AuthConfiguration extends ConfigurationProvider{ public static final String DEFAULT_X509_CHAININGMODE = "pkix"; - + public static final int CONFIG_PROPS_METADATA_SOCKED_TIMEOUT = 20 * 1000; //20 seconds metadata socked timeout + public Properties getGeneralPVP2ProperiesConfig(); @@ -46,6 +47,16 @@ public interface AuthConfiguration extends ConfigurationProvider{ */ public String getBasicMOAIDConfiguration(final String key, final String defaultValue); + /** + * Get a set of configuration values from basic file based MOA-ID configuration that starts with this prefix + * <br><br> + * <b>Important:</b> The configuration values must be of type String! + * + * @param prefix Prefix of the configuration key + * @return Map<String, String> without prefix, but never null + */ + public Map<String, String> getBasicMOAIDConfigurationWithPrefix(final String prefix); + public int getTransactionTimeOut(); public int getSSOCreatedTimeOut(); public int getSSOUpdatedTimeOut(); diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/IOAAuthParameters.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/IOAAuthParameters.java index 1aea8d7b6..bba6d0541 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/IOAAuthParameters.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/api/IOAAuthParameters.java @@ -42,6 +42,8 @@ public interface IOAAuthParameters { public static final String HANDYBKU = "handy"; public static final String LOCALBKU = "local"; public static final String INDERFEDERATEDIDP = "interfederated"; + public static final String EIDAS = "eIDAS"; + public static final String AUTHTYPE_OTHERS = "others"; /** * Get the full key/value configuration for this online application diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/KeyValueUtils.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/KeyValueUtils.java index bc567e5d2..40ef5a23a 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/KeyValueUtils.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/id/commons/utils/KeyValueUtils.java @@ -29,6 +29,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Properties; import java.util.Set; import org.apache.commons.lang3.StringUtils; @@ -45,6 +46,27 @@ public class KeyValueUtils { public static final String CSV_DELIMITER = ","; /** + * Convert Java properties into a Map<String, String> + * <br><br> + * <b>Important:</b> The key/values from properties must be of type String! + * + * @param properties + * @return + */ + public static Map<String, String> concertPropertiesToMap(Properties properties) { + return new HashMap<String, String>((Map) properties); + + //INFO Java8 solution ;) + // return properties.entrySet().stream().collect( +// Collectors.toMap( +// e -> e.getKey().toString(), +// e -> e.getValue().toString() +// ) +// ); + + } + + /** * Extract the first child of an input key after a the prefix * * @param key Full input key diff --git a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java index 129478270..2a4e3b362 100644 --- a/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java +++ b/id/server/moa-id-commons/src/main/java/at/gv/egovernment/moa/util/Constants.java @@ -394,6 +394,12 @@ public interface Constants { public static final String SAML2_METADATA_SCHEMA_LOCATION = SCHEMA_ROOT + "saml-schema-metadata-2.0.xsd"; + + /* Prefix and Schema definition for eIDAS specific SAML2 extensions*/ + public static final String SAML2_eIDAS_EXTENSIONS_PREFIX = "eidas"; + public static final String SAML2_eIDAS_EXTENSIONS = "http://eidas.europa.eu/saml-extensions"; + public static final String SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION = SCHEMA_ROOT + "eIDAS_saml_extensions.xsd"; + /** * Contains all namespaces and local schema locations for XML schema * definitions relevant for MOA. For use in validating XML parsers. @@ -427,7 +433,8 @@ public interface Constants { + (STORK_NS_URI + " " + STORK_SCHEMA_LOCATION + " ") + (STORKP_NS_URI + " " + STORKP_SCHEMA_LOCATION + " ") + (SAML2_METADATA_URI + " " + SAML2_METADATA_SCHEMA_LOCATION + " ") - + (XENC_NS_URI + " " + XENC_SCHEMA_LOCATION); + + (XENC_NS_URI + " " + XENC_SCHEMA_LOCATION) + + (SAML2_eIDAS_EXTENSIONS + " " + SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION); /** URN prefix for bPK and wbPK. */ public static final String URN_PREFIX = "urn:publicid:gv.at"; diff --git a/id/server/moa-id-commons/src/main/resources/resources/schemas/eIDAS_saml_extensions.xsd b/id/server/moa-id-commons/src/main/resources/resources/schemas/eIDAS_saml_extensions.xsd new file mode 100644 index 000000000..76b82a267 --- /dev/null +++ b/id/server/moa-id-commons/src/main/resources/resources/schemas/eIDAS_saml_extensions.xsd @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:eidas="http://eidas.europa.eu/saml-extensions" targetNamespace="http://eidas.europa.eu/saml-extensions" elementFormDefault="qualified" attributeFormDefault="unqualified"> + + <xsd:element name="SPType" type="eidas:SPTypeType"/> + <xsd:simpleType name="SPTypeType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="public"/> + <xsd:enumeration value="private"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:element name="RequestedAttributes" type="eidas:RequestedAttributesType"/> + <xsd:complexType name="RequestedAttributesType"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" ref="eidas:RequestedAttribute"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="RequestedAttribute" type="eidas:RequestedAttributeType"/> + <xsd:complexType name="RequestedAttributeType"> + <xsd:sequence> + <xsd:element name="AttributeValue" minOccurs="0" maxOccurs="unbounded" type="xsd:anyType"/> + </xsd:sequence> + <xsd:attribute name="Name" type="xsd:string" use="required"/> + <xsd:attribute name="NameFormat" type="xsd:anyURI" use="required" /> + <xsd:attribute name="isRequired" type="xsd:boolean" use="required"/> + <xsd:attribute name="FriendlyName" type="xsd:string" use="optional"/> + <xsd:anyAttribute namespace="##other" processContents="lax" /> + </xsd:complexType> + +</xsd:schema> diff --git a/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html new file mode 100644 index 000000000..54dc9d910 --- /dev/null +++ b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetect.html @@ -0,0 +1,32 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="de"> +<head> +<title>BKU-Erkennung</title> +<script type="text/javascript"> +<!-- + bkuprot = location.protocol; + bkuhost = "localhost"; + bkuport = (bkuprot == "https:" ? 3496 : 3495); + bkupath = "https-security-layer-request"; + bkuurl = bkuprot + "//" + bkuhost + ":" + bkuport + "/" + bkupath; + baseurl = location.href.substr(0, location.href.lastIndexOf("/")); +//--> +</script> +</head> +<body style="background-color:transparent"> +<script type="text/javascript"> +<!-- + if (bkuprot == "https:" || bkuprot == "http:") { + parent.setBKUAvailable(false); + document.write('<form name="bkudetectform" method="POST" target="bkudetect" action="' + bkuurl + '" enctype="application/x-www-form-urlencoded">'); + document.write('<input type="hidden" name="XMLRequest" value="<?xml version="1.0" encoding="UTF-8"?><NullOperationRequest xmlns="http://www.buergerkarte.at/namespaces/securitylayer/1.2#"/>" />'); + document.write('<input type="hidden" name="RedirectURL" value="' + baseurl + '/iframeLBKUdetected.html"/>'); + document.write('</form>'); + try { + document.bkudetectform.submit(); + } catch(e) {} + } +//--> +</script> +</body> +</html> diff --git a/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html new file mode 100644 index 000000000..8769c38ad --- /dev/null +++ b/id/server/moa-id-frontend-resources/src/main/resources/mainGUI/iframeLBKUdetected.html @@ -0,0 +1,14 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html lang="de"> +<head> +<title>BKU-Erkennung</title> +<script type="text/javascript"> + parent.setBKUAvailable(true); +</script> +</head> +<body style="background-color:transparent"> +<script type="text/javascript"> + parent.setBKUAvailable(true); +</script> +</body> +</html> diff --git a/id/server/moa-id-frontend-resources/src/main/resources/templates/css_template.css b/id/server/moa-id-frontend-resources/src/main/resources/templates/css_template.css index a334b258d..691166911 100644 --- a/id/server/moa-id-frontend-resources/src/main/resources/templates/css_template.css +++ b/id/server/moa-id-frontend-resources/src/main/resources/templates/css_template.css @@ -23,7 +23,7 @@ /*border-radius: 5px;*/ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit]{ font-size: 0.85em; /*border-radius: 7px;*/ margin-bottom: 25px; @@ -171,7 +171,7 @@ /* border-radius: 5px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit]{ font-size: 0.7em; min-width: 55px; /*min-height: 1.1em; @@ -210,7 +210,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.75em; min-width: 60px; /* min-height: 0.95em; @@ -248,7 +248,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.85em; /* min-height: 1.05em; border-radius: 7px; */ @@ -280,7 +280,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 0.9em; /* min-height: 1.2em; border-radius: 8px; */ @@ -313,7 +313,7 @@ /* border-radius: 6px; */ } - #bkuselectionarea input[type=button] { + #bkuselectionarea input[type=button],#bkuselectionarea input[type=submit] { font-size: 1.0em; /* min-height: 1.3em; border-radius: 10px; */ @@ -423,7 +423,7 @@ height: 25px; } - input[type=button] { + input[type=button],input[type=submit] { /* height: 11%; */ width: 70%; } @@ -464,9 +464,14 @@ text-align: right; } + #ssoSessionTransferBlock { + clear: both; + } + #stork { /*margin-bottom: 10px;*/ /* margin-top: 5px; */ + clear: both; } #mandateLogin { @@ -520,8 +525,9 @@ } .bkuimage { - width: 70%; + width: 60%; height: auto; + margin-bottom: 10%; } #mandate{ diff --git a/id/server/moa-id-frontend-resources/src/main/resources/templates/javascript_tempalte.js b/id/server/moa-id-frontend-resources/src/main/resources/templates/javascript_tempalte.js index a463bae65..0c1f6a561 100644 --- a/id/server/moa-id-frontend-resources/src/main/resources/templates/javascript_tempalte.js +++ b/id/server/moa-id-frontend-resources/src/main/resources/templates/javascript_tempalte.js @@ -33,7 +33,11 @@ function isIE() { function bkuOnlineClicked() { if (isMetro()) document.getElementById("metroDetected").style.display="block"; - document.getElementById("localBKU").style.display="block"; + + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="block"; + /* if (checkMandateSSO()) return; */ @@ -49,7 +53,10 @@ function isIE() { generateIFrame(iFrameURL); } function bkuHandyClicked() { - document.getElementById("localBKU").style.display="none"; + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="block"; + /* if (checkMandateSSO()) return; */ @@ -65,7 +72,10 @@ function isIE() { generateIFrame(iFrameURL); } function storkClicked() { - document.getElementById("localBKU").style.display="none"; + var localBkuEl = document.getElementById("localBKU"); + if (localBkuEl) + localBkuEl.style.display="none"; + /* if (checkMandateSSO()) return; */ @@ -129,12 +139,14 @@ function isIE() { console.log("Browser is Chrome: "+checkIfBrowserIsChrome()); console.log("Browser is Safari: "+checkIfBrowserIsSafari()); console.log("Browser is Edge: "+checkIfBrowserIsEdge()); + console.log("Browser is Firefox(>51): " +checkIfBrowserIsFirefox()) var cnt = 0; if(checkIfBrowserIsChrome())cnt++; if(checkIfBrowserIsEdge())cnt++; if(checkIfBrowserIsSafari())cnt++; + if(checkIfBrowserIsFirefox())cnt++; if(cnt==0 || cnt>1)//cnt>1 means perhaps wrong detection return true; @@ -149,11 +161,25 @@ function isIE() { var button = document.getElementsByName("bkuButtonOnline")[0]; button.setAttribute("class","browserInfoButton"); button.setAttribute("title","Java wird nicht unterstützt, klicken für mehr Informationen."); - button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von Firefox und MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); + button.setAttribute("onClick","alert('Java wird von Ihrem Browser nicht unterstützt, ist jedoch für den Betrieb der Online Bürgerkartenumgebung notwendig.\\nWollen Sie dennoch die Online Bürgerkartenumgebung verwenden, wird zur Zeit Java noch von MS Internet Explorer unterstützt. \\nAlternativ koennen Sie auch eine lokale Bürgerkartenumgebung verwenden, verfügbar unter www.buergerkarte.at.');"); return false; } + function checkIfBrowserIsFirefox() { + var firefoxMarkerPos = navigator.userAgent.toLowerCase().indexOf('firefox'); + if (firefoxMarkerPos > -1) { + if (navigator.userAgent.toLowerCase().length >= (firefoxMarkerPos + 'firefox/'.length)) { + var ffversion = navigator.userAgent.toLowerCase().substring(firefoxMarkerPos + 8); + if (ffversion > 51) { + return true; + } + } else { + console.log("Browser looks like Firefox but has suspect userAgent string: " + navigator.userAgent.toLowerCase()); + } + } + return false; + } function checkIfBrowserIsChrome(){ var chrome_defined = !!window.chrome;//chrome object defined var webstore_defined = false; @@ -173,7 +199,44 @@ function isIE() { function checkIfBrowserIsSafari(){ var cond1 = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0; return cond1; - } + } + function setBKUAvailable(available) { + //login = document.getElementById("localBKU"); + //active = (login.className.indexOf("lokalebkuaktiv") != -1); + try { + if (available) { + console.log("Local BKU available") + //login.className = login.className.replace("lokalebkuinaktiv", "lokalebkuaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.removeAttribute("class");; + button.setAttribute("title","Bürgerkarte mit localer Bürgerkartenumgebung."); + + var image = document.getElementById("bkuimage"); + var srcatt = image.getAttribute("src"); + var last = srcatt.substring(srcatt.lastIndexOf('/')+1); + srcatt = srcatt.replace(last,'karte.png'); + image.setAttribute("src",srcatt); + + } else if (!available) { + //login.className = login.className.replace("lokalebkuaktiv", "lokalebkuinaktiv"); + var localBKUForm = document.getElementById("moaidform"); + var button = localBKUForm.getElementsByTagName("input")[5]; + button.setAttribute("class","browserInfoButton"); + button.setAttribute("title","Es wurde keine Bürgerkartenumgebung gefunden. Sollte es sich hierbei um einen Fehler handeln können Sie den Prozess durch einen Klick auf den Button denoch fortsetzen."); + + var image = document.getElementById("bkuimage"); + var srcatt = image.getAttribute("src"); + var last = srcatt.substring(srcatt.lastIndexOf('/')+1); + srcatt = srcatt.replace(last,'karte_deactivated.png'); + image.setAttribute("src",srcatt); + + console.log("Local BKU NOT available") + } + } catch(e) {console.log("Local BKU detection is not possible! Msg: "+e);} + + } + /* function setSSOSelection() { document.getElementById("useSSO").value = "false"; var checkbox = document.getElementById("SSOCheckBox"); diff --git a/id/server/moa-id-frontend-resources/src/main/resources/templates/loginFormFull.html b/id/server/moa-id-frontend-resources/src/main/resources/templates/loginFormFull.html index 32f0a7d4d..53c4f0d5d 100644 --- a/id/server/moa-id-frontend-resources/src/main/resources/templates/loginFormFull.html +++ b/id/server/moa-id-frontend-resources/src/main/resources/templates/loginFormFull.html @@ -12,7 +12,8 @@ <title>Anmeldung mittels Bürgerkarte oder Handy-Signatur</title> </head> -<body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"> +<!--body onload="onChangeChecks();checkIfBrowserSupportsJava();" onresize="onChangeChecks();"--> +<body onload="onChangeChecks();" onresize="onChangeChecks();"> <div id="page"> <div id="page1" class="case selected-case" role="main"> <h2 class="OA_header" role="heading">Anmeldung an: $OAName</h2> @@ -37,19 +38,28 @@ </div> <div id="bkuselectionarea"> <div id="bkukarte"> - <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" - alt="OnlineBKU" /> <input name="bkuButtonOnline" type="button" - onClick="bkuOnlineClicked();" tabindex="2" role="button" - value="Karte" /> + <img id="bkuimage" class="bkuimage" src="$contextPath/img/karte.png" alt="OnlineBKU" /> + + <!-- Remove support for Online BKU and swith the card button to local BKU--> + <!--input name="bkuButtonOnline" type="button" onClick="bkuOnlineClicked();" tabindex="2" role="button" value="Karte" /--> + + <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> + <input type="hidden" name="bkuURI" value="$bkuLocal" /> + <input type="hidden" name="useMandate" id="useMandate" /> + <input type="hidden" name="SSO" id="useSSO" /> + <input type="hidden" name="ccc" id="ccc" /> + <input type="hidden" name="pendingid" value="$pendingReqID" /> + <input type="submit" value=" Karte " tabindex="4" role="button" onclick="setMandateSelection();"> + </form> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"></iframe> + </div> <div id="bkuhandy"> - <img class="bkuimage" src="$contextPath/img/handysign.png" - alt="HandyBKU" /> <input name="bkuButtonHandy" type="button" - onClick="bkuHandyClicked();" tabindex="3" role="button" - value="HANDY" /> + <img class="bkuimage" src="$contextPath/img/handysign.png" alt="HandyBKU" /> + <input name="bkuButtonHandy" type="button" onClick="bkuHandyClicked();" tabindex="3" role="button" value="HANDY" /> </div> </div> - <div id="localBKU"> + <!--div id="localBKU"> <form method="get" id="moaidform" action="$contextPath$submitEndpoint" class="verticalcenter" target="_parent"> <input type="hidden" name="bkuURI" value="$bkuLocal" /> @@ -60,7 +70,8 @@ <input type="submit" value=" Lokale Bürgerkartenumgebung " tabindex="4" role="button" onclick="setMandateSelection();"> </form> - </div> + <iframe name="bkudetect" width="0" height="0" scrolling="no" marginheight="0" marginwidth="0" frameborder="0" src="$contextPath/iframeLBKUdetect.html"><\/iframe> + </div--> <!-- Single Sign-On Session transfer functionality --> <!--div id="ssoSessionTransferBlock"> diff --git a/id/server/moa-id-spring-initializer/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthSpringInitializer.java b/id/server/moa-id-spring-initializer/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthSpringInitializer.java index 07ba6a89e..b6fd8de8e 100644 --- a/id/server/moa-id-spring-initializer/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthSpringInitializer.java +++ b/id/server/moa-id-spring-initializer/src/main/java/at/gv/egovernment/moa/id/auth/MOAIDAuthSpringInitializer.java @@ -1,5 +1,8 @@ package at.gv.egovernment.moa.id.auth; +import java.util.Map; +import java.util.Map.Entry; + import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; @@ -147,8 +150,19 @@ public class MOAIDAuthSpringInitializer implements WebApplicationInitializer { // servletContext.addFilter("vHost RequestFilter", new VHostUrlRewriteServletFilter(rootContext)) // .addMappingForUrlPatterns(null, false, "/*"); - Logger.info("Basic Context initalisation finished --> Start MOA-ID-Auth initialisation process ..."); + Logger.info("Basic Context initalisation finished --> Start MOA-ID-Auth initialization process ..."); MOAIDAuthInitializer.initialize(rootContext); + + + //initialize object that implements the IPostStartupInitializeable interface + Map<String, IPostStartupInitializable> objForInitialization = rootContext.getBeansOfType(IPostStartupInitializable.class); + for (Entry<String, IPostStartupInitializable> el : objForInitialization.entrySet()) { + Logger.debug("Starting post start-up initialization of '" + el.getKey() + "' ..." ); + el.getValue().executeAfterStartup(); + Logger.info("Post start-up initialization of '" + el.getKey() + "' finished." ); + + } + Logger.info(MOAIDMessageProvider.getInstance().getMessage( "init.00", null)); Logger.info("MOA-ID-Auth initialization finished."); diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/pom.xml b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/pom.xml new file mode 100644 index 000000000..0db2b26a8 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/pom.xml @@ -0,0 +1,10 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>MOA.id.server.modules</groupId> + <artifactId>moa-id-modules</artifactId> + <version>${moa-id-version}</version> + </parent> + <artifactId>moa-id-module-bkaMobilaAuthSAML2Test</artifactId> + <description>BKA MobileAuth Test for SAML2 applications</description> +</project>
\ No newline at end of file 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 new file mode 100644 index 000000000..44554e21d --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthModule.java @@ -0,0 +1,106 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.springframework.beans.factory.annotation.Autowired; + +import at.gv.egovernment.moa.id.auth.modules.AuthModule; +import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; +import at.gv.egovernment.moa.id.commons.utils.KeyValueUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class BKAMobileAuthModule implements AuthModule { + + private int priority = 1; + + @Autowired protected AuthConfiguration authConfig; + + private List<String> uniqueIDsDummyAuthEnabled = new ArrayList<String>(); + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getPriority() + */ + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + + @PostConstruct + public void initialDummyAuthWhiteList() { + String sensitiveSpIdentifier = authConfig.getBasicMOAIDConfiguration("modules.bkamobileAuth.entityID"); + if (MiscUtil.isNotEmpty(sensitiveSpIdentifier)) { + uniqueIDsDummyAuthEnabled.addAll(KeyValueUtils.getListOfCSVValues(sensitiveSpIdentifier)); + + if (!uniqueIDsDummyAuthEnabled.isEmpty()) { + Logger.info("Dummy authentication is enabled for ...."); + for (String el : uniqueIDsDummyAuthEnabled) + Logger.info(" EntityID: " + el); + } + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#selectProcess(at.gv.egovernment.moa.id.process.api.ExecutionContext) + */ + @Override + public String selectProcess(ExecutionContext context) { + String spEntityID = (String) context.get(MOAIDAuthConstants.PROCESSCONTEXT_UNIQUE_OA_IDENTFIER); + if (MiscUtil.isNotEmpty(spEntityID)) { + if (uniqueIDsDummyAuthEnabled.contains(spEntityID)) + return "BKAMobileAuthentication"; + + } + + return null; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AuthModule#getProcessDefinitions() + */ + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:/BKAMobileAuth.process.xml" }; + } + +} diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthSpringResourceProvider.java b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthSpringResourceProvider.java new file mode 100644 index 000000000..884129453 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/BKAMobileAuthSpringResourceProvider.java @@ -0,0 +1,62 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests; + +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; + +import at.gv.egiz.components.spring.api.SpringResourceProvider; + +/** + * @author tlenz + * + */ +public class BKAMobileAuthSpringResourceProvider implements SpringResourceProvider { + + /* (non-Javadoc) + * @see at.gv.egiz.components.spring.api.SpringResourceProvider#getResourcesToLoad() + */ + @Override + public Resource[] getResourcesToLoad() { + ClassPathResource authConfig = new ClassPathResource("/moaid_bka_mobileauth.beans.xml", BKAMobileAuthSpringResourceProvider.class); + return new Resource[] {authConfig}; + } + + /* (non-Javadoc) + * @see at.gv.egiz.components.spring.api.SpringResourceProvider#getPackagesToScan() + */ + @Override + public String[] getPackagesToScan() { + // TODO Auto-generated method stub + return null; + } + + /* (non-Javadoc) + * @see at.gv.egiz.components.spring.api.SpringResourceProvider#getName() + */ + @Override + public String getName() { + return "BKA MobileAuth SAML2 Test"; + } + +} 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 new file mode 100644 index 000000000..66112edc5 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/FirstBKAMobileAuthTask.java @@ -0,0 +1,56 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.tasks; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Component; + +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.servlet.GeneralProcessEngineSignalController; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.logging.Logger; + + +/** + * @author tlenz + * + */ +@Component("FirstBKAMobileAuthTask") +public class FirstBKAMobileAuthTask extends AbstractAuthServletTask { + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + Logger.info("Redirect to Second BKA Mobile Auth task"); + performRedirectToItself(pendingReq, response, GeneralProcessEngineSignalController.ENDPOINT_GENERIC); + + } + +} diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/SecondBKAMobileAuthTask.java b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/SecondBKAMobileAuthTask.java new file mode 100644 index 000000000..4b18e7112 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/java/at/gv/egovernment/moa/id/auth/modules/bkamobileauthtests/tasks/SecondBKAMobileAuthTask.java @@ -0,0 +1,104 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.tasks; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.springframework.stereotype.Component; + +import at.gv.egovernment.moa.id.auth.exception.ParseException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.commons.api.IRequest; +import at.gv.egovernment.moa.id.commons.api.data.IAuthenticationSession; +import at.gv.egovernment.moa.id.commons.api.data.IIdentityLink; +import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; + +/** + * @author tlenz + * + */ +@Component("SecondBKAMobileAuthTask") +public class SecondBKAMobileAuthTask extends AbstractAuthServletTask { + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + + try { + Logger.info("Add user credentials for BKA MobileAuth SAML2 test and finalize authentication"); + parseDemoValuesIntoMOASession(pendingReq, pendingReq.getMOASession()); + + // store MOASession into database + requestStoreage.storePendingRequest(pendingReq); + + } catch (MOAIDException e) { + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } catch (Exception e) { + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + } + + /** + * @param pendingReq + * @param moaSession + * @throws MOAIDException + */ + private void parseDemoValuesIntoMOASession(IRequest pendingReq, IAuthenticationSession moaSession) throws MOAIDException { + moaSession.setUseMandates(false); + moaSession.setForeigner(false); + + moaSession.setBkuURL("http://egiz.gv.at/BKA_MobileAuthTest"); + moaSession.setQAALevel(PVPConstants.STORK_QAA_1_4); + + try { + String idlurl = FileUtils.makeAbsoluteURL(authConfig.getMonitoringTestIdentityLinkURL(), authConfig.getRootConfigFileDir()); + URL keystoreURL = new URL(idlurl); + InputStream idlstream = keystoreURL.openStream(); + IIdentityLink identityLink = new IdentityLinkAssertionParser(idlstream).parseIdentityLink(); + moaSession.setIdentityLink(identityLink); + + } catch (ParseException | IOException e) { + Logger.error("IdentityLink is not parseable.", e); + throw new MOAIDException("IdentityLink is not parseable.", null); + + } + + } + +} 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 new file mode 100644 index 000000000..4a0f4d5f2 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/BKAMobileAuth.process.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="UTF-8"?> +<pd:ProcessDefinition id="BKAMobileAuthentication" xmlns:pd="http://reference.e-government.gv.at/namespace/moa/process/definition/v1"> + +<!-- + STORK authentication both with C-PEPS supporting xml signatures and with C-PEPS not supporting xml signatures. +--> + <pd:Task id="firstStep" class="FirstBKAMobileAuthTask" /> + <pd:Task id="secondStep" class="SecondBKAMobileAuthTask" async="true" /> + <pd:Task id="finalizeAuthentication" class="FinalizeAuthenticationTask" /> + + <!-- Process is triggered either by GenerateIFrameTemplateServlet (upon bku selection) or by AuthenticationManager (upon legacy authentication start using legacy parameters. --> + <pd:StartEvent id="start" /> + + <pd:Transition from="start" to="firstStep" /> + <pd:Transition from="firstStep" to="secondStep"/> + <pd:Transition from="secondStep" to="finalizeAuthentication" /> + + <pd:Transition from="finalizeAuthentication" to="end" /> + + <pd:EndEvent id="end" /> + +</pd:ProcessDefinition> diff --git a/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider new file mode 100644 index 000000000..42dbf09e7 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/META-INF/services/at.gv.egiz.components.spring.api.SpringResourceProvider @@ -0,0 +1 @@ +at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.BKAMobileAuthSpringResourceProvider
\ No newline at end of file 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 new file mode 100644 index 000000000..ef13b0348 --- /dev/null +++ b/id/server/modules/moa-id-module-bkaMobilaAuthSAML2Test/src/main/resources/moaid_bka_mobileauth.beans.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8"?> +<beans xmlns="http://www.springframework.org/schema/beans" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xmlns:context="http://www.springframework.org/schema/context" + xmlns:tx="http://www.springframework.org/schema/tx" + xmlns:aop="http://www.springframework.org/schema/aop" + xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd + http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd + http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd + http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd"> + + <bean id="BKAMobileAuthModule" class="at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.BKAMobileAuthModule"> + <property name="priority" value="1" /> + </bean> + + + <bean id="FirstBKAMobileAuthTask" + class="at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.tasks.FirstBKAMobileAuthTask" + scope="prototype"/> + + <bean id="SecondBKAMobileAuthTask" + class="at.gv.egovernment.moa.id.auth.modules.bkamobileauthtests.tasks.SecondBKAMobileAuthTask" + scope="prototype"/> + +</beans>
\ No newline at end of file diff --git a/id/server/modules/moa-id-module-eIDAS/pom.xml b/id/server/modules/moa-id-module-eIDAS/pom.xml index 55d02e82a..f3d8eeb36 100644 --- a/id/server/modules/moa-id-module-eIDAS/pom.xml +++ b/id/server/modules/moa-id-module-eIDAS/pom.xml @@ -12,11 +12,11 @@ <properties> <repositoryPath>${basedir}/../../../../repository</repositoryPath> - <eidas-commons.version>1.2.0</eidas-commons.version> - <eidas-light-commons.version>1.2.0</eidas-light-commons.version> - <eidas-saml-engine.version>1.2.0</eidas-saml-engine.version> - <eidas-encryption.version>1.2.0</eidas-encryption.version> - <eidas-configmodule.version>1.2.0</eidas-configmodule.version> + <eidas-commons.version>1.4.0-SNAPSHOT</eidas-commons.version> + <eidas-light-commons.version>1.4.0-SNAPSHOT</eidas-light-commons.version> + <eidas-saml-engine.version>1.4.0-SNAPSHOT</eidas-saml-engine.version> + <eidas-encryption.version>1.4.0-SNAPSHOT</eidas-encryption.version> + <eidas-configmodule.version>1.4.0-SNAPSHOT</eidas-configmodule.version> </properties> diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java index 369d77863..c0101b553 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/Constants.java @@ -25,10 +25,6 @@ package at.gv.egovernment.moa.id.auth.modules.eidas; import org.apache.xml.security.signature.XMLSignature; import org.opensaml.xml.encryption.EncryptionConstants; import org.opensaml.xml.signature.SignatureConstants; -//import eu.eidas.auth.engine.core.validator.eidas.EIDASAttributes; - -import eu.eidas.auth.commons.attribute.AttributeRegistries; -import eu.eidas.auth.commons.attribute.AttributeRegistry; /** * @author tlenz @@ -61,17 +57,23 @@ public class Constants { public static final String CONIG_PROPS_EIDAS_SAMLENGINE_SIGN_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." + CONIG_PROPS_EIDAS_SAMLENGINE_SIGN + ".config.file"; public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ENC_CONFIGFILE = CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + "." - + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + + CONIG_PROPS_EIDAS_SAMLENGINE_ENCRYPT + ".config.file"; + public static final String CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS = + CONIG_PROPS_EIDAS_SAMLENGINE_PREFIX + ".attributes.addition.config"; public static final String CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE = CONIG_PROPS_EIDAS_PREFIX + ".metadata.validation.truststore"; + public static final String CONIG_PROPS_EIDAS_NODE_COUNTRYCODE = CONIG_PROPS_EIDAS_NODE + ".countrycode"; public static final String CONIG_PROPS_EIDAS_NODE_COUNTRY = CONIG_PROPS_EIDAS_NODE + ".country"; - public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + public static final String CONIG_PROPS_EIDAS_NODE_LoA = CONIG_PROPS_EIDAS_NODE + ".LoA"; + + public static final String CONIG_PROPS_EIDAS_METADATA_URLS_LIST_PREFIX = CONIG_PROPS_EIDAS_PREFIX + ".metadata.url"; + //timeouts and clock skews - public static final int CONFIG_PROPS_SKEWTIME = 2 * 60 * 1000; //2 minutes skew time for response validation - public static final int CONFIG_PROPS_METADATA_SOCKED_TIMEOUT = 20 * 1000; //20 seconds metadata socked timeout + public static final long CONFIG_PROPS_SKEWTIME_BEFORE = -2 * 60 * 1000; //5 minutes skew time for response validation + public static final long CONFIG_PROPS_SKEWTIME_AFTER = 2 * 60 * 1000; //5 minutes skew time for response validation public static final long CONFIG_PROPS_METADATA_GARBAGE_TIMEOUT = 7 * 24 * 60 * 60 * 1000; //remove unused eIDAS metadata after 7 days //eIDAS request parameters @@ -88,8 +90,6 @@ public class Constants { //http endpoint descriptions public static final String eIDAS_HTTP_ENDPOINT_SP_POST = "/eidas/sp/post"; public static final String eIDAS_HTTP_ENDPOINT_SP_REDIRECT = "/eidas/sp/redirect"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_POST = "/eidas/idp/post"; - //public static final String eIDAS_HTTP_ENDPOINT_IDP_REDIRECT = "/eidas/idp/redirect"; public static final String eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST = "/eidas/ColleagueRequest"; public static final String eIDAS_HTTP_ENDPOINT_METADATA = "/eidas/metadata"; @@ -99,38 +99,6 @@ public class Constants { public static final int eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST = 3401; public static final int eIDAS_REVERSIONSLOG_IDP_AUTHRESPONSE = 3402; - //metadata constants -// public final static Map<String, EidasAttributesTypes> METADATA_POSSIBLE_ATTRIBUTES = Collections.unmodifiableMap( -// new HashMap<String, EidasAttributesTypes>(){ -// private static final long serialVersionUID = 1L; -// { -// put(EIDASAttributes.ATTRIBUTE_GIVENNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_FIRSTNAME, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_DATEOFBIRTH, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// put(EIDASAttributes.ATTRIBUTE_PERSONIDENTIFIER, EidasAttributesTypes.NATURAL_PERSON_MANDATORY); -// -// //TODO: add additional attributes for eIDAS with mandates -// //put(EIDASAttributes.ATTRIBUTE_LEGALIDENTIFIER, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// //put(EIDASAttributes.ATTRIBUTE_LEGALNAME, EidasAttributesTypes.LEGAL_PERSON_MANDATORY); -// } -// } -// ); - - public static final AttributeRegistry NAT_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME, - eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH - ); - - public static final AttributeRegistry LEGAL_ATTR = - AttributeRegistries.of( eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER, - eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME - ); - - public static final AttributeRegistry MOA_IDP_ATTR_REGISTRY = - AttributeRegistries.copyOf(NAT_ATTR, LEGAL_ATTR); - public static final String METADATA_ALLOWED_ALG_DIGIST = SignatureConstants.ALGO_ID_DIGEST_SHA256 + ";" + diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java index e08d302f6..6a48e5030 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOAExtendedSWSigner.java @@ -98,8 +98,11 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { private final ImmutableList<X509Credential> trustedCredentials; private final String signatureAlgorithm; - public MOAExtendedSWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { - this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties)); + + //TODO: check if it is required any more + + public MOAExtendedSWSigner(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + this(new KeyStoreSignatureConfigurator().getSignatureConfiguration(properties, null)); } @@ -109,7 +112,7 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { */ public MOAExtendedSWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { this(new KeyStoreSignatureConfigurator().getSignatureConfiguration( - ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters())); + ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters(), null)); } @@ -226,7 +229,7 @@ public class MOAExtendedSWSigner implements ProtocolSignerI, MetadataSignerI { checkCertificateIssuer(credential.getEntityCertificate()); Signature signature; try { - Logger.debug("Creating an OpenSAML signature object"); + Logger.trace("Creating an OpenSAML signature object"); signature = (Signature) Configuration.getBuilderFactory().getBuilder(Signature.DEFAULT_ELEMENT_NAME) .buildObject(Signature.DEFAULT_ELEMENT_NAME); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java index 5cf5e83ec..3cc9787df 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/MOASWSigner.java @@ -79,8 +79,8 @@ public class MOASWSigner extends KeyStoreProtocolSigner { //Set other algorithms which are not supported by openSAML in default StringUtils.lowerCase(XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA256_MGF1, Locale.ENGLISH)); - public MOASWSigner(Map<String, String> properties) throws SamlEngineConfigurationException { - super(properties); + public MOASWSigner(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + super(properties, null); props = properties; } @@ -90,7 +90,7 @@ public class MOASWSigner extends KeyStoreProtocolSigner { * @throws SamlEngineConfigurationException */ public MOASWSigner(CertificateConfigurationManager configManager) throws SamlEngineConfigurationException { - super(props = ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters()); + super(props = ConfigurationAdapter.adapt(configManager).getInstances().get(Constants.eIDAS_SAML_ENGINE_NAME).getConfigurationEntries().get(ConfigurationKey.SIGNATURE_CONFIGURATION.getKey()).getParameters(), null); } @@ -100,7 +100,7 @@ public class MOASWSigner extends KeyStoreProtocolSigner { if (sigAlgWhiteList == null) { sigAlgWhiteList = MOAWhiteListConfigurator.getAllowedAlgorithms(DEFAULT_ALGORITHM_WHITE_LIST, ALLOWED_ALGORITHMS_FOR_VERIFYING, - (new KeyStoreSignatureConfigurator().getSignatureConfiguration(props)).getSignatureAlgorithmWhiteList()); + (new KeyStoreSignatureConfigurator().getSignatureConfiguration(props, null)).getSignatureAlgorithmWhiteList()); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java index de4f3fc9c..d5cbb2cfd 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/config/ModifiedEncryptionSW.java @@ -33,15 +33,15 @@ public class ModifiedEncryptionSW extends KeyStoreSamlEngineEncryption { private static ReloadableProperties initActivationConf(Map<String, String> properties) { String activationConfigurationFile = EncryptionKey.ENCRYPTION_ACTIVATION.getAsString(properties); Logger.debug("File containing encryption configuration: \"" + activationConfigurationFile + "\""); - return new ReloadableProperties(activationConfigurationFile); + return new ReloadableProperties(activationConfigurationFile, null); } /** * @param properties * @throws SamlEngineConfigurationException */ - public ModifiedEncryptionSW(Map<String, String> properties) throws SamlEngineConfigurationException { - super(properties); + public ModifiedEncryptionSW(Map<String, String> properties, String defaultConfigPath) throws SamlEngineConfigurationException { + super(properties, null); this.properties = ImmutableMap.copyOf(properties); encryptionActivationProperties = initActivationConf(properties); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java index c24c5efca..28d74075e 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAEidasProtocolProcesser.java @@ -22,7 +22,9 @@ */ package at.gv.egovernment.moa.id.auth.modules.eidas.engine; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.core.eidas.EidasProtocolProcessor; +import eu.eidas.auth.engine.core.eidas.spec.EidasSpec; import eu.eidas.auth.engine.metadata.MetadataFetcherI; import eu.eidas.auth.engine.metadata.MetadataSignerI; @@ -38,11 +40,14 @@ public class MOAEidasProtocolProcesser extends EidasProtocolProcessor { private final MetadataSignerI metadataSigner; /** - * @param metadataFetcher - * @param metadataSigner + * Build a MOA specific eIDAS-engine protocol processor + * + * @param metadataFetcher eIDAS-engine Metadata fetcher implementation + * @param metadataSigner eIDAS-engine Signer implementation + * @param addAttrDefinitions additinal eIDAS attributes */ - public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner) { - super(metadataFetcher, metadataSigner); + public MOAEidasProtocolProcesser(MetadataFetcherI metadataFetcher, MetadataSignerI metadataSigner, AttributeRegistry addAttrDefinitions) { + super(EidasSpec.REGISTRY, addAttrDefinitions, metadataFetcher, metadataSigner); this.metadataFetcher = metadataFetcher; this.metadataSigner = metadataSigner; @@ -53,5 +58,11 @@ public class MOAEidasProtocolProcesser extends EidasProtocolProcessor { public String getResponseValidatorId() { return OWN_EIDAS_RESPONSE_VALIDATOR_SUITE_ID; } - + + + public MetadataFetcherI getMetadataFetcher() { + return this.metadataFetcher; + } + + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java index d8fcd1694..f347022b8 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAProtocolEngine.java @@ -1,16 +1,17 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.engine; -import java.security.cert.X509Certificate; - -import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Response; +import org.w3c.dom.Document; import at.gv.egovernment.moa.logging.Logger; -import eu.eidas.auth.commons.EidasErrorKey; -import eu.eidas.auth.commons.protocol.IAuthenticationRequest; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.engine.Correlated; import eu.eidas.auth.engine.ProtocolEngine; import eu.eidas.auth.engine.configuration.ProtocolConfigurationAccessor; -import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; +import eu.eidas.auth.engine.core.ProtocolProcessorI; +import eu.eidas.auth.engine.metadata.MetadataFetcherI; +import eu.eidas.auth.engine.xml.opensaml.XmlSchemaUtil; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; public class MOAProtocolEngine extends ProtocolEngine { @@ -20,6 +21,98 @@ public class MOAProtocolEngine extends ProtocolEngine { } + /** + * Add SAML2 metadata refresh functionality if first validation failed + * + */ + @Override + public Correlated unmarshallResponse(byte[] responseBytes) throws EIDASSAMLEngineException { + try { + return super.unmarshallResponse(responseBytes); + + } catch (EIDASSAMLEngineException e) { + if (responseBytes != null ) { + Logger.info("eIDAS Response validation FAILED. Starting metadata reloading process ..."); + Document document = XmlSchemaUtil.validateSamlSchema(responseBytes); + Response response = (Response) unmarshall(document); + String entityID = response.getIssuer().getValue(); + + if (MiscUtil.isEmpty(entityID)) { + Logger.debug("eIDAS Response contains no EntityID."); + throw e; + + } + + if (startInternalMetadataRefesh(entityID)) { + Logger.debug("Metadata refresh success. Revalidate eIDAS Response ..."); + return super.unmarshallResponse(responseBytes); + + } + Logger.info("eIDAS metadata refresh not possible or not successful."); + + } + throw e; + + } + } + + /** + * Add SAML2 metadata refresh functionality if first validation failed + * + */ + @Override + public AuthnRequest unmarshallRequest(byte[] requestBytes) throws EIDASSAMLEngineException { + try { + return super.unmarshallRequest(requestBytes); + + + } catch (EIDASSAMLEngineException e) { + if (null != requestBytes) { + Logger.info("eIDAS Request validation FAILED. Starting metadata reloading process ..."); + Document document = XmlSchemaUtil.validateSamlSchema(requestBytes); + AuthnRequest request = (AuthnRequest) unmarshall(document); + String entityID = request.getIssuer().getValue(); + + if (MiscUtil.isEmpty(entityID)) { + Logger.debug("eIDAS Authn. Request contains no EntityID."); + throw e; + + } + + if (startInternalMetadataRefesh(entityID)) { + Logger.debug("Metadata refresh success. Revalidate eIDAS Authn. Request ..."); + return super.unmarshallRequest(requestBytes); + + } + + Logger.info("eIDAS metadata refresh not possible or not successful."); + } + + throw e; + + } + } + + /** + * Refresh SAML2 metadata if the internal metadata provider supports this functionality + * + * @param entityID + * @return true if refresh was success, otherwise false + */ + private boolean startInternalMetadataRefesh(String entityID) { + //check if eIDAS SAML-Engine implementation supports metadata refresh + ProtocolProcessorI protocolProcessor = this.getProtocolProcessor(); + if (protocolProcessor instanceof MOAEidasProtocolProcesser) { + MetadataFetcherI metadataFetcher = + ((MOAEidasProtocolProcesser)protocolProcessor).getMetadataFetcher(); + if (metadataFetcher instanceof MOAeIDASMetadataProviderDecorator) + return ((MOAeIDASMetadataProviderDecorator)metadataFetcher).refreshMetadata(entityID); + + } + + return false; + } + // @Override // protected X509Certificate getEncryptionCertificate(String requestIssuer, // String destinationCountryCode) throws EIDASSAMLEngineException { diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java index ffa74b92b..490dc9dcf 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASChainingMetadataProvider.java @@ -9,15 +9,13 @@ import java.util.Map; import java.util.Map.Entry; import java.util.Timer; -import javax.net.ssl.SSLHandshakeException; import javax.xml.namespace.QName; -import org.apache.commons.httpclient.MOAHttpClient; -import org.apache.commons.httpclient.params.HttpClientParams; import org.opensaml.saml2.metadata.EntitiesDescriptor; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.RoleDescriptor; import org.opensaml.saml2.metadata.provider.ChainingMetadataProvider; +import org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider; import org.opensaml.saml2.metadata.provider.HTTPMetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataFilter; import org.opensaml.saml2.metadata.provider.MetadataProvider; @@ -28,25 +26,22 @@ import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.IDestroyableObject; import at.gv.egovernment.moa.id.auth.IGarbageCollectorProcessing; +import at.gv.egovernment.moa.id.auth.IPostStartupInitializable; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; -import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; -import at.gv.egovernment.moa.id.commons.ex.MOAHttpProtocolSocketFactoryException; -import at.gv.egovernment.moa.id.commons.utils.MOAHttpProtocolSocketFactory; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SchemaValidationException; -import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.filter.SignatureValidationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IMOARefreshableMetadataProvider; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.SimpleMOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.MOASPMetadataSignatureFilter; import at.gv.egovernment.moa.id.saml2.MetadataFilterChain; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.engine.AbstractProtocolEngine; @Service("eIDASMetadataProvider") -public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvider, - IGarbageCollectorProcessing, IDestroyableObject { +public class MOAeIDASChainingMetadataProvider extends SimpleMOAMetadataProvider implements ObservableMetadataProvider, + IGarbageCollectorProcessing, IDestroyableObject, IMOARefreshableMetadataProvider, IPostStartupInitializable{ -// private static MOAeIDASChainingMetadataProvider instance = null; - private static Object mutex = new Object(); + private Timer timer = null; private MetadataProvider internalProvider; private Map<String, Date> lastAccess = null; @@ -70,12 +65,41 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi lastAccess = new HashMap<String, Date>(); } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.IPostStartupInitializable#executeAfterStartup() + */ + @Override + public void executeAfterStartup() { + initializeEidasMetadataFromFileSystem(); + + } + + protected void initializeEidasMetadataFromFileSystem() { + Map<String, String> metadataToLoad = authConfig.getBasicMOAIDConfigurationWithPrefix(Constants.CONIG_PROPS_EIDAS_METADATA_URLS_LIST_PREFIX); + if (!metadataToLoad.isEmpty()) { + Logger.info("Load static configurated eIDAS metadata ... "); + for (String metaatalocation : metadataToLoad.values()) { + String absMetadataLocation = FileUtils.makeAbsoluteURL(metaatalocation, authConfig.getRootConfigFileDir()); + Logger.info(" Load eIDAS metadata from: " + absMetadataLocation); + refreshMetadataProvider(absMetadataLocation); + + } + + Logger.info("Load static configurated eIDAS metadata finished "); + } + } + /* (non-Javadoc) * @see at.gv.egovernment.moa.id.auth.IDestroyableObject#fullyDestroy() */ @Override public void fullyDestroy() { + + if (timer != null) + timer.cancel(); + Map<String, HTTPMetadataProvider> loadedproviders = getAllActuallyLoadedProviders(); if (loadedproviders != null) { for (Entry<String, HTTPMetadataProvider> el : loadedproviders.entrySet()) { @@ -140,8 +164,8 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi + " after timeout."); } else - Logger.warn("eIDAS metadata for EntityID: " + expired - + " is marked as unsed, but no loaded metadata provider is found."); + Logger.info("eIDAS metadata for EntityID: " + expired + + " is marked as expired, but no currently loaded HTTPMetadataProvider metadata provider is found."); } } @@ -187,108 +211,50 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi } } - - - private HTTPMetadataProvider createNewHTTPMetaDataProvider(String metadataURL) { - HTTPMetadataProvider httpProvider = null; - Timer timer= null; - MOAHttpClient httpClient = null; - try { - AuthConfiguration authConfig = AuthConfigurationProviderFactory.getInstance(); - - httpClient = new MOAHttpClient(); - - HttpClientParams httpClientParams = new HttpClientParams(); - httpClientParams.setSoTimeout(Constants.CONFIG_PROPS_METADATA_SOCKED_TIMEOUT); - httpClient.setParams(httpClientParams); - - if (metadataURL.startsWith("https:")) { - try { - //FIX: change hostname validation default flag to true when httpClient is updated to > 4.4 - MOAHttpProtocolSocketFactory protoSocketFactory = new MOAHttpProtocolSocketFactory( - Constants.SSLSOCKETFACTORYNAME, - authConfig.getTrustedCACertificates(), - null, - AuthConfiguration.DEFAULT_X509_CHAININGMODE, - authConfig.isTrustmanagerrevoationchecking(), - authConfig.getRevocationMethodOrder(), - authConfig.getBasicMOAIDConfigurationBoolean( - AuthConfiguration.PROP_KEY_SSL_HOSTNAME_VALIDATION, false)); - - httpClient.setCustomSSLTrustStore(metadataURL, protoSocketFactory); - - } catch (MOAHttpProtocolSocketFactoryException e) { - Logger.warn("MOA SSL-TrustStore can not initialized. Use default Java TrustStore."); - - } - } - + + private MetadataProvider createNewHTTPMetaDataProvider(String metadataURL) { + if (timer == null) timer = new Timer(true); - httpProvider = new HTTPMetadataProvider(timer, httpClient, - metadataURL); - httpProvider.setParserPool(AbstractProtocolEngine.getSecuredParserPool()); - httpProvider.setRequireValidMetadata(true); - httpProvider.setMinRefreshDelay(1000*60*15); //15 minutes - httpProvider.setMaxRefreshDelay(1000*60*60*24); //24 hours - //httpProvider.setRefreshDelayFactor(0.1F); - - //add Metadata filters - MetadataFilterChain filter = new MetadataFilterChain(); - filter.addFilter(new MOASPMetadataSignatureFilter( - authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE))); - httpProvider.setMetadataFilter(filter); - - httpProvider.initialize(); - - return httpProvider; - - } catch (Throwable e) { - if (e.getCause() != null && e.getCause().getCause() instanceof SSLHandshakeException) { - Logger.warn("SSL-Server certificate for metadata " - + metadataURL + " not trusted.", e); - - } if (e.getCause() != null && e.getCause().getCause() instanceof SignatureValidationException) { - Logger.warn("Signature verification for metadata" - + metadataURL + " FAILED.", e); - - } if (e.getCause() != null && e.getCause().getCause() instanceof SchemaValidationException) { - Logger.warn("Schema validation for metadata " - + metadataURL + " FAILED.", e); - } - - Logger.error( - "Failed to add Metadata file for " - + metadataURL + "[ " - + e.getMessage() + " ]", e); - - if (httpProvider != null) { - Logger.debug("Destroy failed Metadata provider"); - httpProvider.destroy(); - } - - if (timer != null) { - Logger.debug("Destroy Timer."); - timer.cancel(); - } - - - } - return null; + //add Metadata filters + MetadataFilterChain filter = new MetadataFilterChain(); + filter.addFilter(new MOASPMetadataSignatureFilter( + authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_METADATA_VALIDATION_TRUSTSTORE))); + + return createNewMoaMetadataProvider(metadataURL, filter, + "eIDAS metadata-provider", + timer, AbstractProtocolEngine.getSecuredParserPool()); + } private Map<String, HTTPMetadataProvider> getAllActuallyLoadedProviders() { Map<String, HTTPMetadataProvider> loadedproviders = new HashMap<String, HTTPMetadataProvider>(); ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - + //make a Map of all actually loaded HTTPMetadataProvider List<MetadataProvider> providers = chainProvider.getProviders(); for (MetadataProvider provider : providers) { if (provider instanceof HTTPMetadataProvider) { HTTPMetadataProvider httpprovider = (HTTPMetadataProvider) provider; loadedproviders.put(httpprovider.getMetadataURI(), httpprovider); - - } + + } else if (provider instanceof FilesystemMetadataProvider) { + String entityID = "'!!NO-ENTITYID!!'"; + try { + if (provider.getMetadata() instanceof EntityDescriptor) + entityID = ((EntityDescriptor)provider.getMetadata()).getEntityID(); + + Logger.debug("Skip eIDAS metadata: " + entityID + " because it is loaded from local Filesystem"); + + } catch (MetadataProviderException e) { + Logger.info("Collect currently loaded eIDAS metadata provider has an internel process error: " + e.getMessage()); + + } + + } else + Logger.info("Skip " + provider.getClass().getName() + " from list of currently loaded " + + "eIDAS metadata provider"); + } return loadedproviders; @@ -309,7 +275,7 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi } else { //load new Metadata Provider ChainingMetadataProvider chainProvider = (ChainingMetadataProvider) internalProvider; - HTTPMetadataProvider newMetadataProvider = createNewHTTPMetaDataProvider(metadataURL); + MetadataProvider newMetadataProvider = createNewHTTPMetaDataProvider(metadataURL); if (newMetadataProvider != null) { chainProvider.addMetadataProvider(newMetadataProvider); @@ -319,7 +285,8 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi + metadataURL + " is added."); return true; - } + } else + Logger.warn("Can not load eIDAS metadata from URL: " + metadataURL); } } else @@ -435,4 +402,5 @@ public class MOAeIDASChainingMetadataProvider implements ObservableMetadataProvi if (observer != null) observer.onEvent(this); } + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java index c5e56502b..9adc221e5 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/MOAeIDASMetadataProviderDecorator.java @@ -31,6 +31,7 @@ import org.opensaml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.IMOARefreshableMetadataProvider; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.metadata.MetadataFetcherI; import eu.eidas.auth.engine.metadata.MetadataSignerI; @@ -54,6 +55,23 @@ public class MOAeIDASMetadataProviderDecorator implements MetadataFetcherI { } + /** + * Refresh the SAML2 metadata of a specific Entity + * <br> + * <b>Info:</b> A refresh is only possible if the internal metadata provider implements + * the 'RefeshableMetadataProvider' interface + * + * @param entityId EntityID that should be refreshed + * @return true if refresh was successful, otherwise false + */ + public boolean refreshMetadata(String entityId) { + if (this.metadataprovider instanceof IMOARefreshableMetadataProvider ) + return ((IMOARefreshableMetadataProvider)this.metadataprovider).refreshMetadataProvider(entityId); + else + return false; + + } + /* (non-Javadoc) * @see eu.eidas.auth.engine.metadata.MetadataFetcherI#getEntityDescriptor(java.lang.String, eu.eidas.auth.engine.metadata.MetadataSignerI) */ diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java index d9453322f..9895ca79f 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/engine/validation/MoaEidasConditionsValidator.java @@ -56,7 +56,7 @@ public class MoaEidasConditionsValidator extends ConditionsSpecValidator { throw new ValidationException("NotBefore is required."); } - if (conditions.getNotBefore().minusMillis(Constants.CONFIG_PROPS_SKEWTIME).isAfterNow()) { + if (conditions.getNotBefore().plusMillis((int)Constants.CONFIG_PROPS_SKEWTIME_BEFORE).isAfterNow()) { throw new ValidationException("Current time is before NotBefore condition"); } @@ -64,7 +64,7 @@ public class MoaEidasConditionsValidator extends ConditionsSpecValidator { throw new ValidationException("NotOnOrAfter is required."); } - if (conditions.getNotOnOrAfter().isBeforeNow()) { + if (conditions.getNotOnOrAfter().plusMillis((int)Constants.CONFIG_PROPS_SKEWTIME_AFTER).isBeforeNow()) { throw new ValidationException("Current time is after NotOnOrAfter condition"); } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java index 7155040c6..6f1d75bfe 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/GenerateAuthnRequestTask.java @@ -228,9 +228,9 @@ public class GenerateAuthnRequestTask extends AbstractAuthServletTask { //set correct SPType for this online application if (oaConfig.getBusinessService()) - authnRequestBuilder.spType(SpType.PRIVATE); + authnRequestBuilder.spType(SpType.PRIVATE.getValue()); else - authnRequestBuilder.spType(SpType.PUBLIC); + authnRequestBuilder.spType(SpType.PUBLIC.getValue()); //set service provider (eIDAS node) countryCode diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java index 45ba3d64e..17e112c4c 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/tasks/ReceiveAuthnResponseTask.java @@ -57,7 +57,8 @@ public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { //validate SAML token IAuthenticationResponse samlResp = engine.unmarshallResponseAndValidate(decSamlToken, request.getRemoteHost(), - Constants.CONFIG_PROPS_SKEWTIME, + Constants.CONFIG_PROPS_SKEWTIME_BEFORE, + Constants.CONFIG_PROPS_SKEWTIME_AFTER, pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_METADATA); if (samlResp.isEncrypted()) { diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java index 47cdb4ade..dbe11c12e 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAProtocolEngineFactory.java @@ -23,10 +23,16 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; import at.gv.egovernment.moa.id.auth.modules.eidas.config.MOAIDCertificateManagerConfigurationImpl; +import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAProtocolEngine; import at.gv.egovernment.moa.logging.Logger; import eu.eidas.auth.engine.ProtocolEngineFactory; +import eu.eidas.auth.engine.ProtocolEngineI; +import eu.eidas.auth.engine.SamlEngineClock; +import eu.eidas.auth.engine.configuration.FixedProtocolConfigurationAccessor; +import eu.eidas.auth.engine.configuration.ProtocolEngineConfiguration; import eu.eidas.auth.engine.configuration.SamlEngineConfigurationException; import eu.eidas.auth.engine.configuration.dom.ProtocolEngineConfigurationFactory; +import eu.eidas.auth.engine.core.ProtocolProcessorI; import eu.eidas.samlengineconfig.CertificateConfigurationManager; /** @@ -95,22 +101,32 @@ public class MOAProtocolEngineFactory extends ProtocolEngineFactory { } -// public static ProtocolEngineI createProtocolEngine(String instanceName, -// ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory, -// ProtocolProcessorI protocolProcessor, SamlEngineClock samlEngineClock) -// throws SamlEngineConfigurationException { -// -// ProtocolEngineConfiguration preConfiguration = protocolEngineConfigurationFactory -// .getConfiguration(instanceName); -// -// protocolProcessor.configure(); -// -// ProtocolEngineConfiguration configuration = ProtocolEngineConfiguration.builder(preConfiguration) -// .protocolProcessor(protocolProcessor).clock(samlEngineClock).build(); -// -// ProtocolEngineI samlEngine = new MOAProtocolEngine(new FixedProtocolConfigurationAccessor(configuration)); -// -// return samlEngine; -// } + public static ProtocolEngineI ownCreateProtocolEngine(String instanceName, + CertificateConfigurationManager configManager, ProtocolProcessorI protocolProcessor, + SamlEngineClock samlEngineClock) throws SamlEngineConfigurationException { + ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory = new ProtocolEngineConfigurationFactory( + configManager); + + return createProtocolEngine(instanceName, protocolEngineConfigurationFactory, protocolProcessor, + samlEngineClock); + } + + public static ProtocolEngineI createProtocolEngine(String instanceName, + ProtocolEngineConfigurationFactory protocolEngineConfigurationFactory, + ProtocolProcessorI protocolProcessor, SamlEngineClock samlEngineClock) + throws SamlEngineConfigurationException { + + ProtocolEngineConfiguration preConfiguration = protocolEngineConfigurationFactory + .getConfiguration(instanceName); + + protocolProcessor.configure(); + + ProtocolEngineConfiguration configuration = ProtocolEngineConfiguration.builder(preConfiguration) + .protocolProcessor(protocolProcessor).clock(samlEngineClock).build(); + + ProtocolEngineI samlEngine = new MOAProtocolEngine(new FixedProtocolConfigurationAccessor(configuration)); + + return samlEngine; + } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java index 8faaf1874..9683db503 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/MOAeIDASMetadataGenerator.java @@ -1,675 +1,681 @@ -/* - * Copyright 2014 Federal Chancellery Austria - * MOA-ID has been developed in a cooperation between BRZ, the Federal - * Chancellery Austria - ICT staff unit, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * http://www.osor.eu/eupl/ - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - */ -package at.gv.egovernment.moa.id.auth.modules.eidas.utils; - -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.apache.commons.lang.StringUtils; -import org.joda.time.DateTime; -import org.joda.time.DurationFieldType; -import org.opensaml.Configuration; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.common.Extensions; -import org.opensaml.saml2.common.impl.ExtensionsBuilder; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeValue; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.Company; -import org.opensaml.saml2.metadata.ContactPerson; -import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; -import org.opensaml.saml2.metadata.EmailAddress; -import org.opensaml.saml2.metadata.EncryptionMethod; -import org.opensaml.saml2.metadata.EntitiesDescriptor; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.GivenName; -import org.opensaml.saml2.metadata.IDPSSODescriptor; -import org.opensaml.saml2.metadata.KeyDescriptor; -import org.opensaml.saml2.metadata.LocalizedString; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.Organization; -import org.opensaml.saml2.metadata.OrganizationDisplayName; -import org.opensaml.saml2.metadata.OrganizationName; -import org.opensaml.saml2.metadata.OrganizationURL; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.opensaml.saml2.metadata.SSODescriptor; -import org.opensaml.saml2.metadata.SingleSignOnService; -import org.opensaml.saml2.metadata.SurName; -import org.opensaml.saml2.metadata.TelephoneNumber; -import org.opensaml.samlext.saml2mdattr.EntityAttributes; -import org.opensaml.xml.XMLObject; -import org.opensaml.xml.XMLObjectBuilderFactory; -import org.opensaml.xml.schema.XSString; -import org.opensaml.xml.schema.impl.XSStringBuilder; -import org.opensaml.xml.security.SecurityException; -import org.opensaml.xml.security.credential.Credential; -import org.opensaml.xml.security.credential.UsageType; -import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; -import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; -import org.opensaml.xml.signature.KeyInfo; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.google.common.collect.ImmutableSortedSet; -import com.google.common.collect.Ordering; - -import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; -import eu.eidas.auth.commons.EIDASUtil; -import eu.eidas.auth.commons.EidasStringUtil; -import eu.eidas.auth.commons.attribute.AttributeDefinition; -import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; -import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; -import eu.eidas.auth.engine.ProtocolEngineI; -import eu.eidas.auth.engine.core.SAMLExtensionFormat; -import eu.eidas.auth.engine.core.eidas.DigestMethod; -import eu.eidas.auth.engine.core.eidas.EidasConstants; -import eu.eidas.auth.engine.core.eidas.SPType; -import eu.eidas.auth.engine.core.eidas.SigningMethod; -import eu.eidas.auth.engine.metadata.Contact; -import eu.eidas.auth.engine.metadata.EntityDescriptorContainer; -import eu.eidas.auth.engine.metadata.MetadataConfigParams; -import eu.eidas.auth.engine.metadata.MetadataGenerator; -import eu.eidas.auth.engine.metadata.MetadataSignerI; -import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; -import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; -import eu.eidas.encryption.exception.UnmarshallException; -import eu.eidas.engine.exceptions.EIDASSAMLEngineException; -import eu.eidas.engine.exceptions.SAMLEngineException; - -/** - * @author tlenz - * - */ -public class MOAeIDASMetadataGenerator extends MetadataGenerator { - private static final Logger LOGGER = LoggerFactory.getLogger(MetadataGenerator.class.getName()); - - MetadataConfigParams params; - - XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); - - SPSSODescriptor spSSODescriptor = null; - - IDPSSODescriptor idpSSODescriptor = null; - - private String ssoLocation; - - /** - * @return a String representation of the entityDescriptr built based on the attributes previously set - */ - public String generateMetadata() throws EIDASSAMLEngineException { - EntityDescriptor entityDescriptor; - try { - entityDescriptor = (EntityDescriptor) builderFactory.getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) - .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); - - entityDescriptor.setEntityID(params.getEntityID()); - entityDescriptor.setOrganization(buildOrganization()); - - /**FIXME: - * HOTFIX: do not add empty contactPerson elements - */ - ContactPerson contactSupport = buildContact(ContactPersonTypeEnumeration.SUPPORT); - if (contactSupport != null) - entityDescriptor.getContactPersons().add(contactSupport); - ContactPerson contactTech = buildContact(ContactPersonTypeEnumeration.TECHNICAL); - if (contactTech != null) - entityDescriptor.getContactPersons().add(contactTech); - - entityDescriptor.setValidUntil(getExpireDate()); - - X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); - keyInfoGeneratorFactory.setEmitEntityCertificate(true); - Extensions e = generateExtensions(); - if (!e.getUnknownXMLObjects().isEmpty()) { - entityDescriptor.setExtensions(e); - } - if (spSSODescriptor != null) { - generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); - } - if (idpSSODescriptor != null) { - generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); - } - if (params.getSpEngine() != null) { - ProtocolEngineI spEngine = params.getSpEngine(); - ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); - } else if (params.getIdpEngine() != null) { - ProtocolEngineI idpEngine = params.getIdpEngine(); - ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); - } - return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); - } catch (Exception ex) { - LOGGER.info("ERROR : SAMLException ", ex.getMessage()); - LOGGER.debug("ERROR : SAMLException ", ex); - throw new IllegalStateException(ex); - } - } - - private void generateSPSSODescriptor(final EntityDescriptor entityDescriptor, - final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) - throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, - SAMLEngineException, EIDASSAMLEngineException { - //the node has SP role - spSSODescriptor.setWantAssertionsSigned(params.isWantAssertionsSigned()); - spSSODescriptor.setAuthnRequestsSigned(true); - - - /**FIXME: - * "SP" + params.getEntityID()) is not a valid XML ID attribute value - */ - //spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() : ("SP" + params.getEntityID())); - spSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); - - - if (params.getSPSignature() != null) { - spSSODescriptor.setSignature(params.getSPSignature()); - } - if (params.getSpSigningCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpSigningCredential(), UsageType.SIGNING)); - - } else if (params.getSigningCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); - } - - if (params.getSpEncryptionCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpEncryptionCredential(), - UsageType.ENCRYPTION)); - } else if (params.getEncryptionCredential() != null) { - spSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); - } - spSSODescriptor.addSupportedProtocol(params.getSpSamlProtocol()); - if (!StringUtils.isEmpty(params.getAssertionConsumerUrl())) { - addAssertionConsumerService(); - } - fillNameIDFormat(spSSODescriptor); - - /**FIXME: - * Double signing of SPSSODescribtor is not required - */ -// if (params.getSpEngine() != null) { -// ProtocolEngineI spEngine = params.getSpEngine(); -// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); -// } - - entityDescriptor.getRoleDescriptors().add(spSSODescriptor); - - } - - private void fillNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { - NameIDFormat persistentFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(persistentFormat); - NameIDFormat transientFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(transientFormat); - NameIDFormat unspecifiedFormat = - (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); - unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); - ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); - } - - private void generateIDPSSODescriptor(final EntityDescriptor entityDescriptor, - final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) - throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, - SAMLEngineException, EIDASSAMLEngineException { - //the node has IDP role - idpSSODescriptor.setWantAuthnRequestsSigned(true); - - /**FIXME: - * "IDP" + params.getEntityID()) is not a valid XML ID attribute value - */ - //idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() : ("IDP" + params.getEntityID())); - idpSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); - - if (params.getIDPSignature() != null) { - idpSSODescriptor.setSignature(params.getIDPSignature()); - } - if (params.getIdpSigningCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpSigningCredential(), UsageType.SIGNING)); - } else if (params.getSigningCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); - } - if (params.getIdpEncryptionCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpEncryptionCredential(), - UsageType.ENCRYPTION)); - } else if (params.getEncryptionCredential() != null) { - idpSSODescriptor.getKeyDescriptors() - .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); - } - idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); - fillNameIDFormat(idpSSODescriptor); - - - if (params.getIdpEngine() != null) { - if (params.getIdpEngine().getProtocolProcessor() != null - && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { - - /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata - * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. - * - * INFO: Maybe, this code can be removed in a future version of the eIDAS engine - */ - generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes()); - } - - - /**FIXME: - * Double signing of IDPSSODescribtor is not required - */ -// ProtocolEngineI idpEngine = params.getIdpEngine(); -// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); - } - - idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); - - entityDescriptor.getRoleDescriptors().add(idpSSODescriptor); - - } - - /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata - * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. - */ - public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { - ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = - new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); - builder.addAll(Constants.MOA_IDP_ATTR_REGISTRY.getAttributes()); - return builder.build(); - } - - private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() - throws NoSuchFieldException, IllegalAccessException { - ArrayList<SingleSignOnService> singleSignOnServices = new ArrayList<SingleSignOnService>(); - - HashMap<String, String> bindingLocations = params.getProtocolBindingLocation(); - for (String binding : bindingLocations.keySet()) { - SingleSignOnService ssos = BuilderFactoryUtil.buildXmlObject(SingleSignOnService.class); - ssos.setBinding(binding); - ssos.setLocation(bindingLocations.get(binding)); - singleSignOnServices.add(ssos); - } - - return singleSignOnServices; - } - - /** - * @param metadata - * @return an EntityDescriptor parsed from the given String or null - */ - // TODO (commented by donydgr) Move to a eu.eidas.auth.engine.metadata.MetadataUtil ? Throw an exception if the metadata is invalid instead of returning null ? - public static EntityDescriptorContainer deserializeEntityDescriptor(String metadata) { - EntityDescriptorContainer result = new EntityDescriptorContainer(); - try { - byte[] metaDataBytes = EidasStringUtil.getBytes(metadata); - XMLObject obj = OpenSamlHelper.unmarshall(metaDataBytes); - if (obj instanceof EntityDescriptor) { - result.addEntityDescriptor((EntityDescriptor) obj, metaDataBytes); - } else if (obj instanceof EntitiesDescriptor) { - EntitiesDescriptor ed = (EntitiesDescriptor) obj; - result.setEntitiesDescriptor(ed); - result.getEntityDescriptors().addAll(((EntitiesDescriptor) obj).getEntityDescriptors()); - result.setSerializedEntitesDescriptor(metaDataBytes); - } - } catch (UnmarshallException ue) { - LOGGER.info("ERROR : unmarshalling error", ue.getMessage()); - LOGGER.debug("ERROR : unmarshalling error", ue); - } - return result; - } - - private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, - Credential credential, - UsageType usage) - throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { - KeyDescriptor keyDescriptor = null; - if (credential != null) { - keyDescriptor = BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); - KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); - - KeyInfo keyInfo = keyInfoGenerator.generate(credential); - keyDescriptor.setUse(usage); - keyDescriptor.setKeyInfo(keyInfo); - if (usage == UsageType.ENCRYPTION && params.getEncryptionAlgorithms() != null) { - Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(params.getEncryptionAlgorithms()); - for (String encryptionAlgo : encryptionAlgos) { - EncryptionMethod em = - (EncryptionMethod) BuilderFactoryUtil.buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); - em.setAlgorithm(encryptionAlgo); - keyDescriptor.getEncryptionMethods().add(em); - } - } - - } - return keyDescriptor; - } - - private Organization buildOrganization() { - Organization organization = null; - try { - organization = BuilderFactoryUtil.buildXmlObject(Organization.class); - - /**FIXME: - * set correct OrganizationName value if it is not fixed in next eIDAS node version - */ - OrganizationName orgName = BuilderFactoryUtil.buildXmlObject(OrganizationName.class); - orgName.setName(new LocalizedString(params.getNodeUrl(), "en")); - organization.getOrganizationNames().add(orgName); - - OrganizationDisplayName odn = BuilderFactoryUtil.buildXmlObject(OrganizationDisplayName.class); - odn.setName(new LocalizedString(params.getCountryName(), "en")); - organization.getDisplayNames().add(odn); - OrganizationURL url = BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); - url.setURL(new LocalizedString(params.getNodeUrl(), "en")); - organization.getURLs().add(url); - } catch (IllegalAccessException iae) { - LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", iae); - } catch (NoSuchFieldException nfe) { - LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", nfe); - } - return organization; - } - - private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { - ContactPerson contact = null; - try { - Contact currentContact = null; - if (contactType == ContactPersonTypeEnumeration.SUPPORT) { - currentContact = params.getSupportContact(); - } else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) { - currentContact = params.getTechnicalContact(); - } else { - LOGGER.error("ERROR: unsupported contact type"); - } - contact = BuilderFactoryUtil.buildXmlObject(ContactPerson.class); - if (currentContact == null) { - LOGGER.error("ERROR: cannot retrieve contact from the configuration"); - return null; - } - - EmailAddress emailAddressObj = BuilderFactoryUtil.buildXmlObject(EmailAddress.class); - Company company = BuilderFactoryUtil.buildXmlObject(Company.class); - GivenName givenName = BuilderFactoryUtil.buildXmlObject(GivenName.class); - SurName surName = BuilderFactoryUtil.buildXmlObject(SurName.class); - TelephoneNumber phoneNumber = BuilderFactoryUtil.buildXmlObject(TelephoneNumber.class); - contact.setType(contactType); - emailAddressObj.setAddress(currentContact.getEmail()); - company.setName(currentContact.getCompany()); - givenName.setName(currentContact.getGivenName()); - surName.setName(currentContact.getSurName()); - phoneNumber.setNumber(currentContact.getPhone()); - - populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); - - } catch (IllegalAccessException iae) { - LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", iae); - } catch (NoSuchFieldException nfe) { - LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); - LOGGER.debug("ERROR : error generating the Organization: {}", nfe); - } - return contact; - } - - private void populateContact(ContactPerson contact, - Contact currentContact, - EmailAddress emailAddressObj, - Company company, - GivenName givenName, - SurName surName, - TelephoneNumber phoneNumber) { - if (!StringUtils.isEmpty(currentContact.getEmail())) { - contact.getEmailAddresses().add(emailAddressObj); - } - if (!StringUtils.isEmpty(currentContact.getCompany())) { - contact.setCompany(company); - } - if (!StringUtils.isEmpty(currentContact.getGivenName())) { - contact.setGivenName(givenName); - } - if (!StringUtils.isEmpty(currentContact.getSurName())) { - contact.setSurName(surName); - } - if (!StringUtils.isEmpty(currentContact.getPhone())) { - contact.getTelephoneNumbers().add(phoneNumber); - } - - } - - /** - * @param engine a EIDASSamlEngine from which signing and encryption information is extracted - */ - - public void initialize(ProtocolEngineI engine) throws EIDASSAMLEngineException { - - X509Certificate decryptionCertificate = engine.getDecryptionCertificate(); - if (null != decryptionCertificate) { - params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); - } - params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate())); - params.setIdpEngine(engine); - params.setSpEngine(engine); - } - - /** - * @param spEngine a EIDASSamlEngine for the - */ - - public void initialize(ProtocolEngineI spEngine, ProtocolEngineI idpEngine) throws EIDASSAMLEngineException { - if (idpEngine != null) { - idpEngine.getProtocolProcessor().configure(); - params.setIdpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); - - final X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); - if (idpEngineDecryptionCertificate != null) { - params.setIdpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); - } - - } - if (spEngine != null) { - spEngine.getProtocolProcessor().configure(); - params.setSpSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); - - final X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); - if (spEngineDecryptionCertificate != null) { - params.setSpEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); - } - } - - params.setIdpEngine(idpEngine); - params.setSpEngine(spEngine); - } - - public void addSPRole() throws EIDASSAMLEngineException { - try { - if (spSSODescriptor == null) { - spSSODescriptor = BuilderFactoryUtil.buildXmlObject(SPSSODescriptor.class); - } - } catch (IllegalAccessException iae) { - throw new EIDASSAMLEngineException(iae); - } catch (NoSuchFieldException nsfe) { - throw new EIDASSAMLEngineException(nsfe); - } - } - - public void addIDPRole() throws EIDASSAMLEngineException { - try { - if (idpSSODescriptor == null) { - idpSSODescriptor = BuilderFactoryUtil.buildXmlObject(IDPSSODescriptor.class); - } - } catch (IllegalAccessException iae) { - throw new EIDASSAMLEngineException(iae); - } catch (NoSuchFieldException nsfe) { - throw new EIDASSAMLEngineException(nsfe); - } - } - - private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { - if (!StringUtils.isEmpty(params.getDigestMethods())) { - Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); - Set<String> digestMethods = new HashSet<String>(); - for (String signatureMethod : signatureMethods) { - - //BUGFIX: eIDAS implementation does not allow MGF1 signature schemes - digestMethods.add(signatureMethod); - //digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); - } - for (String digestMethod : digestMethods) { - final DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); - if (dm != null) { - dm.setAlgorithm(digestMethod); - eidasExtensions.getUnknownXMLObjects().add(dm); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); - } - } - } - - } - - private Extensions generateExtensions() throws EIDASSAMLEngineException { - /**FIXME: BuilderFactoryUtil.generateExtension() generates extensions from SAML2 request namespace - * but SAML2 metadata namespace is required - **/ - //Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); - - ExtensionsBuilder extensionsBuilder = new ExtensionsBuilder(); - Extensions eidasExtensions = extensionsBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:metadata", "Extensions", "md"); - - if (params.getAssuranceLevel() != null) { - generateLoA(eidasExtensions); - } - if (!StringUtils.isEmpty(params.getSpType())) { - final SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); - if (spTypeObj != null) { - spTypeObj.setSPType(params.getSpType()); - eidasExtensions.getUnknownXMLObjects().add(spTypeObj); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); - } - } - generateDigest(eidasExtensions); - - if (!StringUtils.isEmpty(params.getSigningMethods())) { - Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods()); - for (String signMethod : signMethods) { - final SigningMethod sm = - (SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); - if (sm != null) { - sm.setAlgorithm(signMethod); - eidasExtensions.getUnknownXMLObjects().add(sm); - } else { - LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); - } - } - } - return eidasExtensions; - } - - private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { - EntityAttributes loa = - (EntityAttributes) BuilderFactoryUtil.buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); - Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); - loaAttrib.setName(EidasConstants.LEVEL_OF_ASSURANCE_NAME); - loaAttrib.setNameFormat(Attribute.URI_REFERENCE); - XSStringBuilder stringBuilder = - (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); - XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); - stringValue.setValue(params.getAssuranceLevel()); - loaAttrib.getAttributeValues().add(stringValue); - loa.getAttributes().add(loaAttrib); - eidasExtensions.getUnknownXMLObjects().add(loa); - - } - - private static final Set<String> DEFAULT_BINDING = new HashSet<String>() {{ - this.add(SAMLConstants.SAML2_POST_BINDING_URI); - }}; - - private void addAssertionConsumerService() throws EIDASSAMLEngineException { - int index = 0; - Set<String> bindings = params.getProtocolBinding().isEmpty() ? DEFAULT_BINDING : params.getProtocolBinding(); - for (String binding : bindings) { - AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil.buildXmlObject( - AssertionConsumerService.DEFAULT_ELEMENT_NAME); - asc.setLocation(params.getAssertionConsumerUrl()); - asc.setBinding(checkBinding(binding)); - asc.setIndex(index); - if (index == 0) { - asc.setIsDefault(true); - } - index++; - spSSODescriptor.getAssertionConsumerServices().add(asc); - } - } - - private String checkBinding(String binding) { - if (binding != null && (binding.equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) || binding.equals( - SAMLConstants.SAML2_POST_BINDING_URI))) { - return binding; - } - return SAMLConstants.SAML2_POST_BINDING_URI; - } - - private DateTime getExpireDate() { - DateTime expiryDate = DateTime.now(); - expiryDate = - expiryDate.withFieldAdded(DurationFieldType.seconds(), (int) (getConfigParams().getValidityDuration())); - return expiryDate; - } - - private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, - ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) - throws EIDASSAMLEngineException { - List<Attribute> attributes = idpssoDescriptor.getAttributes(); - for (AttributeDefinition<?> attributeDefinition : attributeDefinitions) { - Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); - a.setName(attributeDefinition.getNameUri().toASCIIString()); - a.setFriendlyName(attributeDefinition.getFriendlyName()); - a.setNameFormat(Attribute.URI_REFERENCE); - attributes.add(a); - } - } - - public MetadataConfigParams getConfigParams() { - return params; - } - - public void setConfigParams(MetadataConfigParams params) { - this.params = params; - } - -} +///* +// * Copyright 2014 Federal Chancellery Austria +// * MOA-ID has been developed in a cooperation between BRZ, the Federal +// * Chancellery Austria - ICT staff unit, and Graz University of Technology. +// * +// * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by +// * the European Commission - subsequent versions of the EUPL (the "Licence"); +// * You may not use this work except in compliance with the Licence. +// * You may obtain a copy of the Licence at: +// * http://www.osor.eu/eupl/ +// * +// * Unless required by applicable law or agreed to in writing, software +// * distributed under the Licence is distributed on an "AS IS" basis, +// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// * See the Licence for the specific language governing permissions and +// * limitations under the Licence. +// * +// * This product combines work with different licenses. See the "NOTICE" text +// * file for details on the various modules and licenses. +// * The "NOTICE" text file is part of the distribution. Any derivative works +// * that you distribute must include a readable copy of the "NOTICE" text file. +// */ +//package at.gv.egovernment.moa.id.auth.modules.eidas.utils; +// +//import java.security.cert.X509Certificate; +//import java.util.ArrayList; +//import java.util.HashMap; +//import java.util.HashSet; +//import java.util.List; +//import java.util.Set; +// +//import org.apache.commons.lang.StringUtils; +//import org.joda.time.DateTime; +//import org.joda.time.DurationFieldType; +//import org.opensaml.Configuration; +//import org.opensaml.common.xml.SAMLConstants; +//import org.opensaml.saml2.common.Extensions; +//import org.opensaml.saml2.common.impl.ExtensionsBuilder; +//import org.opensaml.saml2.core.Attribute; +//import org.opensaml.saml2.core.AttributeValue; +//import org.opensaml.saml2.metadata.AssertionConsumerService; +//import org.opensaml.saml2.metadata.Company; +//import org.opensaml.saml2.metadata.ContactPerson; +//import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; +//import org.opensaml.saml2.metadata.EmailAddress; +//import org.opensaml.saml2.metadata.EncryptionMethod; +//import org.opensaml.saml2.metadata.EntitiesDescriptor; +//import org.opensaml.saml2.metadata.EntityDescriptor; +//import org.opensaml.saml2.metadata.GivenName; +//import org.opensaml.saml2.metadata.IDPSSODescriptor; +//import org.opensaml.saml2.metadata.KeyDescriptor; +//import org.opensaml.saml2.metadata.LocalizedString; +//import org.opensaml.saml2.metadata.NameIDFormat; +//import org.opensaml.saml2.metadata.Organization; +//import org.opensaml.saml2.metadata.OrganizationDisplayName; +//import org.opensaml.saml2.metadata.OrganizationName; +//import org.opensaml.saml2.metadata.OrganizationURL; +//import org.opensaml.saml2.metadata.SPSSODescriptor; +//import org.opensaml.saml2.metadata.SSODescriptor; +//import org.opensaml.saml2.metadata.SingleSignOnService; +//import org.opensaml.saml2.metadata.SurName; +//import org.opensaml.saml2.metadata.TelephoneNumber; +//import org.opensaml.samlext.saml2mdattr.EntityAttributes; +//import org.opensaml.xml.XMLObject; +//import org.opensaml.xml.XMLObjectBuilderFactory; +//import org.opensaml.xml.schema.XSString; +//import org.opensaml.xml.schema.impl.XSStringBuilder; +//import org.opensaml.xml.security.SecurityException; +//import org.opensaml.xml.security.credential.Credential; +//import org.opensaml.xml.security.credential.UsageType; +//import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +//import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +//import org.opensaml.xml.signature.KeyInfo; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +// +//import com.google.common.collect.ImmutableSortedSet; +//import com.google.common.collect.Ordering; +// +//import at.gv.egovernment.moa.id.commons.db.dao.config.deprecated.Contact; +//import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +//import eu.eidas.auth.commons.EIDASUtil; +//import eu.eidas.auth.commons.EidasStringUtil; +//import eu.eidas.auth.commons.attribute.AttributeDefinition; +//import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; +//import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; +//import eu.eidas.auth.engine.ProtocolEngineI; +//import eu.eidas.auth.engine.core.SAMLExtensionFormat; +//import eu.eidas.auth.engine.core.eidas.DigestMethod; +//import eu.eidas.auth.engine.core.eidas.EidasConstants; +//import eu.eidas.auth.engine.core.eidas.SPType; +//import eu.eidas.auth.engine.core.eidas.SigningMethod; +//import eu.eidas.auth.engine.metadata.EntityDescriptorContainer; +//import eu.eidas.auth.engine.metadata.MetadataConfigParams; +//import eu.eidas.auth.engine.metadata.MetadataGenerator; +//import eu.eidas.auth.engine.metadata.MetadataSignerI; +//import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; +//import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; +//import eu.eidas.encryption.exception.UnmarshallException; +//import eu.eidas.engine.exceptions.EIDASSAMLEngineException; +//import eu.eidas.engine.exceptions.SAMLEngineException; +// +///** +// * @author tlenz +// * +// */ +//public class MOAeIDASMetadataGenerator extends MetadataGenerator { +// private static final Logger LOGGER = LoggerFactory.getLogger(MetadataGenerator.class.getName()); +// +// MetadataConfigParams params; +// +// XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); +// +// SPSSODescriptor spSSODescriptor = null; +// +// IDPSSODescriptor idpSSODescriptor = null; +// +// private String ssoLocation; +// +// /** +// * @return a String representation of the entityDescriptr built based on the attributes previously set +// */ +// public String generateMetadata() throws EIDASSAMLEngineException { +// EntityDescriptor entityDescriptor; +// try { +// entityDescriptor = (EntityDescriptor) builderFactory.getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) +// .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); +// +// entityDescriptor.setEntityID(params.getEntityID()); +// entityDescriptor.setOrganization(buildOrganization()); +// +// /**FIXME: +// * HOTFIX: do not add empty contactPerson elements +// */ +// ContactPerson contactSupport = buildContact(ContactPersonTypeEnumeration.SUPPORT); +// if (contactSupport != null) +// entityDescriptor.getContactPersons().add(contactSupport); +// ContactPerson contactTech = buildContact(ContactPersonTypeEnumeration.TECHNICAL); +// if (contactTech != null) +// entityDescriptor.getContactPersons().add(contactTech); +// +// entityDescriptor.setValidUntil(getExpireDate()); +// +// X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); +// keyInfoGeneratorFactory.setEmitEntityCertificate(true); +// Extensions e = generateExtensions(); +// if (!e.getUnknownXMLObjects().isEmpty()) { +// entityDescriptor.setExtensions(e); +// } +// if (spSSODescriptor != null) { +// generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); +// } +// if (idpSSODescriptor != null) { +// generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); +// } +// if (params.getSpEngine() != null) { +// ProtocolEngineI spEngine = params.getSpEngine(); +// ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); +// } else if (params.getIdpEngine() != null) { +// ProtocolEngineI idpEngine = params.getIdpEngine(); +// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); +// } +// return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); +// } catch (Exception ex) { +// LOGGER.info("ERROR : SAMLException ", ex.getMessage()); +// LOGGER.debug("ERROR : SAMLException ", ex); +// throw new IllegalStateException(ex); +// } +// } +// +// private void generateSPSSODescriptor(final EntityDescriptor entityDescriptor, +// final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) +// throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, +// SAMLEngineException, EIDASSAMLEngineException { +// //the node has SP role +// spSSODescriptor.setWantAssertionsSigned(params.isWantAssertionsSigned()); +// spSSODescriptor.setAuthnRequestsSigned(true); +// +// +// /**FIXME: +// * "SP" + params.getEntityID()) is not a valid XML ID attribute value +// */ +// //spSSODescriptor.setID(idpSSODescriptor == null ? params.getEntityID() : ("SP" + params.getEntityID())); +// spSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); +// +// +// if (params.getSPSignature() != null) { +// spSSODescriptor.setSignature(params.getSPSignature()); +// } +// if (params.getSpSigningCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpSigningCredential(), UsageType.SIGNING)); +// +// } else if (params.getSigningCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); +// } +// +// if (params.getSpEncryptionCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSpEncryptionCredential(), +// UsageType.ENCRYPTION)); +// } else if (params.getEncryptionCredential() != null) { +// spSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); +// } +// spSSODescriptor.addSupportedProtocol(params.getSpSamlProtocol()); +// if (!StringUtils.isEmpty(params.getAssertionConsumerUrl())) { +// addAssertionConsumerService(); +// } +// +// //FIX: Austrian eIDAS node SP only needs persistent identifiers +// NameIDFormat persistentFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); +// spSSODescriptor.getNameIDFormats().add(persistentFormat); +// +// /**FIXME: +// * Double signing of SPSSODescribtor is not required +// */ +//// if (params.getSpEngine() != null) { +//// ProtocolEngineI spEngine = params.getSpEngine(); +//// ((MetadataSignerI) spEngine.getSigner()).signMetadata(spSSODescriptor); +//// } +// +// entityDescriptor.getRoleDescriptors().add(spSSODescriptor); +// +// } +// +// private void fillIDPNameIDFormat(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { +// NameIDFormat persistentFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(persistentFormat); +// NameIDFormat transientFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(transientFormat); +// NameIDFormat unspecifiedFormat = +// (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); +// unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); +// ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); +// } +// +// private void generateIDPSSODescriptor(final EntityDescriptor entityDescriptor, +// final X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) +// throws org.opensaml.xml.security.SecurityException, IllegalAccessException, NoSuchFieldException, +// SAMLEngineException, EIDASSAMLEngineException { +// //the node has IDP role +// idpSSODescriptor.setWantAuthnRequestsSigned(true); +// +// /**FIXME: +// * "IDP" + params.getEntityID()) is not a valid XML ID attribute value +// */ +// //idpSSODescriptor.setID(spSSODescriptor == null ? params.getEntityID() : ("IDP" + params.getEntityID())); +// idpSSODescriptor.setID(SAML2Utils.getSecureIdentifier()); +// +// if (params.getIDPSignature() != null) { +// idpSSODescriptor.setSignature(params.getIDPSignature()); +// } +// if (params.getIdpSigningCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpSigningCredential(), UsageType.SIGNING)); +// } else if (params.getSigningCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getSigningCredential(), UsageType.SIGNING)); +// } +// if (params.getIdpEncryptionCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getIdpEncryptionCredential(), +// UsageType.ENCRYPTION)); +// } else if (params.getEncryptionCredential() != null) { +// idpSSODescriptor.getKeyDescriptors() +// .add(getKeyDescriptor(keyInfoGeneratorFactory, params.getEncryptionCredential(), UsageType.ENCRYPTION)); +// } +// idpSSODescriptor.addSupportedProtocol(params.getIdpSamlProtocol()); +// +// //Austrian eIDAS node IDP can provided persistent, transient, and unspecified identifiers +// fillIDPNameIDFormat(idpSSODescriptor); +// +// +// if (params.getIdpEngine() != null) { +// if (params.getIdpEngine().getProtocolProcessor() != null +// && params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10) { +// +// generateSupportedAttributes(idpSSODescriptor, getAllSupportedAttributes()); +// } +// +// +// /**FIXME: +// * Double signing of IDPSSODescribtor is not required +// */ +//// ProtocolEngineI idpEngine = params.getIdpEngine(); +//// ((MetadataSignerI) idpEngine.getSigner()).signMetadata(idpSSODescriptor); +// } +// +// idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); +// +// entityDescriptor.getRoleDescriptors().add(idpSSODescriptor); +// +// } +// +// /* FIX: Work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata +// * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. +// */ +// public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { +// ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = +// new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); +// +// for (String attr : eIDASAttributeBuilder.getAllProvideableeIDASAttributes()) { +// AttributeDefinition<?> supAttr = params.getIdpEngine().getProtocolProcessor().getAttributeDefinitionNullable(attr); +// builder.add(supAttr); +// } +// +// return builder.build(); +// } +// +// private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() +// throws NoSuchFieldException, IllegalAccessException { +// ArrayList<SingleSignOnService> singleSignOnServices = new ArrayList<SingleSignOnService>(); +// +// HashMap<String, String> bindingLocations = params.getProtocolBindingLocation(); +// for (String binding : bindingLocations.keySet()) { +// SingleSignOnService ssos = BuilderFactoryUtil.buildXmlObject(SingleSignOnService.class); +// ssos.setBinding(binding); +// ssos.setLocation(bindingLocations.get(binding)); +// singleSignOnServices.add(ssos); +// } +// +// return singleSignOnServices; +// } +// +// /** +// * @param metadata +// * @return an EntityDescriptor parsed from the given String or null +// */ +// // TODO (commented by donydgr) Move to a eu.eidas.auth.engine.metadata.MetadataUtil ? Throw an exception if the metadata is invalid instead of returning null ? +// public static EntityDescriptorContainer deserializeEntityDescriptor(String metadata) { +// EntityDescriptorContainer result = new EntityDescriptorContainer(); +// try { +// byte[] metaDataBytes = EidasStringUtil.getBytes(metadata); +// XMLObject obj = OpenSamlHelper.unmarshall(metaDataBytes); +// if (obj instanceof EntityDescriptor) { +// result.addEntityDescriptor((EntityDescriptor) obj, metaDataBytes); +// } else if (obj instanceof EntitiesDescriptor) { +// EntitiesDescriptor ed = (EntitiesDescriptor) obj; +// result.setEntitiesDescriptor(ed); +// result.getEntityDescriptors().addAll(((EntitiesDescriptor) obj).getEntityDescriptors()); +// result.setSerializedEntitesDescriptor(metaDataBytes); +// } +// } catch (UnmarshallException ue) { +// LOGGER.info("ERROR : unmarshalling error", ue.getMessage()); +// LOGGER.debug("ERROR : unmarshalling error", ue); +// } +// return result; +// } +// +// private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, +// Credential credential, +// UsageType usage) +// throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { +// KeyDescriptor keyDescriptor = null; +// if (credential != null) { +// keyDescriptor = BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); +// KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); +// +// KeyInfo keyInfo = keyInfoGenerator.generate(credential); +// keyDescriptor.setUse(usage); +// keyDescriptor.setKeyInfo(keyInfo); +// if (usage == UsageType.ENCRYPTION && params.getEncryptionAlgorithms() != null) { +// Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(params.getEncryptionAlgorithms()); +// for (String encryptionAlgo : encryptionAlgos) { +// EncryptionMethod em = +// (EncryptionMethod) BuilderFactoryUtil.buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); +// em.setAlgorithm(encryptionAlgo); +// keyDescriptor.getEncryptionMethods().add(em); +// } +// } +// +// } +// return keyDescriptor; +// } +// +// private Organization buildOrganization() { +// Organization organization = null; +// try { +// organization = BuilderFactoryUtil.buildXmlObject(Organization.class); +// +// /**FIXME: +// * set correct OrganizationName value if it is not fixed in next eIDAS node version +// */ +// OrganizationName orgName = BuilderFactoryUtil.buildXmlObject(OrganizationName.class); +// orgName.setName(new LocalizedString(params.getNodeUrl(), "en")); +// organization.getOrganizationNames().add(orgName); +// +// OrganizationDisplayName odn = BuilderFactoryUtil.buildXmlObject(OrganizationDisplayName.class); +// odn.setName(new LocalizedString(params.getCountryName(), "en")); +// organization.getDisplayNames().add(odn); +// OrganizationURL url = BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); +// url.setURL(new LocalizedString(params.getNodeUrl(), "en")); +// organization.getURLs().add(url); +// } catch (IllegalAccessException iae) { +// LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", iae); +// } catch (NoSuchFieldException nfe) { +// LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", nfe); +// } +// return organization; +// } +// +// private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { +// ContactPerson contact = null; +// try { +// Contact currentContact = null; +// if (contactType == ContactPersonTypeEnumeration.SUPPORT) { +// currentContact = params.getSupportContact(); +// } else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) { +// currentContact = params.getTechnicalContact(); +// } else { +// LOGGER.error("ERROR: unsupported contact type"); +// } +// contact = BuilderFactoryUtil.buildXmlObject(ContactPerson.class); +// if (currentContact == null) { +// LOGGER.error("ERROR: cannot retrieve contact from the configuration"); +// return null; +// } +// +// EmailAddress emailAddressObj = BuilderFactoryUtil.buildXmlObject(EmailAddress.class); +// Company company = BuilderFactoryUtil.buildXmlObject(Company.class); +// GivenName givenName = BuilderFactoryUtil.buildXmlObject(GivenName.class); +// SurName surName = BuilderFactoryUtil.buildXmlObject(SurName.class); +// TelephoneNumber phoneNumber = BuilderFactoryUtil.buildXmlObject(TelephoneNumber.class); +// contact.setType(contactType); +// emailAddressObj.setAddress(currentContact.getEmail()); +// company.setName(currentContact.getCompany()); +// givenName.setName(currentContact.getGivenName()); +// surName.setName(currentContact.getSurName()); +// phoneNumber.setNumber(currentContact.getPhone()); +// +// populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); +// +// } catch (IllegalAccessException iae) { +// LOGGER.info("ERROR : error generating the Organization: {}", iae.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", iae); +// } catch (NoSuchFieldException nfe) { +// LOGGER.info("ERROR : error generating the Organization: {}", nfe.getMessage()); +// LOGGER.debug("ERROR : error generating the Organization: {}", nfe); +// } +// return contact; +// } +// +// private void populateContact(ContactPerson contact, +// Contact currentContact, +// EmailAddress emailAddressObj, +// Company company, +// GivenName givenName, +// SurName surName, +// TelephoneNumber phoneNumber) { +// if (!StringUtils.isEmpty(currentContact.getEmail())) { +// contact.getEmailAddresses().add(emailAddressObj); +// } +// if (!StringUtils.isEmpty(currentContact.getCompany())) { +// contact.setCompany(company); +// } +// if (!StringUtils.isEmpty(currentContact.getGivenName())) { +// contact.setGivenName(givenName); +// } +// if (!StringUtils.isEmpty(currentContact.getSurName())) { +// contact.setSurName(surName); +// } +// if (!StringUtils.isEmpty(currentContact.getPhone())) { +// contact.getTelephoneNumbers().add(phoneNumber); +// } +// +// } +// +// /** +// * @param engine a EIDASSamlEngine from which signing and encryption information is extracted +// */ +// +// public void initialize(ProtocolEngineI engine) throws EIDASSAMLEngineException { +// +// X509Certificate decryptionCertificate = engine.getDecryptionCertificate(); +// if (null != decryptionCertificate) { +// params.setSpEncryptionCredential(CertificateUtil.toCredential(decryptionCertificate)); +// } +// params.setSigningCredential(CertificateUtil.toCredential(engine.getSigningCertificate())); +// params.setIdpEngine(engine); +// params.setSpEngine(engine); +// } +// +// /** +// * @param spEngine a EIDASSamlEngine for the +// */ +// +// public void initialize(ProtocolEngineI spEngine, ProtocolEngineI idpEngine) throws EIDASSAMLEngineException { +// if (idpEngine != null) { +// idpEngine.getProtocolProcessor().configure(); +// params.setIdpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); +// +// final X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); +// if (idpEngineDecryptionCertificate != null) { +// params.setIdpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); +// } +// +// } +// if (spEngine != null) { +// spEngine.getProtocolProcessor().configure(); +// params.setSpSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); +// +// final X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); +// if (spEngineDecryptionCertificate != null) { +// params.setSpEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); +// } +// } +// +// params.setIdpEngine(idpEngine); +// params.setSpEngine(spEngine); +// } +// +// public void addSPRole() throws EIDASSAMLEngineException { +// try { +// if (spSSODescriptor == null) { +// spSSODescriptor = BuilderFactoryUtil.buildXmlObject(SPSSODescriptor.class); +// } +// } catch (IllegalAccessException iae) { +// throw new EIDASSAMLEngineException(iae); +// } catch (NoSuchFieldException nsfe) { +// throw new EIDASSAMLEngineException(nsfe); +// } +// } +// +// public void addIDPRole() throws EIDASSAMLEngineException { +// try { +// if (idpSSODescriptor == null) { +// idpSSODescriptor = BuilderFactoryUtil.buildXmlObject(IDPSSODescriptor.class); +// } +// } catch (IllegalAccessException iae) { +// throw new EIDASSAMLEngineException(iae); +// } catch (NoSuchFieldException nsfe) { +// throw new EIDASSAMLEngineException(nsfe); +// } +// } +// +// private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { +// if (!StringUtils.isEmpty(params.getDigestMethods())) { +// Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(params.getDigestMethods()); +// Set<String> digestMethods = new HashSet<String>(); +// for (String signatureMethod : signatureMethods) { +// +// //BUGFIX: eIDAS implementation does not allow MGF1 signature schemes +// digestMethods.add(signatureMethod); +// //digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); +// } +// for (String digestMethod : digestMethods) { +// final DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); +// if (dm != null) { +// dm.setAlgorithm(digestMethod); +// eidasExtensions.getUnknownXMLObjects().add(dm); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); +// } +// } +// } +// +// } +// +// private Extensions generateExtensions() throws EIDASSAMLEngineException { +// /**FIXME: BuilderFactoryUtil.generateExtension() generates extensions from SAML2 request namespace +// * but SAML2 metadata namespace is required +// **/ +// //Extensions eidasExtensions = BuilderFactoryUtil.generateExtension(); +// +// ExtensionsBuilder extensionsBuilder = new ExtensionsBuilder(); +// Extensions eidasExtensions = extensionsBuilder.buildObject("urn:oasis:names:tc:SAML:2.0:metadata", "Extensions", "md"); +// +// if (params.getAssuranceLevel() != null) { +// generateLoA(eidasExtensions); +// } +// if (!StringUtils.isEmpty(params.getSpType())) { +// final SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); +// if (spTypeObj != null) { +// spTypeObj.setSPType(params.getSpType()); +// eidasExtensions.getUnknownXMLObjects().add(spTypeObj); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); +// } +// } +// generateDigest(eidasExtensions); +// +// if (!StringUtils.isEmpty(params.getSigningMethods())) { +// Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(params.getSigningMethods()); +// for (String signMethod : signMethods) { +// final SigningMethod sm = +// (SigningMethod) BuilderFactoryUtil.buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); +// if (sm != null) { +// sm.setAlgorithm(signMethod); +// eidasExtensions.getUnknownXMLObjects().add(sm); +// } else { +// LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); +// } +// } +// } +// return eidasExtensions; +// } +// +// private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { +// EntityAttributes loa = +// (EntityAttributes) BuilderFactoryUtil.buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); +// Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); +// loaAttrib.setName(EidasConstants.LEVEL_OF_ASSURANCE_NAME); +// loaAttrib.setNameFormat(Attribute.URI_REFERENCE); +// XSStringBuilder stringBuilder = +// (XSStringBuilder) Configuration.getBuilderFactory().getBuilder(XSString.TYPE_NAME); +// XSString stringValue = stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, XSString.TYPE_NAME); +// stringValue.setValue(params.getAssuranceLevel()); +// loaAttrib.getAttributeValues().add(stringValue); +// loa.getAttributes().add(loaAttrib); +// eidasExtensions.getUnknownXMLObjects().add(loa); +// +// } +// +// private static final Set<String> DEFAULT_BINDING = new HashSet<String>() {{ +// this.add(SAMLConstants.SAML2_POST_BINDING_URI); +// }}; +// +// private void addAssertionConsumerService() throws EIDASSAMLEngineException { +// int index = 0; +// Set<String> bindings = params.getProtocolBinding().isEmpty() ? DEFAULT_BINDING : params.getProtocolBinding(); +// for (String binding : bindings) { +// AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil.buildXmlObject( +// AssertionConsumerService.DEFAULT_ELEMENT_NAME); +// asc.setLocation(params.getAssertionConsumerUrl()); +// asc.setBinding(checkBinding(binding)); +// asc.setIndex(index); +// if (index == 0) { +// asc.setIsDefault(true); +// } +// index++; +// spSSODescriptor.getAssertionConsumerServices().add(asc); +// } +// } +// +// private String checkBinding(String binding) { +// if (binding != null && (binding.equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) || binding.equals( +// SAMLConstants.SAML2_POST_BINDING_URI))) { +// return binding; +// } +// return SAMLConstants.SAML2_POST_BINDING_URI; +// } +// +// private DateTime getExpireDate() { +// DateTime expiryDate = DateTime.now(); +// expiryDate = +// expiryDate.withFieldAdded(DurationFieldType.seconds(), (int) (getConfigParams().getValidityDuration())); +// return expiryDate; +// } +// +// private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, +// ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) +// throws EIDASSAMLEngineException { +// List<Attribute> attributes = idpssoDescriptor.getAttributes(); +// for (AttributeDefinition<?> attributeDefinition : attributeDefinitions) { +// Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); +// a.setName(attributeDefinition.getNameUri().toASCIIString()); +// a.setFriendlyName(attributeDefinition.getFriendlyName()); +// a.setNameFormat(Attribute.URI_REFERENCE); +// attributes.add(a); +// } +// } +// +// public MetadataConfigParams getConfigParams() { +// return params; +// } +// +// public void setConfigParams(MetadataConfigParams params) { +// this.params = params; +// } +// +//} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java new file mode 100644 index 000000000..bb52d2ffe --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/NewMoaEidasMetadata.java @@ -0,0 +1,602 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang.StringUtils; +import org.joda.time.DateTime; +import org.joda.time.DurationFieldType; +import org.opensaml.Configuration; +import org.opensaml.saml2.common.Extensions; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeValue; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.Company; +import org.opensaml.saml2.metadata.ContactPerson; +import org.opensaml.saml2.metadata.ContactPersonTypeEnumeration; +import org.opensaml.saml2.metadata.EmailAddress; +import org.opensaml.saml2.metadata.EncryptionMethod; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.GivenName; +import org.opensaml.saml2.metadata.IDPSSODescriptor; +import org.opensaml.saml2.metadata.KeyDescriptor; +import org.opensaml.saml2.metadata.LocalizedString; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.Organization; +import org.opensaml.saml2.metadata.OrganizationDisplayName; +import org.opensaml.saml2.metadata.OrganizationName; +import org.opensaml.saml2.metadata.OrganizationURL; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.opensaml.saml2.metadata.SSODescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.saml2.metadata.SurName; +import org.opensaml.saml2.metadata.TelephoneNumber; +import org.opensaml.samlext.saml2mdattr.EntityAttributes; +import org.opensaml.xml.XMLObjectBuilderFactory; +import org.opensaml.xml.schema.XSString; +import org.opensaml.xml.schema.impl.XSStringBuilder; +import org.opensaml.xml.security.SecurityException; +import org.opensaml.xml.security.credential.Credential; +import org.opensaml.xml.security.credential.UsageType; +import org.opensaml.xml.security.keyinfo.KeyInfoGenerator; +import org.opensaml.xml.security.x509.X509KeyInfoGeneratorFactory; +import org.opensaml.xml.signature.KeyInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.ImmutableSortedSet; +import com.google.common.collect.Ordering; + +import eu.eidas.auth.commons.EIDASUtil; +import eu.eidas.auth.commons.EidasStringUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; +import eu.eidas.auth.commons.xml.opensaml.OpenSamlHelper; +import eu.eidas.auth.engine.ProtocolEngineI; +import eu.eidas.auth.engine.core.SAMLExtensionFormat; +import eu.eidas.auth.engine.core.eidas.DigestMethod; +import eu.eidas.auth.engine.core.eidas.SPType; +import eu.eidas.auth.engine.core.eidas.SigningMethod; +import eu.eidas.auth.engine.metadata.ContactData; +import eu.eidas.auth.engine.metadata.EidasMetadata; +import eu.eidas.auth.engine.metadata.MetadataConfigParams; +import eu.eidas.auth.engine.metadata.MetadataSignerI; +import eu.eidas.auth.engine.xml.opensaml.BuilderFactoryUtil; +import eu.eidas.auth.engine.xml.opensaml.CertificateUtil; +import eu.eidas.engine.exceptions.EIDASSAMLEngineException; +import eu.eidas.engine.exceptions.SAMLEngineException; +import eu.eidas.util.Preconditions; + +/** + * @author tlenz + * + * MOA specific implementation of {@link EidasMetadata} + * This version fix some bugs<br> + * <ul> + * <li>Does not add an encryption certificated to IDPSSODescriptor</li> + * <li>Only set provideable eIDAS attributes to IDPSSODescriptor</li> + * <li>SPSSODescriptor only requests 'persistent' subject nameIDs</li> + * </ul> + * + */ +public class NewMoaEidasMetadata { + private static final Logger LOGGER = LoggerFactory.getLogger(EidasMetadata.class.getName()); + private final String metadata; + private final String entityId; + private static final Set<String> DEFAULT_BINDING = new HashSet() { + }; + + private NewMoaEidasMetadata( Generator generator) throws EIDASSAMLEngineException { + this.entityId = generator.entityId; + this.metadata = generator.metadata; + } + + public String getMetadata() { + return this.metadata; + } + + + public static Generator generator() { + return new Generator(); + } + + + public static Generator generator( Generator copy) { + return new Generator(copy); + } + + public static final class Generator { + private XMLObjectBuilderFactory builderFactory = Configuration.getBuilderFactory(); + private MetadataConfigParams params; + private SPSSODescriptor spSSODescriptor = null; + private IDPSSODescriptor idpSSODescriptor = null; + private String ssoLocation; + private String metadata; + private String entityId; + + public Generator() { + } + + public Generator( Generator copy) { + Preconditions.checkNotNull(copy, "copy"); + this.params = copy.params; + this.spSSODescriptor = copy.spSSODescriptor; + this.idpSSODescriptor = copy.idpSSODescriptor; + this.ssoLocation = copy.ssoLocation; + this.entityId = copy.entityId; + } + + + public NewMoaEidasMetadata build() throws EIDASSAMLEngineException { + initialize(); + this.entityId = this.params.getEntityID(); + this.metadata = generateMetadata(); + return new NewMoaEidasMetadata(this); + } + + public Generator configParams(MetadataConfigParams params) { + this.params = params; + return this; + } + + private void generateDigest(Extensions eidasExtensions) throws EIDASSAMLEngineException { + if (!(StringUtils.isEmpty(this.params.getSigningMethods()))) { + Set<String> signatureMethods = EIDASUtil.parseSemicolonSeparatedList(this.params.getSigningMethods()); + Set<String> digestMethods = new HashSet(); + for (String signatureMethod : signatureMethods) { + digestMethods.add(CertificateUtil.validateDigestAlgorithm(signatureMethod)); + } + for (String digestMethod : digestMethods) { + DigestMethod dm = (DigestMethod) BuilderFactoryUtil.buildXmlObject(DigestMethod.DEF_ELEMENT_NAME); + if (dm != null) { + dm.setAlgorithm(digestMethod); + eidasExtensions.getUnknownXMLObjects().add(dm); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding DigestMethod extension"); + } + } + } + } + + private Extensions generateExtensions() throws EIDASSAMLEngineException { + Extensions eidasExtensions = BuilderFactoryUtil.generateMetadataExtension(); + if (this.params.getAssuranceLevel() != null) { + generateLoA(eidasExtensions); + } + if (!(StringUtils.isEmpty(this.params.getSpType()))) { + SPType spTypeObj = (SPType) BuilderFactoryUtil.buildXmlObject(SPType.DEF_ELEMENT_NAME); + if (spTypeObj != null) { + spTypeObj.setSPType(this.params.getSpType()); + eidasExtensions.getUnknownXMLObjects().add(spTypeObj); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding SPType extension"); + } + } + generateDigest(eidasExtensions); + + if (!(StringUtils.isEmpty(this.params.getSigningMethods()))) { + Set<String> signMethods = EIDASUtil.parseSemicolonSeparatedList(this.params.getSigningMethods()); + for (String signMethod : signMethods) { + SigningMethod sm = (SigningMethod) BuilderFactoryUtil + .buildXmlObject(SigningMethod.DEF_ELEMENT_NAME); + + if (sm != null) { + sm.setAlgorithm(signMethod); + eidasExtensions.getUnknownXMLObjects().add(sm); + } else { + NewMoaEidasMetadata.LOGGER.info("BUSINESS EXCEPTION error adding SigningMethod extension"); + } + } + } + return eidasExtensions; + } + + private void generateLoA(Extensions eidasExtensions) throws EIDASSAMLEngineException { + EntityAttributes loa = (EntityAttributes) BuilderFactoryUtil + .buildXmlObject(EntityAttributes.DEFAULT_ELEMENT_NAME); + + Attribute loaAttrib = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); + loaAttrib.setName("urn:oasis:names:tc:SAML:attribute:assurance-certification"); + loaAttrib.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"); + XSStringBuilder stringBuilder = (XSStringBuilder) Configuration.getBuilderFactory() + .getBuilder(XSString.TYPE_NAME); + + XSString stringValue = (XSString) stringBuilder.buildObject(AttributeValue.DEFAULT_ELEMENT_NAME, + XSString.TYPE_NAME); + stringValue.setValue(this.params.getAssuranceLevel()); + loaAttrib.getAttributeValues().add(stringValue); + loa.getAttributes().add(loaAttrib); + eidasExtensions.getUnknownXMLObjects().add(loa); + } + + private void addAssertionConsumerService() throws EIDASSAMLEngineException { + int index = 0; + Set<String> bindings = (this.params.getProtocolBinding().isEmpty()) ? NewMoaEidasMetadata.DEFAULT_BINDING + : this.params.getProtocolBinding(); + for (String binding : bindings) { + AssertionConsumerService asc = (AssertionConsumerService) BuilderFactoryUtil + .buildXmlObject(AssertionConsumerService.DEFAULT_ELEMENT_NAME); + + asc.setLocation(this.params.getAssertionConsumerUrl()); + asc.setBinding(checkBinding(binding)); + asc.setIndex(Integer.valueOf(index)); + if (index == 0) { + asc.setIsDefault(Boolean.valueOf(true)); + } + ++index; + this.spSSODescriptor.getAssertionConsumerServices().add(asc); + } + } + + private String checkBinding(String binding) { + if ((binding != null) && (((binding.equals("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect")) + || (binding.equals("urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"))))) { + return binding; + } + return "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"; + } + + private DateTime getExpireDate() { + DateTime expiryDate = DateTime.now(); + expiryDate = expiryDate.withFieldAdded(DurationFieldType.seconds(), + (int) this.params.getValidityDuration()); + + return expiryDate; + } + + private void generateSupportedAttributes(IDPSSODescriptor idpssoDescriptor, + ImmutableSortedSet<AttributeDefinition<?>> attributeDefinitions) throws EIDASSAMLEngineException { + List attributes = idpssoDescriptor.getAttributes(); + for (AttributeDefinition attributeDefinition : attributeDefinitions) { + Attribute a = (Attribute) BuilderFactoryUtil.buildXmlObject(Attribute.DEFAULT_ELEMENT_NAME); + a.setName(attributeDefinition.getNameUri().toASCIIString()); + a.setFriendlyName(attributeDefinition.getFriendlyName()); + a.setNameFormat("urn:oasis:names:tc:SAML:2.0:attrname-format:uri"); + attributes.add(a); + } + } + + private void generateSPSSODescriptor(EntityDescriptor entityDescriptor, + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) throws SecurityException, IllegalAccessException, + NoSuchFieldException, SAMLEngineException, EIDASSAMLEngineException { + this.spSSODescriptor.setWantAssertionsSigned(Boolean.valueOf(this.params.isWantAssertionsSigned())); + this.spSSODescriptor.setAuthnRequestsSigned(Boolean.valueOf(true)); + if (this.params.getSpSignature() != null) { + this.spSSODescriptor.setSignature(this.params.getSpSignature()); + } + if (this.params.getSpSigningCredential() != null) { + this.spSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getSpSigningCredential(), UsageType.SIGNING)); + } + + if (this.params.getSpEncryptionCredential() != null) { + this.spSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getSpEncryptionCredential(), UsageType.ENCRYPTION)); + } + + this.spSSODescriptor.addSupportedProtocol(this.params.getSpSamlProtocol()); + if (!(StringUtils.isEmpty(this.params.getAssertionConsumerUrl()))) { + addAssertionConsumerService(); + } + + + //fillNameIDFormat(this.spSSODescriptor); + //FIX: Austrian eIDAS node SP only needs persistent identifiers + NameIDFormat persistentFormat = + (NameIDFormat) BuilderFactoryUtil.buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); + spSSODescriptor.getNameIDFormats().add(persistentFormat); + + entityDescriptor.getRoleDescriptors().add(this.spSSODescriptor); + } + + private void fillNameIDFormatIDP(SSODescriptor ssoDescriptor) throws EIDASSAMLEngineException { + NameIDFormat persistentFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + persistentFormat.setFormat(SamlNameIdFormat.PERSISTENT.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(persistentFormat); + NameIDFormat transientFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + transientFormat.setFormat(SamlNameIdFormat.TRANSIENT.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(transientFormat); + NameIDFormat unspecifiedFormat = (NameIDFormat) BuilderFactoryUtil + .buildXmlObject(NameIDFormat.DEFAULT_ELEMENT_NAME); + + unspecifiedFormat.setFormat(SamlNameIdFormat.UNSPECIFIED.getNameIdFormat()); + ssoDescriptor.getNameIDFormats().add(unspecifiedFormat); + } + + private void generateIDPSSODescriptor(EntityDescriptor entityDescriptor, + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory) throws SecurityException, IllegalAccessException, + NoSuchFieldException, SAMLEngineException, EIDASSAMLEngineException { + this.idpSSODescriptor.setWantAuthnRequestsSigned(Boolean.valueOf(true)); + if (this.params.getIdpSignature() != null) { + this.idpSSODescriptor.setSignature(this.params.getIdpSignature()); + } + if (this.params.getIdpSigningCredential() != null) { + this.idpSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, + this.params.getIdpSigningCredential(), UsageType.SIGNING)); + } + + //INFO: IDP requires no encryption certificate +// if (this.params.getIdpEncryptionCredential() != null) { +// this.idpSSODescriptor.getKeyDescriptors().add(getKeyDescriptor(keyInfoGeneratorFactory, +// this.params.getIdpEncryptionCredential(), UsageType.ENCRYPTION)); +// } + + this.idpSSODescriptor.addSupportedProtocol(this.params.getIdpSamlProtocol()); + fillNameIDFormatIDP(this.idpSSODescriptor); + this.idpSSODescriptor.getSingleSignOnServices().addAll(buildSingleSignOnServicesBindingLocations()); + if ((this.params.getIdpEngine() != null) && (this.params.getIdpEngine().getProtocolProcessor() != null) + && (this.params.getIdpEngine().getProtocolProcessor().getFormat() == SAMLExtensionFormat.EIDAS10)) { + + /*TODO: Only a work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata + * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. + * + * INFO: Maybe, this code can be removed in a future version of the eIDAS engine + */ + generateSupportedAttributes(this.idpSSODescriptor, getAllSupportedAttributes()); + } + entityDescriptor.getRoleDescriptors().add(this.idpSSODescriptor); + } + + /* FIX: Work-around to add eIDAS attributes, which could be provided from MOA-ID, to IDP metadata + * If we restrict the eIDAS Engine attribute definitions then also additional incoming attributes can not processed any more. + */ + public ImmutableSortedSet<AttributeDefinition<?>> getAllSupportedAttributes() { + ImmutableSortedSet.Builder<AttributeDefinition<?>> builder = + new ImmutableSortedSet.Builder<>(Ordering.<AttributeDefinition<?>>natural()); + + for (String attr : eIDASAttributeBuilder.getAllProvideableeIDASAttributes()) { + AttributeDefinition<?> supAttr = params.getIdpEngine().getProtocolProcessor().getAttributeDefinitionNullable(attr); + builder.add(supAttr); + } + + return builder.build(); + } + + private ArrayList<SingleSignOnService> buildSingleSignOnServicesBindingLocations() + throws NoSuchFieldException, IllegalAccessException { + ArrayList singleSignOnServices = new ArrayList(); + + HashMap<String, String> bindingLocations = this.params.getProtocolBindingLocation(); + Iterator bindLocs = bindingLocations.entrySet().iterator(); + while (bindLocs.hasNext()) { + Map.Entry bindingLoc = (Map.Entry) bindLocs.next(); + SingleSignOnService ssos = (SingleSignOnService) BuilderFactoryUtil + .buildXmlObject(SingleSignOnService.class); + ssos.setBinding((String) bindingLoc.getKey()); + ssos.setLocation((String) bindingLoc.getValue()); + singleSignOnServices.add(ssos); + } + return singleSignOnServices; + } + + private KeyDescriptor getKeyDescriptor(X509KeyInfoGeneratorFactory keyInfoGeneratorFactory, + Credential credential, UsageType usage) + throws NoSuchFieldException, IllegalAccessException, SecurityException, EIDASSAMLEngineException { + KeyDescriptor keyDescriptor = null; + if (credential != null) { + keyDescriptor = (KeyDescriptor) BuilderFactoryUtil.buildXmlObject(KeyDescriptor.class); + KeyInfoGenerator keyInfoGenerator = keyInfoGeneratorFactory.newInstance(); + + KeyInfo keyInfo = keyInfoGenerator.generate(credential); + keyDescriptor.setUse(usage); + keyDescriptor.setKeyInfo(keyInfo); + if ((usage == UsageType.ENCRYPTION) && (this.params.getEncryptionAlgorithms() != null)) { + Set<String> encryptionAlgos = EIDASUtil.parseSemicolonSeparatedList(this.params.getEncryptionAlgorithms()); + for (String encryptionAlgo : encryptionAlgos) { + EncryptionMethod em = (EncryptionMethod) BuilderFactoryUtil + .buildXmlObject(EncryptionMethod.DEFAULT_ELEMENT_NAME); + + em.setAlgorithm(encryptionAlgo); + keyDescriptor.getEncryptionMethods().add(em); + } + } + } + + return keyDescriptor; + } + + private Organization buildOrganization() { + Organization organization = null; + if (this.params.getOrganization() != null) { + try { + organization = (Organization) BuilderFactoryUtil.buildXmlObject(Organization.class); + OrganizationDisplayName odn = (OrganizationDisplayName) BuilderFactoryUtil + .buildXmlObject(OrganizationDisplayName.class); + odn.setName(new LocalizedString(this.params.getOrganization().getDisplayName(), "en")); + organization.getDisplayNames().add(odn); + OrganizationName on = (OrganizationName) BuilderFactoryUtil.buildXmlObject(OrganizationName.class); + on.setName(new LocalizedString(this.params.getOrganization().getName(), "en")); + organization.getOrganizationNames().add(on); + OrganizationURL url = (OrganizationURL) BuilderFactoryUtil.buildXmlObject(OrganizationURL.class); + url.setURL(new LocalizedString(this.params.getOrganization().getUrl(), "en")); + organization.getURLs().add(url); + } catch (IllegalAccessException iae) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", iae.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", iae); + } catch (NoSuchFieldException nfe) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", nfe.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", nfe); + } + } + return organization; + } + + private ContactPerson buildContact(ContactPersonTypeEnumeration contactType) { + ContactPerson contact = null; + try { + ContactData currentContact = null; + if (contactType == ContactPersonTypeEnumeration.SUPPORT) + currentContact = this.params.getSupportContact(); + else if (contactType == ContactPersonTypeEnumeration.TECHNICAL) + currentContact = this.params.getTechnicalContact(); + else { + NewMoaEidasMetadata.LOGGER.error("ERROR: unsupported contact type"); + } + contact = (ContactPerson) BuilderFactoryUtil.buildXmlObject(ContactPerson.class); + if (currentContact == null) { + NewMoaEidasMetadata.LOGGER.error("ERROR: cannot retrieve contact from the configuration"); + return contact; + } + + EmailAddress emailAddressObj = (EmailAddress) BuilderFactoryUtil.buildXmlObject(EmailAddress.class); + Company company = (Company) BuilderFactoryUtil.buildXmlObject(Company.class); + GivenName givenName = (GivenName) BuilderFactoryUtil.buildXmlObject(GivenName.class); + SurName surName = (SurName) BuilderFactoryUtil.buildXmlObject(SurName.class); + TelephoneNumber phoneNumber = (TelephoneNumber) BuilderFactoryUtil + .buildXmlObject(TelephoneNumber.class); + contact.setType(contactType); + emailAddressObj.setAddress(currentContact.getEmail()); + company.setName(currentContact.getCompany()); + givenName.setName(currentContact.getGivenName()); + surName.setName(currentContact.getSurName()); + phoneNumber.setNumber(currentContact.getPhone()); + + populateContact(contact, currentContact, emailAddressObj, company, givenName, surName, phoneNumber); + } catch (IllegalAccessException iae) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", iae.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", iae); + } catch (NoSuchFieldException nfe) { + NewMoaEidasMetadata.LOGGER.info("ERROR : error generating the OrganizationData: {}", nfe.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : error generating the OrganizationData: {}", nfe); + } + return contact; + } + + private void populateContact(ContactPerson contact, ContactData currentContact, EmailAddress emailAddressObj, + Company company, GivenName givenName, SurName surName, TelephoneNumber phoneNumber) { + if (!(StringUtils.isEmpty(currentContact.getEmail()))) { + contact.getEmailAddresses().add(emailAddressObj); + } + if (!(StringUtils.isEmpty(currentContact.getCompany()))) { + contact.setCompany(company); + } + if (!(StringUtils.isEmpty(currentContact.getGivenName()))) { + contact.setGivenName(givenName); + } + if (!(StringUtils.isEmpty(currentContact.getSurName()))) { + contact.setSurName(surName); + } + if (!(StringUtils.isEmpty(currentContact.getPhone()))) + contact.getTelephoneNumbers().add(phoneNumber); + } + + private String generateMetadata() throws EIDASSAMLEngineException { + try { + EntityDescriptor entityDescriptor = (EntityDescriptor) this.builderFactory + .getBuilder(EntityDescriptor.DEFAULT_ELEMENT_NAME) + .buildObject(EntityDescriptor.DEFAULT_ELEMENT_NAME); + + entityDescriptor.setEntityID(this.params.getEntityID()); + entityDescriptor.setOrganization(buildOrganization()); + entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.SUPPORT)); + entityDescriptor.getContactPersons().add(buildContact(ContactPersonTypeEnumeration.TECHNICAL)); + entityDescriptor.setValidUntil(getExpireDate()); + + X509KeyInfoGeneratorFactory keyInfoGeneratorFactory = new X509KeyInfoGeneratorFactory(); + keyInfoGeneratorFactory.setEmitEntityCertificate(true); + Extensions e = generateExtensions(); + if (!(e.getUnknownXMLObjects().isEmpty())) { + entityDescriptor.setExtensions(e); + } + if (this.spSSODescriptor != null) { + generateSPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); + } + if (this.idpSSODescriptor != null) { + generateIDPSSODescriptor(entityDescriptor, keyInfoGeneratorFactory); + } + if (this.params.getSpEngine() != null) { + ProtocolEngineI spEngine = this.params.getSpEngine(); + ((MetadataSignerI) spEngine.getSigner()).signMetadata(entityDescriptor); + } else if (this.params.getIdpEngine() != null) { + ProtocolEngineI idpEngine = this.params.getIdpEngine(); + ((MetadataSignerI) idpEngine.getSigner()).signMetadata(entityDescriptor); + } + return EidasStringUtil.toString(OpenSamlHelper.marshall(entityDescriptor, false)); + } catch (Exception ex) { + NewMoaEidasMetadata.LOGGER.info("ERROR : SAMLException ", ex.getMessage()); + NewMoaEidasMetadata.LOGGER.debug("ERROR : SAMLException ", ex); + throw new IllegalStateException(ex); + } + } + + private void initialize() throws EIDASSAMLEngineException { + ProtocolEngineI idpEngine = this.params.getIdpEngine(); + ProtocolEngineI spEngine = this.params.getSpEngine(); + MetadataConfigParams.Builder initParamBuilder = MetadataConfigParams.builder(this.params); + if (idpEngine != null) { + idpEngine.getProtocolProcessor().configure(); + initParamBuilder.idpSigningCredential(CertificateUtil.toCredential(idpEngine.getSigningCertificate())); + + X509Certificate idpEngineDecryptionCertificate = idpEngine.getDecryptionCertificate(); + if (idpEngineDecryptionCertificate != null) { + initParamBuilder + .idpEncryptionCredential(CertificateUtil.toCredential(idpEngineDecryptionCertificate)); + } + if (this.idpSSODescriptor == null) { + try { + this.idpSSODescriptor = ((IDPSSODescriptor) BuilderFactoryUtil + .buildXmlObject(IDPSSODescriptor.class)); + } catch (NoSuchFieldException e) { + throw new EIDASSAMLEngineException(e); + } catch (IllegalAccessException e) { + throw new EIDASSAMLEngineException(e); + } + } + } + if (spEngine != null) { + spEngine.getProtocolProcessor().configure(); + initParamBuilder.spSigningCredential(CertificateUtil.toCredential(spEngine.getSigningCertificate())); + + X509Certificate spEngineDecryptionCertificate = spEngine.getDecryptionCertificate(); + if (spEngineDecryptionCertificate != null) { + initParamBuilder + .spEncryptionCredential(CertificateUtil.toCredential(spEngineDecryptionCertificate)); + } + if (this.spSSODescriptor == null) { + try { + this.spSSODescriptor = ((SPSSODescriptor) BuilderFactoryUtil + .buildXmlObject(SPSSODescriptor.class)); + } catch (NoSuchFieldException e) { + throw new EIDASSAMLEngineException(e); + } catch (IllegalAccessException e) { + throw new EIDASSAMLEngineException(e); + } + } + } + this.params = initParamBuilder.build(); + } + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java index 70135c06f..02a5df098 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/SAMLEngineUtils.java @@ -23,9 +23,12 @@ package at.gv.egovernment.moa.id.auth.modules.eidas.utils; import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; import java.util.HashMap; import java.util.Map; +import org.opensaml.common.xml.SAMLSchemaBuilder; import org.opensaml.xml.ConfigurationException; import org.opensaml.xml.XMLConfigurator; @@ -36,8 +39,13 @@ import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAEidasProtocolProces import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASMetadataProviderDecorator; import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeRegistries; +import eu.eidas.auth.commons.attribute.AttributeRegistry; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.SamlEngineSystemClock; import eu.eidas.auth.engine.metadata.MetadataFetcherI; @@ -62,6 +70,7 @@ public class SAMLEngineUtils { if (eIDASEngine == null) { try { + //get eIDAS SAMLengine configuration from MOA-ID configuration CertificateConfigurationManager configManager = new MOAIDCertificateManagerConfigurationImpl(); @@ -70,12 +79,25 @@ public class SAMLEngineUtils { //set metadata signer metadataSigner = new MOAExtendedSWSigner(configManager); - + + //load additional eIDAS attribute definitions + String additionalAttributeConfigFile = + AuthConfigurationProviderFactory.getInstance().getBasicMOAIDConfiguration( + Constants.CONIG_PROPS_EIDAS_SAMLENGINE_ATTIONAL_ATTRIBUTE_DEFINITIONS); + AttributeRegistry addAttrDefinitions = AttributeRegistries.empty(); + if (MiscUtil.isNotEmpty(additionalAttributeConfigFile)) { + URL addAttrConfigUrl = new URL(FileUtils.makeAbsoluteURL( + additionalAttributeConfigFile, + AuthConfigurationProviderFactory.getInstance().getRootConfigFileDir())); + addAttrDefinitions = AttributeRegistries.fromFile(addAttrConfigUrl.getPath(), null); + + } + //build eIDAS SAML eninge - ProtocolEngineI engine = MOAProtocolEngineFactory.createProtocolEngine( + ProtocolEngineI engine = MOAProtocolEngineFactory.ownCreateProtocolEngine( Constants.eIDAS_SAML_ENGINE_NAME, configManager, - new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner), + new MOAEidasProtocolProcesser(metadataFetcher, metadataSigner, addAttrDefinitions), new SamlEngineSystemClock()); //build a map with all actually supported attributes @@ -86,6 +108,9 @@ public class SAMLEngineUtils { //overwrite eIDAS response validator suite because Condition-Valitator has not time jitter initOpenSAMLConfig("own-saml-eidasnode-config.xml"); + //add eIDAS specific SAML2 extensions to eIDAS Schema validatior + SAMLSchemaBuilder.addExtensionSchema( + at.gv.egovernment.moa.util.Constants.SAML2_eIDAS_EXTENSIONS_SCHEMA_LOCATION); eIDASEngine = engine; @@ -93,6 +118,14 @@ public class SAMLEngineUtils { Logger.error("eIDAS SAMLengine initialization FAILED!", e); throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } catch (at.gv.egovernment.moa.id.commons.api.exceptions.ConfigurationException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + + } catch (MalformedURLException e) { + Logger.error("eIDAS SAMLengine initialization FAILED!", e); + throw new EIDASEngineException("eIDAS.00", new Object[]{e.getMessage()}, e); + } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java new file mode 100644 index 000000000..22b94178e --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/auth/modules/eidas/utils/eIDASAttributeBuilder.java @@ -0,0 +1,174 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.auth.modules.eidas.utils; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; + +import com.google.common.collect.ImmutableSet; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAttributeBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.eidas.auth.commons.attribute.AttributeDefinition; +import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; +import eu.eidas.auth.commons.attribute.AttributeValue; +import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; +import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; + +/** + * @author tlenz + * + */ +public class eIDASAttributeBuilder extends PVPAttributeBuilder { + private static IAttributeGenerator<String> generator = new SimpleEidasAttributeGenerator(); + + private static List<String> listOfSupportedeIDASAttributes; + private static ServiceLoader<IeIDASAttribute> eIDASAttributLoader = + ServiceLoader.load(IeIDASAttribute.class); + + static { + List<String> supportAttrList = new ArrayList<String>(); + + Logger.info("Select eIDAS attributes that are corrently providable:"); + if (eIDASAttributLoader != null ) { + Iterator<IeIDASAttribute> moduleLoaderInterator = eIDASAttributLoader.iterator(); + while (moduleLoaderInterator.hasNext()) { + try { + IeIDASAttribute modul = moduleLoaderInterator.next(); + Logger.info("Loading eIDAS attribut-builder Modul Information: " + modul.getName()); + supportAttrList.add(modul.getName()); + + } catch(Throwable e) { + Logger.error("Check configuration! " + "Some attribute-builder modul" + + " is not a valid IAttributeBuilder", e); + } + } + } + + listOfSupportedeIDASAttributes = Collections.unmodifiableList(supportAttrList); + Logger.info("Selection of providable eIDAS attributes done"); + + } + + /** + * Get all eIDAS attribute names that can be generated by the Austrian eIDAS node. + * This list is dynamically generated from loaded eIDAS attribute builders that are found in Java Classpath + * + * @return {@link List} of {@link String} of eIDAS attribute names + */ + public static List<String> getAllProvideableeIDASAttributes() { + return listOfSupportedeIDASAttributes; + } + + /** + * This method build an eIDAS response attribute, by using a loaded eIDAS attribute builder. + * + * @param attr eIDAS attribute that should be generated + * @param onlineApplicationConfiguration SP configuration + * @param authData Authentication data that contains user information for attribute generation + * @return eIDAS attribute response {@link Pair} or null if the attribute generation FAILES + */ + public static Pair<AttributeDefinition<?>,ImmutableSet<AttributeValue<?>>> buildAttribute(AttributeDefinition<?> attr, IOAAuthParameters onlineApplicationConfiguration, + IAuthData authData) { + + String attrName = attr.getNameUri().toString(); + Logger.trace("Build eIDAS attribute: "+ attrName); + + + IAttributeBuilder attrBuilder = getAttributeBuilder(attrName); + if (attrBuilder != null) { + try { + String attrValue = attrBuilder.build(onlineApplicationConfiguration, authData, generator); + if (MiscUtil.isNotEmpty(attrValue)) { + //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the + // Subject->NameID value from this attribute + Builder<?> eIDASAttrBuilder = AttributeDefinition.builder(attr); + eIDASAttrBuilder.uniqueIdentifier(evaluateUniqueID(attrName, authData.isUseMandate())); + AttributeDefinition<?> returnAttr = eIDASAttrBuilder.build(); + + //unmarshal attribute value into eIDAS attribute + AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); + ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); + + AttributeValue<?> attributeValue = null; + try { + attributeValue = attributeValueMarshaller.unmarshal(attrValue, false); + builder.add(attributeValue); + + } catch (AttributeValueMarshallingException e) { + throw new IllegalStateException(e); + + } + + return Pair.newInstance(returnAttr, builder.build()); + + } + + } catch (AttributeException e) { + Logger.debug("Attribute can not generate requested attribute:" + attr.getNameUri().toString() + " Reason:" + e.getMessage()); + + } + + } else + Logger.warn("NO attribute builder FOUND for eIDAS attr: " + attrName); + + return null; + } + + /** + * This method use the information from authenticated session and + * evaluate the uniqueID flag according to eIDAS specification + * + * @param attrName eIDAS attribute name that is evaluated + * @param useMandate flag that indicates if the current authenticated session includes a mandate + * @return true if eIDAS attribute holds the unique ID, otherwise false + */ + private static boolean evaluateUniqueID(String attrName, boolean useMandate) { + //if no mandate is used the natural person identifier is the unique ID + if (!useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //if mandates are used the the legal person identifier or the natural person identifier of the mandator is the unique ID + else if (useMandate && + attrName.equals(eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString())) + return true; + + //TODO: implement flag selector for mandates and natural persons + + + return false; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java index 7647b4cab..694efab80 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASData.java @@ -15,6 +15,8 @@ import eu.eidas.auth.commons.protocol.IAuthenticationRequest; @Scope(value = BeanDefinition.SCOPE_PROTOTYPE) public class EIDASData extends RequestImpl { + public static final String REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID = "transiendIDRequested"; + /** The Constant serialVersionUID. */ private static final long serialVersionUID = 8765755670214923910L; @@ -28,7 +30,7 @@ public class EIDASData extends RequestImpl { private String remoteIPAddress; private String remoteRelayState; - + @Override public Collection<String> getRequestedAttributes(MetadataProvider metadataProvider) { // TODO Auto-generated method stub diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java index 388d65963..940b91b44 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EIDASProtocol.java @@ -67,6 +67,7 @@ import eu.eidas.auth.commons.protocol.eidas.IEidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.eidas.impl.EidasAuthenticationRequest; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse.Builder; +import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.metadata.MetadataUtil; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -307,6 +308,13 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { pendingReq.setGenericDataToSession(RequestImpl.eIDAS_GENERIC_REQ_DATA_LEVELOFASSURENCE, eIDASSamlReq.getEidasLevelOfAssurance().stringValue()); + //set flag if transiend identifier is requested + if (MiscUtil.isNotEmpty(eIDASSamlReq.getNameIdFormat()) + && eIDASSamlReq.getNameIdFormat().equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, true); + else + pendingReq.setGenericDataToSession(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, false); + // - memorize requested attributes pendingReq.setEidasRequestedAttributes(eIDASSamlReq.getRequestedAttributes()); @@ -322,7 +330,7 @@ public class EIDASProtocol extends AbstractAuthProtocolModulController { // - memorize service-provider type from eIDAS request String spType = null; if (eIDASSamlReq.getSpType() != null) - spType = eIDASSamlReq.getSpType().getValue(); + spType = eIDASSamlReq.getSpType(); if (MiscUtil.isEmpty(spType)) spType = MetadataUtil.getSPTypeFromMetadata(eIDASNodeEntityDesc); diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java index df96bef12..cc9b09107 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/EidasMetaDataRequest.java @@ -31,7 +31,7 @@ import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.exceptions.EIDASEngineException; -import at.gv.egovernment.moa.id.auth.modules.eidas.utils.MOAeIDASMetadataGenerator; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.NewMoaEidasMetadata; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; import at.gv.egovernment.moa.id.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; @@ -44,8 +44,10 @@ import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.protocols.pvp2x.config.PVPConfiguration; import at.gv.egovernment.moa.logging.Logger; import eu.eidas.auth.engine.ProtocolEngineI; -import eu.eidas.auth.engine.metadata.Contact; +import eu.eidas.auth.engine.metadata.ContactData; import eu.eidas.auth.engine.metadata.MetadataConfigParams; +import eu.eidas.auth.engine.metadata.MetadataConfigParams.Builder; +import eu.eidas.auth.engine.metadata.OrganizationData; import eu.eidas.engine.exceptions.EIDASSAMLEngineException; @@ -119,22 +121,21 @@ public class EidasMetaDataRequest implements IAction { ProtocolEngineI engine = SAMLEngineUtils.createSAMLEngine(eIDASMetadataProvider); - MOAeIDASMetadataGenerator generator = new MOAeIDASMetadataGenerator(); - MetadataConfigParams mcp=new MetadataConfigParams(); - generator.setConfigParams(mcp); - generator.initialize(engine); - - mcp.setEntityID(metadata_url); - mcp.setAssertionConsumerUrl(sp_return_url); - mcp.getProtocolBindingLocation().put( + //configura metadata builder + Builder metadataConfigBuilder = MetadataConfigParams.builder(); + metadataConfigBuilder.entityID(metadata_url); + metadataConfigBuilder.assertionConsumerUrl(sp_return_url); + + metadataConfigBuilder.addProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI); + metadataConfigBuilder.addProtocolBindingLocation( SAMLConstants.SAML2_POST_BINDING_URI, pendingReq.getAuthURL() + Constants.eIDAS_HTTP_ENDPOINT_IDP_COLLEAGUEREQUEST); //TODO: make it configurable - mcp.setAuthnRequestsSigned(true); - mcp.setWantAssertionsSigned(true); - mcp.setAssuranceLevel( + metadataConfigBuilder.authnRequestsSigned(true); + metadataConfigBuilder.wantAssertionsSigned(true); + metadataConfigBuilder.assuranceLevel( authConfig.getBasicMOAIDConfiguration( Constants.CONIG_PROPS_EIDAS_NODE_LoA, MOAIDAuthConstants.eIDAS_LOA_HIGH)); @@ -142,47 +143,71 @@ public class EidasMetaDataRequest implements IAction { //must be set in request, because it could be different for every online-application //mcp.setSpType(SPType.DEFAULT_VALUE); - mcp.setDigestMethods(Constants.METADATA_ALLOWED_ALG_DIGIST); - mcp.setSigningMethods(Constants.METADATA_ALLOWED_ALG_SIGN); - mcp.setEncryptionAlgorithms(Constants.METADATA_ALLOWED_ALG_ENCRYPT); + metadataConfigBuilder.digestMethods(Constants.METADATA_ALLOWED_ALG_DIGIST); + metadataConfigBuilder.signingMethods(Constants.METADATA_ALLOWED_ALG_SIGN); + metadataConfigBuilder.encryptionAlgorithms(Constants.METADATA_ALLOWED_ALG_ENCRYPT); //add organisation information from PVP metadata information Organization pvpOrganisation = null; try { pvpOrganisation = PVPConfiguration.getInstance().getIDPOrganisation(); - Contact technicalContact = new Contact(); + eu.eidas.auth.engine.metadata.ContactData.Builder technicalContact = ContactData.builder(); List<ContactPerson> contacts = PVPConfiguration.getInstance().getIDPContacts(); if (contacts != null && contacts.size() >= 1) { ContactPerson contact = contacts.get(0); - technicalContact.setGivenName(contact.getGivenName().getName()); - technicalContact.setSurName(contact.getSurName().getName()); + technicalContact.givenName(contact.getGivenName().getName()); + technicalContact.surName(contact.getSurName().getName()); if (!contact.getEmailAddresses().isEmpty()) - technicalContact.setEmail(contact.getEmailAddresses().get(0).getAddress()); + technicalContact.email(contact.getEmailAddresses().get(0).getAddress()); if (!contact.getTelephoneNumbers().isEmpty()) - technicalContact.setPhone(contact.getTelephoneNumbers().get(0).getNumber()); + technicalContact.phone(contact.getTelephoneNumbers().get(0).getNumber()); - mcp.setTechnicalContact(technicalContact ); + } if (pvpOrganisation != null) { - mcp.setNodeUrl(pvpOrganisation.getURLs().get(0).getURL().getLocalString()); - mcp.setCountryName(authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRY, "Austria")); - technicalContact.setCompany(pvpOrganisation.getDisplayNames().get(0).getName().getLocalString()); + eu.eidas.auth.engine.metadata.OrganizationData.Builder organizationConfig = OrganizationData.builder(); + organizationConfig.url(pvpOrganisation.getURLs().get(0).getURL().getLocalString()); + organizationConfig.name(authConfig.getBasicMOAIDConfiguration(Constants.CONIG_PROPS_EIDAS_NODE_COUNTRY, "Austria")); + //TODO: add display name and maybe update name + + + metadataConfigBuilder.organization(organizationConfig.build()); + + technicalContact.company(pvpOrganisation.getDisplayNames().get(0).getName().getLocalString()); } + + metadataConfigBuilder.technicalContact(technicalContact.build()); + + //TODO: add correct support contact + metadataConfigBuilder.supportContact(ContactData.builder(technicalContact.build()).build()); + } catch (ConfigurationException | NullPointerException e) { Logger.warn("Can not load Organisation or Contact from Configuration", e); } - - generator.addSPRole(); - generator.addIDPRole(); + + metadataConfigBuilder.idpEngine(engine); + metadataConfigBuilder.spEngine(engine); + + //TODO: +// MOAeIDASMetadataGenerator generator = new MOAeIDASMetadataGenerator(); +// generator.initialize(engine); +// generator.addSPRole(); +// generator.addIDPRole(); +// metadata = generator.generateMetadata(); + + //use own implementation that solves some problems in original implementation + NewMoaEidasMetadata.Generator generator = NewMoaEidasMetadata.generator(); + generator.configParams(metadataConfigBuilder.build()); + NewMoaEidasMetadata eidasMetadata = generator.build(); + metadata = eidasMetadata.getMetadata(); - metadata = generator.generateMetadata(); return metadata; } } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java new file mode 100644 index 000000000..15060fb52 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/IeIDASAttribute.java @@ -0,0 +1,33 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder; + +/** + * @author tlenz + * + */ +public interface IeIDASAttribute extends IAttributeBuilder{ + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java new file mode 100644 index 000000000..64e5ae770 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrDateOfBirth.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.BirthdateAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrDateOfBirth extends BirthdateAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.DATE_OF_BIRTH.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java new file mode 100644 index 000000000..4195eeeef --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrFamilyName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrFamilyName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_FAMILY_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getFamilyName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java new file mode 100644 index 000000000..2a654ac44 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrGivenName.java @@ -0,0 +1,61 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; + +/** + * @author tlenz + * + */ +public class eIDASAttrGivenName implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.CURRENT_GIVEN_NAME.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + return g.buildStringAttribute(null, getName(), authData.getGivenName()); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java new file mode 100644 index 000000000..51a2bd69b --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalName.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalName extends MandateLegalPersonFullNameAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_NAME.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java new file mode 100644 index 000000000..c008048cb --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrLegalPersonIdentifier.java @@ -0,0 +1,37 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; + +/** + * @author tlenz + * + */ +public class eIDASAttrLegalPersonIdentifier extends MandateLegalPersonSourcePinAttributeBuilder implements IeIDASAttribute { + + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.LegalPersonSpec.Definitions.LEGAL_PERSON_IDENTIFIER.getNameUri().toString(); + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java new file mode 100644 index 000000000..cb659c2b1 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/attributes/builder/eIDASAttrNaturalPersonalIdentifier.java @@ -0,0 +1,116 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the "Licence"); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * http://www.osor.eu/eupl/ + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text + * file for details on the various modules and licenses. + * The "NOTICE" text file is part of the distribution. Any derivative works + * that you distribute must include a readable copy of the "NOTICE" text file. + */ +package at.gv.egovernment.moa.id.protocols.eidas.attributes.builder; + +import java.security.MessageDigest; + +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Trible; +import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; +import at.gv.egovernment.moa.id.protocols.eidas.EIDASData; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +public class eIDASAttrNaturalPersonalIdentifier implements IeIDASAttribute{ + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#getName() + */ + @Override + public String getName() { + return eu.eidas.auth.engine.core.eidas.spec.NaturalPersonSpec.Definitions.PERSON_IDENTIFIER.getNameUri().toString(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#build(at.gv.egovernment.moa.id.commons.api.IOAAuthParameters, at.gv.egovernment.moa.id.data.IAuthData, at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT build(IOAAuthParameters oaParam, IAuthData authData, IAttributeGenerator<ATT> g) + throws AttributeException { + String personalID = authData.getBPK(); + + //generate eIDAS conform 'PersonalIdentifier' attribute + if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(personalID)) { + Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); + if (MiscUtil.isEmpty(authData.getBPKType()) + || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { + Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); + throw new AttributeException("Suspect bPKType for eIDAS identifier generation"); + + } + + String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); + personalID = prefix.replaceAll("\\+", "/") + "/" + personalID; + + } + + //generate a transient unique identifier if it is requested + Boolean isTransiendIDRequested = + authData.getGenericData(EIDASData.REQ_PARAM_eIDAS_AUTHN_TRANSIENT_ID, Boolean.class); + if (isTransiendIDRequested != null && isTransiendIDRequested) + personalID = generateTransientNameID(personalID); + + return g.buildStringAttribute(null, getName(), personalID); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder#buildEmpty(at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator) + */ + @Override + public <ATT> ATT buildEmpty(IAttributeGenerator<ATT> g) { + return null; + } + + private String generateTransientNameID(String nameID) { + //extract source-country and destination country from persistent identifier + Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); + if (split == null) { + Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); + + } + + //build correct formated transient identifier + String random = Random.nextLongRandom(); + try { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1")); + return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash); + + } catch (Exception e) { + Logger.error("Can not generate transient personal identifier!", e); + return null; + + } + + } +} diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java index 2fe52bb4f..d0cda38c7 100644 --- a/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java +++ b/id/server/modules/moa-id-module-eIDAS/src/main/java/at/gv/egovernment/moa/id/protocols/eidas/eIDASAuthenticationRequest.java @@ -23,8 +23,6 @@ package at.gv.egovernment.moa.id.protocols.eidas; import java.io.StringWriter; -import java.security.MessageDigest; -import java.text.SimpleDateFormat; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -43,33 +41,23 @@ import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SimpleEidasAttributeGenerator; -import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeProcessingUtils; +import at.gv.egovernment.moa.id.auth.modules.eidas.utils.eIDASAttributeBuilder; import at.gv.egovernment.moa.id.commons.MOAIDConstants; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.Pair; import at.gv.egovernment.moa.id.data.SLOInformationImpl; import at.gv.egovernment.moa.id.data.SLOInformationInterface; -import at.gv.egovernment.moa.id.data.Trible; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeGenerator; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonFullNameAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.builder.attributes.MandateLegalPersonSourcePinAttributeBuilder; -import at.gv.egovernment.moa.id.protocols.pvp2x.builder.attributes.exceptions.AttributeException; -import at.gv.egovernment.moa.id.util.Random; import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.util.Base64Utils; -import at.gv.egovernment.moa.util.MiscUtil; import eu.eidas.auth.commons.EidasStringUtil; import eu.eidas.auth.commons.attribute.AttributeDefinition; -import eu.eidas.auth.commons.attribute.AttributeDefinition.Builder; import eu.eidas.auth.commons.attribute.AttributeValue; -import eu.eidas.auth.commons.attribute.AttributeValueMarshaller; -import eu.eidas.auth.commons.attribute.AttributeValueMarshallingException; import eu.eidas.auth.commons.attribute.ImmutableAttributeMap; import eu.eidas.auth.commons.protocol.IResponseMessage; import eu.eidas.auth.commons.protocol.impl.AuthenticationResponse; -import eu.eidas.auth.commons.protocol.impl.SamlNameIdFormat; import eu.eidas.auth.engine.ProtocolEngineI; import eu.eidas.auth.engine.xml.opensaml.SAMLEngineUtils; @@ -97,104 +85,31 @@ public class eIDASAuthenticationRequest implements IAction { else throw new MOAIDException("got wrong IRequest type. is: {}, should be: {}", new String[] {req.getClass().toString(), EIDASData.class.toString()}); - + String subjectNameID = null; - + //gather attributes ImmutableAttributeMap reqAttributeList = (ImmutableAttributeMap) eidasRequest.getEidasRequestedAttributes(); ImmutableAttributeMap.Builder attrMapBuilder = ImmutableAttributeMap.builder(); - - //TODO: if we support more then this minimum required attributes -> redesign to a smoother attribute builder selector + + //generate eIDAS attributes for(AttributeDefinition<?> attr : reqAttributeList.getDefinitions()) { - String newValue = ""; - boolean isUniqueID = false; - try { - switch(attr.getFriendlyName()) { - case Constants.eIDAS_ATTR_DATEOFBIRTH: - newValue = new SimpleDateFormat("YYYY-MM-dd").format(authData.getDateOfBirth()); - break; - case Constants.eIDAS_ATTR_CURRENTFAMILYNAME: - newValue = authData.getFamilyName(); - break; - case Constants.eIDAS_ATTR_CURRENTGIVENNAME: - newValue = authData.getGivenName(); - break; - case Constants.eIDAS_ATTR_PERSONALIDENTIFIER: - newValue = authData.getBPK(); - isUniqueID = true; + Pair<AttributeDefinition<?>, ImmutableSet<AttributeValue<?>>> eIDASAttr = eIDASAttributeBuilder.buildAttribute( + attr, req.getOnlineApplicationConfiguration(), authData); - //generate eIDAS conform 'PersonalIdentifier' attribute - if (!eIDASAttributeProcessingUtils.validateEidasPersonalIdentifier(newValue)) { - Logger.debug("preCalculated PersonalIdentifier does not include eIDAS conform prefixes ... add prefix now"); - if (MiscUtil.isEmpty(authData.getBPKType()) - || !authData.getBPKType().startsWith(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS)) { - Logger.error("BPKType is empty or does not start with eIDAS bPKType prefix! bPKType:" + authData.getBPKType()); - throw new MOAIDException("builder.08", new Object[]{"Suspect bPKType for eIDAS identifier generation"}); - - } - - String prefix = authData.getBPKType().substring(at.gv.egovernment.moa.util.Constants.URN_PREFIX_EIDAS.length() + 1); - newValue = prefix.replaceAll("\\+", "/") + "/" + newValue; - - } - - //generate a transient unique identifier if it is requested - String reqNameIDFormat = eidasRequest.getEidasRequest().getNameIdFormat(); - if (MiscUtil.isNotEmpty(reqNameIDFormat) - && reqNameIDFormat.equals(SamlNameIdFormat.TRANSIENT.getNameIdFormat())) - newValue = generateTransientNameID(newValue); - - - subjectNameID = newValue; - break; - case Constants.eIDAS_ATTR_LEGALPERSONIDENTIFIER: - newValue = new MandateLegalPersonSourcePinAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - case Constants.eIDAS_ATTR_LEGALNAME: - newValue = new MandateLegalPersonFullNameAttributeBuilder().build( - req.getOnlineApplicationConfiguration(), authData, generator); - break; - - } - - } catch (AttributeException e) { - Logger.debug("Attribute can not generate requested attribute:" + attr.getFriendlyName() + " Reason:" + e.getMessage()); - - } - - if(MiscUtil.isEmpty(newValue)) { + if(eIDASAttr == null) { if (attr.isRequired()) { Logger.info("eIDAS Attr:" + attr.getNameUri() + " is marked as 'Required' but not available."); throw new MOAIDException("eIDAS.15", new Object[]{attr.getFriendlyName()}); } else Logger.info("eIDAS Attr:" + attr.getNameUri() + " is not available."); - } else { - //set uniqueIdentifier attribute, because eIDAS SAMLEngine use this flag to select the - // Subject->NameID value from this attribute - Builder<?> attrBuilder = AttributeDefinition.builder(attr); - attrBuilder.uniqueIdentifier(isUniqueID); - AttributeDefinition<?> returnAttr = attrBuilder.build(); - - //unmarshal attribute value into eIDAS attribute - AttributeValueMarshaller<?> attributeValueMarshaller = returnAttr.getAttributeValueMarshaller(); - ImmutableSet.Builder<AttributeValue<?>> builder = ImmutableSet.builder(); - - AttributeValue<?> attributeValue = null; - try { - attributeValue = attributeValueMarshaller.unmarshal(newValue, false); - builder.add(attributeValue); - - } catch (AttributeValueMarshallingException e) { - throw new IllegalStateException(e); - - } - - //add attribute to Map - attrMapBuilder.put((AttributeDefinition)returnAttr, (ImmutableSet) builder.build()); + //add attribute to Map + attrMapBuilder.put( + (AttributeDefinition)eIDASAttr.getFirst(), + (ImmutableSet)eIDASAttr.getSecond()); } } @@ -231,19 +146,7 @@ public class eIDASAuthenticationRequest implements IAction { eIDASRespMsg = engine.generateResponseMessage(eidasRequest.getEidasRequest(), response, true, eidasRequest.getRemoteAddress()); - -// if(null == eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()) { -// String assertionConsumerUrl = MetadataUtil.getAssertionUrlFromMetadata( -// new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider), -// engine, -// eidasRequest.getEidasRequest()); -// eidasRequest.getEidasRequest().setAssertionConsumerServiceURL(assertionConsumerUrl); -// -// } - -// response = engine.generateEIDASAuthnResponse(eidasRequest.getEidasRequest(), response, eidasRequest.getRemoteAddress(), true); - - + token = EidasStringUtil.encodeToBase64(eIDASRespMsg.getMessageBytes()); } catch(Exception e) { @@ -319,28 +222,6 @@ public class eIDASAuthenticationRequest implements IAction { } - private String generateTransientNameID(String nameID) { - //extract source-country and destination country from persistent identifier - Trible<String, String, String> split = eIDASAttributeProcessingUtils.parseEidasPersonalIdentifier(nameID); - if (split == null) { - Logger.error("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); - throw new IllegalStateException("eIDAS 'PersonalIdentifier' has a wrong format. There had to be a ERROR in implementation!!!!"); - - } - - //build correct formated transient identifier - String random = Random.nextLongRandom(); - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] hash = md.digest((split.getThird() + random).getBytes("ISO-8859-1")); - return split.getFirst() + "/" + split.getSecond() + "/" + Base64Utils.encode(hash); - - } catch (Exception e) { - Logger.error("Can not generate transient personal identifier!", e); - return null; - - } - - } + } diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder new file mode 100644 index 000000000..62e7c20ab --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.builder.attributes.IAttributeBuilder @@ -0,0 +1,6 @@ +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrDateOfBirth +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrFamilyName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrGivenName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrNaturalPersonalIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalPersonIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalName diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute new file mode 100644 index 000000000..62e7c20ab --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.IeIDASAttribute @@ -0,0 +1,6 @@ +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrDateOfBirth +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrFamilyName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrGivenName +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrNaturalPersonalIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalPersonIdentifier +at.gv.egovernment.moa.id.protocols.eidas.attributes.builder.eIDASAttrLegalName diff --git a/id/server/modules/moa-id-module-eIDAS/src/main/resources/schema/eIDAS_saml_extensions.xsd b/id/server/modules/moa-id-module-eIDAS/src/main/resources/schema/eIDAS_saml_extensions.xsd new file mode 100644 index 000000000..76b82a267 --- /dev/null +++ b/id/server/modules/moa-id-module-eIDAS/src/main/resources/schema/eIDAS_saml_extensions.xsd @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8"?> +<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:eidas="http://eidas.europa.eu/saml-extensions" targetNamespace="http://eidas.europa.eu/saml-extensions" elementFormDefault="qualified" attributeFormDefault="unqualified"> + + <xsd:element name="SPType" type="eidas:SPTypeType"/> + <xsd:simpleType name="SPTypeType"> + <xsd:restriction base="xsd:string"> + <xsd:enumeration value="public"/> + <xsd:enumeration value="private"/> + </xsd:restriction> + </xsd:simpleType> + + <xsd:element name="RequestedAttributes" type="eidas:RequestedAttributesType"/> + <xsd:complexType name="RequestedAttributesType"> + <xsd:sequence> + <xsd:element minOccurs="0" maxOccurs="unbounded" ref="eidas:RequestedAttribute"/> + </xsd:sequence> + </xsd:complexType> + + <xsd:element name="RequestedAttribute" type="eidas:RequestedAttributeType"/> + <xsd:complexType name="RequestedAttributeType"> + <xsd:sequence> + <xsd:element name="AttributeValue" minOccurs="0" maxOccurs="unbounded" type="xsd:anyType"/> + </xsd:sequence> + <xsd:attribute name="Name" type="xsd:string" use="required"/> + <xsd:attribute name="NameFormat" type="xsd:anyURI" use="required" /> + <xsd:attribute name="isRequired" type="xsd:boolean" use="required"/> + <xsd:attribute name="FriendlyName" type="xsd:string" use="optional"/> + <xsd:anyAttribute namespace="##other" processContents="lax" /> + </xsd:complexType> + +</xsd:schema> diff --git a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/utils/ELGAMandateServiceMetadataProvider.java b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/utils/ELGAMandateServiceMetadataProvider.java index b35ffdf62..adc2a310b 100644 --- a/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/utils/ELGAMandateServiceMetadataProvider.java +++ b/id/server/modules/moa-id-module-elga_mandate_service/src/main/java/at/gv/egovernment/moa/id/auth/modules/elgamandates/utils/ELGAMandateServiceMetadataProvider.java @@ -36,12 +36,11 @@ import org.opensaml.saml2.metadata.provider.MetadataFilter; import org.opensaml.saml2.metadata.provider.MetadataProvider; import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.xml.XMLObject; -import org.springframework.beans.factory.annotation.Autowired; +import org.opensaml.xml.parse.BasicParserPool; import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.auth.IDestroyableObject; import at.gv.egovernment.moa.id.auth.modules.elgamandates.ELGAMandatesAuthConstants; -import at.gv.egovernment.moa.id.commons.api.AuthConfiguration; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.SimpleMOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.MOASPMetadataSignatureFilter; import at.gv.egovernment.moa.id.protocols.pvp2x.verification.metadata.SchemaValidationFilter; @@ -57,8 +56,6 @@ import at.gv.egovernment.moa.util.MiscUtil; @Service("ELGAMandate_MetadataProvider") public class ELGAMandateServiceMetadataProvider extends SimpleMOAMetadataProvider implements IDestroyableObject { - - @Autowired AuthConfiguration authConfig; private ChainingMetadataProvider metadataProvider = new ChainingMetadataProvider(); private Timer timer = null; @@ -256,11 +253,12 @@ public class ELGAMandateServiceMetadataProvider extends SimpleMOAMetadataProvide filter.addFilter(new SchemaValidationFilter(true)); filter.addFilter(new MOASPMetadataSignatureFilter(trustProfileID)); - HTTPMetadataProvider idpMetadataProvider = createNewHTTPMetaDataProvider(metdataURL, + MetadataProvider idpMetadataProvider = createNewMoaMetadataProvider(metdataURL, filter, - ELGAMandatesAuthConstants.MODULE_NAME_FOR_LOGGING, - timer); - + ELGAMandatesAuthConstants.MODULE_NAME_FOR_LOGGING, + timer, + new BasicParserPool()); + if (idpMetadataProvider == null) { Logger.error("Create ELGA Mandate-Service Client FAILED."); throw new MetadataProviderException("Can not initialize ELGA Mandate-Service metadata provider."); diff --git a/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java b/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java index 0eb71ec92..fe859c7bc 100644 --- a/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java +++ b/id/server/modules/moa-id-module-ssoTransfer/src/test/java/at/gv/egiz/tests/Tests.java @@ -22,20 +22,267 @@ */ package at.gv.egiz.tests; -import com.google.gson.JsonObject; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.SecureRandom; +import java.security.Security; +import java.util.Arrays; +import java.util.Base64; +import java.util.List; -import at.gv.egovernment.moa.id.auth.modules.ssotransfer.SSOTransferConstants; +import org.bouncycastle.jce.ECNamedCurveTable; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import org.bouncycastle.math.ec.ECPoint; +import org.bouncycastle.util.BigIntegers; + +import at.gv.egovernment.moa.id.data.Pair; +import at.gv.egovernment.moa.util.Base64Utils; +import iaik.security.random.SeedGenerator; /** * @author tlenz * */ public class Tests { + + //private static SecureRandom random = new SecureRandom(); + private static SecureRandom random; + private static SeedGenerator seedgenerator; + + static { + random = iaik.security.random.SHA256FIPS186Random.getDefault(); + seedgenerator = iaik.security.random.AutoSeedGenerator.getDefault(); + + if (seedgenerator.seedAvailable()) + random.setSeed(seedgenerator.getSeed()); + } + + + /** + * from https://trac.tools.ietf.org/id/draft-goldbe-vrf-00.htm + * Section: 5.4.1.1. ECVRF_hash_to_curve1 + * + * @param pubKey + * @param target + * @throws NoSuchProviderException + * @throws NoSuchAlgorithmException + */ + private static ECPoint ECVRFHashToCurce(ECPoint pubKey, String target) throws NoSuchAlgorithmException, NoSuchProviderException { + + MessageDigest md = MessageDigest.getInstance("SHA-256", BouncyCastleProvider.PROVIDER_NAME); + + + BigInteger ctr = BigInteger.ZERO; + + boolean runLoop = true; + byte[] comprPubKey = pubKey.getEncoded(true); + + while(runLoop) { + + + //byte[] ctrArray = BigEndianConversions.I2OSP(ctr, 4); + byte[] ctrArray = BigIntegers.asUnsignedByteArray(4, ctr); + + //calculate hash from target, pubKey, and ctr + byte[] hash = md.digest(ByteBuffer.wrap(new byte[target.getBytes().length + comprPubKey.length + ctrArray.length]) + .put(target.getBytes()).put(comprPubKey).put(ctrArray).array()); + + //first hash and check (EC Point x coordinate) + byte[] hashECPointCompr = ByteBuffer.wrap(new byte[1 + hash.length]) + .put((byte)0x02).put(hash).array(); + ECPoint hashECPoint = pubKey.getCurve().decodePoint(hashECPointCompr); + + if (hashECPoint.isValid()) { + //find valid EC point --> stop hash loop + return hashECPoint; + + } + + //second hash and check (EC Point y coordinate) + byte[] hashECPointCompr2 = ByteBuffer.wrap(new byte[1 + hash.length]) + .put((byte)0x03).put(hash).array(); + ECPoint hashECPoint2 = pubKey.getCurve().decodePoint(hashECPointCompr2); + if (hashECPoint2.isValid()) { + //find valid EC point --> stop hash loop + return hashECPoint; + + } + + ctr = ctr.add(BigInteger.ONE); + + } + return null; + + } + + + private static BigInteger ECVRFHashPoints(List<ECPoint> points) throws NoSuchAlgorithmException, NoSuchProviderException { + + MessageDigest md = MessageDigest.getInstance("SHA-256", BouncyCastleProvider.PROVIDER_NAME); + + //create a array of encoded EC points + byte[] encPoints = null; + for (int i=0; i<points.size(); i++) { + byte[] encpoint = points.get(i).getEncoded(true); + if (encPoints == null) + encPoints = encpoint; + else + encPoints = ByteBuffer.wrap(new byte[encPoints.length + encpoint.length]).put(encPoints).put(encpoint).array(); + } + + //hash encoded EC points + byte[] hashArray = md.digest(encPoints); + return BigIntegers.fromUnsignedByteArray(hashArray); + + } + + + public static Pair<String, byte[]> generatebPKAndProof(ECNamedCurveParameterSpec ecParamSpec, + BigInteger sourcePin, ECPoint pubKey, String target) throws NoSuchAlgorithmException, NoSuchProviderException { + + //generate bPK + ECPoint bPKECPointHash = ECVRFHashToCurce(pubKey, target); + ECPoint bPKECPoint = bPKECPointHash.multiply(sourcePin); + String bpK = Base64.getEncoder().encodeToString(bPKECPoint.getEncoded(true)); + + //generate proof + BigInteger k = new BigInteger(pubKey.getCurve().getFieldSize(), random); + //c = ECVRF_hash_points(g, h, g^x, h^x, g^k, h^k) + BigInteger c = ECVRFHashPoints(Arrays.asList(ecParamSpec.getG(), + bPKECPointHash, + pubKey, + bPKECPoint, + ecParamSpec.getG().multiply(k), + bPKECPointHash.multiply(k))); + + //s = k - c*sourcePin mod q //error in original document + BigInteger s = (k.subtract(c.multiply(sourcePin))).mod(ecParamSpec.getN()); + + //create arrays with 32 * 8bit array (8*32 = 256bit ==> prime order used of EC curve) + byte[] cArray = BigIntegers.asUnsignedByteArray(pubKey.getCurve().getFieldSize()/8, c); + byte[] sArray = BigIntegers.asUnsignedByteArray(pubKey.getCurve().getFieldSize()/8, s); + + byte[] proof = ByteBuffer.wrap(new byte[cArray.length + sArray.length]).put(cArray).put(sArray).array(); + + return Pair.newInstance(bpK, proof); + + } + + /** + * @param ecParamSpec + * @param pubkeyPoint + * @param first + * @param second + * @param target + * @return + * @throws NoSuchProviderException + * @throws NoSuchAlgorithmException + */ + private static boolean validatebPK(ECNamedCurveParameterSpec ecParamSpec, ECPoint pubKey, String bPK, + byte[] proof, String target) throws NoSuchAlgorithmException, NoSuchProviderException { + + System.out.println("Validate bPK:" + bPK); + + //decode bPK EC point + ECPoint bPKECPoint = pubKey.getCurve().decodePoint(Base64.getDecoder().decode(bPK)); + if (!bPKECPoint.isValid()) { + System.out.println("No valid bPK because its not point on EC curve"); + return false; + + } + + //decode c and s values from proof + byte[] cArray = Arrays.copyOfRange(proof, 0, (pubKey.getCurve().getFieldSize()/8)); + BigInteger c = BigIntegers.fromUnsignedByteArray(cArray); + + byte[] sArray = Arrays.copyOfRange(proof, pubKey.getCurve().getFieldSize()/8, proof.length); + BigInteger s = BigIntegers.fromUnsignedByteArray(sArray); + + ECPoint u = pubKey.multiply(c).add(ecParamSpec.getG().multiply(s)); + ECPoint h = ECVRFHashToCurce(pubKey, target); + ECPoint v = bPKECPoint.multiply(c).add(h.multiply(s)); + + BigInteger cSlash = ECVRFHashPoints(Arrays.asList( + ecParamSpec.getG(), + h, + pubKey, + bPKECPoint, + u, + v)); + + if (c.equals(cSlash)) { + System.out.println("Check successfull!!!!! \n"); + return true; + + } + + System.out.println("FAILED!!! \n" + + "c =" + c.toString(16) + "\n" + + "c'=" + cSlash.toString(16) + "\n"); + return false; + } + /** * @param args */ public static void main(String[] args) { + + + /* + * Test verifyable random functions with RSA + * + */ + try { + Security.addProvider(new BouncyCastleProvider()); + + String baseIDEnc = "gL/IWO/MtC+EQVLp2ie8GA=="; + byte[] baseID = Base64.getDecoder().decode(baseIDEnc); + + //use sourcePin as private key + BigInteger baseIDKeyInt = new BigInteger(Base64Utils.decode(baseIDEnc, false)); + + //calculate EC PublicKey from sourcePin + ECNamedCurveParameterSpec ecParamSpec = ECNamedCurveTable.getParameterSpec("secp256r1"); + ECPoint pubkeyPoint = ecParamSpec.getG().multiply(baseIDKeyInt); + + //generate bPK and proof + Pair<String, byte[]> bPKAndProof = + generatebPKAndProof(ecParamSpec, baseIDKeyInt, pubkeyPoint, "urn:publicid:gv.at:wbpk+FN+468924i"); + + System.out.println("bPK=" + bPKAndProof.getFirst() + "\n" + + "proof=" + Base64.getEncoder().encodeToString(bPKAndProof.getSecond()) + "\n"); + + //verify bPK with proof and publicKey + validatebPK(ecParamSpec, pubkeyPoint, bPKAndProof.getFirst(), + bPKAndProof.getSecond(), "urn:publicid:gv.at:wbpk+FN+468924i"); + + + + //verify bPK with proof and publicKey + validatebPK(ecParamSpec, pubkeyPoint, bPKAndProof.getFirst(), + bPKAndProof.getSecond(), "urn:publicid:gv.at:wbpk+FN+468925i"); + + validatebPK(ecParamSpec, pubkeyPoint.multiply(BigInteger.TEN), bPKAndProof.getFirst(), + bPKAndProof.getSecond(), "urn:publicid:gv.at:wbpk+FN+468924i"); + + validatebPK(ecParamSpec, pubkeyPoint, bPKAndProof.getFirst(), + bPKAndProof.getSecond(), "urn:publicid:gv.at:wbpk+XFN+468924i"); + + System.out.println("Finished..."); + + + } catch (Exception e) { + System.out.println("ERROR: " + e.getMessage()); + e.printStackTrace(); + + } + + // String json = // "{\"data\":{\"session\":{\"validTo\":\"2015-10-09T10:55:34.738Z\",\"entityID\":\"https://demo.egiz.gv.at/demoportal_moaid-2.0\",\"userID\":\"Thomas Georg Lenz\",\"sessionBlob\":\"PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48c2FtbDJwOlJl\\u000ac3BvbnNlIHhtbG5zOnNhbWwycD0idXJuOm9hc2lzOm5hbWVzOnRjOlNBTUw6Mi4w\\u000aOnByb3RvY29sIiBJRD0iXzQ5ZjgzMDIyZjRkZjFjODMyMDNlZGU1NTQxZDY1ODU4\\u000aIiBJc3N1ZUluc3RhbnQ9IjIwMTUtMTAtMDlUMTA6MzU6NTEuMDI0WiIgVmVyc2lv\\u000abj0iMi4wIj48c2FtbDI6SXNzdWVyIHhtbG5zOnNhbWwyPSJ1cm46b2FzaXM6bmFt\\u000aZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIiBGb3JtYXQ9InVybjpvYXNpczpuYW1l\\u000aczp0YzpTQU1MOjIuMDpuYW1laWQtZm9ybWF0OmVudGl0eSI+aHR0cHM6Ly9kZW1v\\u000aLmVnaXouZ3YuYXQvZGVtb3BvcnRhbF9tb2FpZC0yLjA8L3NhbWwyOklzc3Vlcj48\\u000aZHM6U2lnbmF0dXJlIHhtbG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5\\u000aL3htbGRzaWcjIj48ZHM6U2lnbmVkSW5mbz48ZHM6Q2Fub25pY2FsaXphdGlvbk1l\\u000adGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMTAveG1sLWV4\\u000aYy1jMTRuIyIvPjxkczpTaWduYXR1cmVNZXRob2QgQWxnb3JpdGhtPSJodHRwOi8v\\u000ad3d3LnczLm9yZy8yMDAxLzA0L3htbGRzaWctbW9yZSNyc2Etc2hhMjU2Ii8+PGRz\\u000aOlJlZmVyZW5jZSBVUkk9IiNfNDlmODMwMjJmNGRmMWM4MzIwM2VkZTU1NDFkNjU4\\u000aNTgiPjxkczpUcmFuc2Zvcm1zPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRw\\u000aOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjZW52ZWxvcGVkLXNpZ25hdHVy\\u000aZSIvPjxkczpUcmFuc2Zvcm0gQWxnb3JpdGhtPSJodHRwOi8vd3d3LnczLm9yZy8y\\u000aMDAxLzEwL3htbC1leGMtYzE0biMiLz48L2RzOlRyYW5zZm9ybXM+PGRzOkRpZ2Vz\\u000adE1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1s\\u000aZW5jI3NoYTI1NiIvPjxkczpEaWdlc3RWYWx1ZT44eE9qNmlYVzhIQzk5UGhETEZ0\\u000aOVp0M205VWliaVdrdHMzaWVQTS9CZlFZPTwvZHM6RGlnZXN0VmFsdWU+PC9kczpS\\u000aZWZlcmVuY2U+PC9kczpTaWduZWRJbmZvPjxkczpTaWduYXR1cmVWYWx1ZT5mNjM2\\u000aYjVBeGx6THdUL0I1SmdLdnhNN0haK1lEZGVldUdaRUlxc05KdHdiN05TVFhlbVFC\\u000aTExObDlJTk1aUW1Ybkx3ektCc0pra0tGTXl3MkpsNXVYcWlHWVBzMExTWTNiWTdj\\u000aTTZoeHpDaGdVVHRMWXlPcE9qemxxbE5CN2FKTVpZWU10Q2phcWNqSmxVM0wxTjBv\\u000aYUJ5QlRjaTRHdjd5TUJkdE9nRElHNVVpVEppVmVNOURZcUowZFVaZDNRcG1BK0Zm\\u000aUm10WFVzaVRzU0N0b3lWVHlXYTJWemJweTZxcDMwWkZSTU03LzU0Q0NWZHIvaDZW\\u000aTnZCQ1YydkFEMWdZaUg5VG41aTRSRmRWMFBKNTkrNS9HYXVUMm1HSVRUVmNreVk2\\u000aRlJQSjI2MUV0bmdScE8xK1FYRDZwQVZBM2V6Rm9ZbkkyQ2dYdHQ2K2EyTkV3cnBO\\u000aaHc9PTwvZHM6U2lnbmF0dXJlVmFsdWU+PGRzOktleUluZm8+PGRzOlg1MDlEYXRh\\u000aPjxkczpYNTA5Q2VydGlmaWNhdGU+TUlJREZUQ0NBZjBDQkZVQm5MNHdEUVlKS29a\\u000aSWh2Y05BUUVMQlFBd1R6RUxNQWtHQTFVRUJoTUNRVlF4RFRBTEJnTlZCQWNNQkVk\\u000aeQpZWG94RFRBTEJnTlZCQW9NQkVWSFNWb3hJakFnQmdOVkJBTU1HVTFQUVMxSlJD\\u000aQkpSRkFnS0ZSbGMzUXRWbVZ5YzJsdmJpa3dIaGNOCk1UVXdNekV5TVRRd016UXlX\\u000aaGNOTVRjeE1qQTFNVFF3TXpReVdqQlBNUXN3Q1FZRFZRUUdFd0pCVkRFTk1Bc0dB\\u000aMVVFQnd3RVIzSmgKZWpFTk1Bc0dBMVVFQ2d3RVJVZEpXakVpTUNBR0ExVUVBd3da\\u000aVFU5QkxVbEVJRWxFVUNBb1ZHVnpkQzFXWlhKemFXOXVLVENDQVNJdwpEUVlKS29a\\u000aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSUp2MHFlOVVkdkZZU0w1STAy\\u000aR29rd0VWZnNJR2M3STdFaFZOT3hZCjltdFVlbm1ocU5yTHNMQkZnMUlpUGJrMElT\\u000aV2hPUndQeVZwL1AzK0d5R1AzMzlxWjY4VUNHVjM2MUUwUW03Y2pQZS9PMytyM0hB\\u000aTTIKWkJOOG9BWm9IbXBock5TNmZLZlk1OGt5Z3RyVWErWnlNellXVFRpUzMyU0NN\\u000aOEg1NWJsdUVGYmVaa3NuYlAwWTk0SWprZkpkZ3Z6bApNeHpybFN5b1YyeW1XQmp2\\u000aUzV3ZWxESGdiQ0t5anNqSWhUUmpKdS9vbEdKeWVuMDEvRXBJVnRTeURYTy8ySVMy\\u000adjJPOVVpRndBb3lCCllBalBubDNIeEsyQTU3N25SNjNNeGxnUDAvcytyODR1QnFP\\u000aQWxiNHFuYnBVN2x1NUd4bENQa1ptcFJvb0NRWVVSaW9DK3dqUzZsTUMKQXdFQUFU\\u000aQU5CZ2txaGtpRzl3MEJBUXNGQUFPQ0FRRUFCcU83a2txL2dSYWhBdnBzUWc1TExa\\u000aUk9HRnI5cElQcnlOOXhtSkdnUG83agpLTmw3cnM3Z05TMGxtdWx1WVdXbkpjd0FQ\\u000aYndGZWI5NTRWTUI5eDlwOVFFdzVSblhhbVVZOXFhMExnY1MvdC9XWDZ2SmtaUE5o\\u000aV3BoCjhiWHdoME12bHNiZnJ2RFRKcjhjakgzcWZ4SVRwN3BhM3hiMXFFN3N1UmZm\\u000aVlVkRFhhd2lYWG5XSi9XSnIrdHdWVkhIRXFuWnoxbEEKclNETHhNOHNDakc4RGVK\\u000adzh2blF5NW1QR3JHVlRCYmE0dXBjOFVUWTFuUFY5VTJHQkpWWXVBa29WUmpiVGxO\\u000adnJMNUpxTnF5cEtjRwpiZWpqV3hncnpaa2VRZVUyaEZjanVubWd3R1ordWcyZnE0\\u000aa0trUWZ0d2NxZUpUenl6Qm9vMitPbzRUbWZic2gvb254UFdBPT08L2RzOlg1MDlD\\u000aZXJ0aWZpY2F0ZT48L2RzOlg1MDlEYXRhPjwvZHM6S2V5SW5mbz48L2RzOlNpZ25h\\u000adHVyZT48c2FtbDJwOlN0YXR1cz48c2FtbDJwOlN0YXR1c0NvZGUgVmFsdWU9InVy\\u000abjpvYXNpczpuYW1lczp0YzpTQU1MOjIuMDpzdGF0dXM6U3VjY2VzcyIvPjwvc2Ft\\u000abDJwOlN0YXR1cz48c2FtbDI6RW5jcnlwdGVkQXNzZXJ0aW9uIHhtbG5zOnNhbWwy\\u000aPSJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YXNzZXJ0aW9uIj48eGVuYzpF\\u000abmNyeXB0ZWREYXRhIHhtbG5zOnhlbmM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEv\\u000aMDQveG1sZW5jIyIgSWQ9Il8zZmQzNTg5MmU5YThlYWNiOGUwOGYyODBhODNmY2I3\\u000aNCIgVHlwZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjRWxlbWVu\\u000adCI+PHhlbmM6RW5jcnlwdGlvbk1ldGhvZCBBbGdvcml0aG09Imh0dHA6Ly93d3cu\\u000adzMub3JnLzIwMDEvMDQveG1sZW5jI2FlczEyOC1jYmMiIHhtbG5zOnhlbmM9Imh0\\u000adHA6Ly93d3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyIvPjxkczpLZXlJbmZvIHht\\u000abG5zOmRzPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6\\u000aUmV0cmlldmFsTWV0aG9kIFR5cGU9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvMDQv\\u000aeG1sZW5jI0VuY3J5cHRlZEtleSIgVVJJPSIjX2E3NDBjZjA5MTViZDE1MmRiNzRk\\u000aMDNjZDQ1NzUyMTM3Ii8+PC9kczpLZXlJbmZvPjx4ZW5jOkNpcGhlckRhdGEgeG1s\\u000abnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMjIj48eGVu\\u000aYzpDaXBoZXJWYWx1ZT43R0hKY0NYYXlzME1pY2ZvYXc3cnFNeTZ1bUQyd0FEQmtH\\u000aOThKclJ2UUdMczJneTBOSWFvSlM2SWM1Z254RXBNcUZHZ2ZLNHBBWGxRUVh3K1h6\\u000aY0RNaURhY2tqS1c5ckptNTh0b3dxNmFEbWVIU2doTTRDVzhVb1RaQlFlazVvY1dU\\u000aNmRIT3hPVzFFOFUrTXprTEg1NjVXUWxLYkdHamVSSGNzb3V3MXFuNk1XS01EU0V4\\u000aRzQrZERzSVliMk1uaEc3OEh6TDNZK0VMVG40TWd1cXF4bmpTVC9rRkpTK2dSMm93\\u000aL2tHVHN2ZnlLWmdMZUVYTzRpVHlNM2RzRk1Ma05rM0tHSHVHRmhGeUxycUR3Sko2\\u000aTmY5OVZRTmlDZDlrUnpxOE1qWklpNWQ0SjlhSmgvRk93NFI0TXAveCsvaC9hYVhk\\u000acDVyQ09CcUVaZ3FZUXlqT2FIMlAxRHR0VkU5SU5xS2w1OXh5ZTJaR0tDd1p5TTgr\\u000adWdSRnVDbTJ2RFlRSUx1T1RTaVNpbkJsNnBpLzFYRktNL1lVbTRJMXA0N21LNDlE\\u000aeW9Ia0lBaUk0NjQ2ejNJZ0tMZTBnaFlQYUlvTHhNcDE1ZE83RHRDQzhsZnYwb3Qx\\u000aYVdvTy9TcGpXaVJiOEhCaXdleGxTdHV4dVorUGVqZDlzUS9neTNFOFp1MWJXRmsv\\u000aTDVrNTZqUTAxZStIcEdORW5FSml1c1RHWldMRTZBY1lvd1NCeEZidC9RUHhGTlhh\\u000aRFBmcmlGRGZMK1RuMngyc2Rwb1RlMVpZM1JnZXo5b1Y2QUtJQWZZWC8zMllsT0NK\\u000aTlV5Myt4OU5teHljOFdKNTBjQ2RTd3ZuNTRBc1Z2U0xYRi9sbHIwQmh2cWRWQ0dP\\u000aTy82WGQvdEtpblFPWHdmeEJBMDVJZSs5MFZhU1J2NGFrRXJ4dHhrekVIeXB3R01j\\u000aVStieTYybDh5Q2Qya01vMnpQK0hmZ3NkTU9Ba2hrbDUvRXB2NVdiZGMzeElKRUhK\\u000aOVptbitUdGNWR2FiOHNPeSsyblIwQWNwZDJxeVIvNkNUd3dodk5nbXF1TldiLy9P\\u000aaGNxdDMvR1dPZkt0NGhrRnQxeGE2allTSXVoNHVWMHJqcENvK21ISFk4ZFZaTGZ6\\u000aNE9oR3dpNGd4bDBlV3hYUWF3UGpMWlI5RzdpQ1NCT2ZPV0d5bkdydklKSFF2VUJD\\u000aUVUwLzh3eFNxRmkxcVdQVXN2ZWtxV012SFpYTGdMMGZNYUJEa1ZZTm5YT2FlalJU\\u000aVHNZeENZc1AxYlRCNDY5ZytjRkQ1bEd0VDErTi95S3dKOUJTTGhaenhzRVhVWkhG\\u000aQ1NJTk1vTTlnaVF4TzI2L0VLUENMdXp2bnkyN3orNWdxcURkVzhlVUFCUmEyeFpp\\u000aZ204YmFkSllGWE12dkdDUVBjcmhiN3c1c3dSL2I1TXNiZXV4L3F0RFQ4R3VWcUNG\\u000ac3JDL3E4MlZpOUd5b3VCWDdGRk50UWhWRDFFVWtCQWZTYWE2UDhKU2VPdE01TVYr\\u000aV21OcGJrQ0U2M2hZS2g4cHN5MUdMdlRZRVA3Slh3TmNIWXlmS3FtdXk5S1dOVmUv\\u000aT2JPZTM5azhCWE5tWE9DejRJay93ajZqaU1DWEsrblhwdTBZQ1Z2ODJXM1BMeGlR\\u000ab1liRURMMjNHV05sNFFHQzQ1dE45WUpwK29CSGZjRStmUHk4S1FrOFBDK0s4SFFr\\u000aK21HV3NkTVUxUitTaTExY0VYdzBKTTRTczJzTWpZb05tQXd6a2RvRHliVkdnK3B3\\u000aSnUrUmFmaEJrSmpIU0FMeVQ3Y1R3dncrOW56S1BIdUhvWW5wSTRLQSt6U2xrYkUr\\u000aQ0dSbzd1MUxXVFl0cGZTYnFtd1NjYVlxU01WaTZ5QVdkRnoyS001LzlkVHB6alBY\\u000aNGhOZW82ZE96eVRHUkFMVnVUZi9Ma0RqaElqWGJ0Z2J6ZnU0aWdrWXg3Q2d1RnZ0\\u000abVlkTEhNSE4yRnFOTkN1UWk2bTJLUGYyUG5HdmVrSFVwMEJYZ3NEOUhkZFJtNHBF\\u000aYnE1VEsvV05RTzBuS0g0M1owOU9NcWZZbHEybk5mTi84ZnMyTjc1c2h5NmtheElK\\u000aL0FZUlNkOUU5M1VjOWJmV2FIeUwraWNNTE1GelU5MytMZlhpREkyWDVScEVtSnFB\\u000aSUMwVlJ0NWtXdnlVNGVlWnhOdE8zWUtxUnN2YVo0dzhnZ0I3dkxheFFKUWtnMWhs\\u000acVAzQzhDQW5HWnkrdDR5alRVejA1LzlpQi9HRk1DdDNteEpPajUvaVdTOTZRRW54\\u000aVm8wdVYvYzhDRFd6OERHYzYvLzFBQzBWS0VmaGRsSmFGOHg1NzVHNTI2dHoxTVln\\u000aMHBaaitNRzlsRUxkNm12d011cVE3VEVZdEYyN0Y4Vk5iQ29ZWXUraDhJTCs1Y0Vr\\u000acnBjakUzMm9MbWx4ZjBjNnpZaDhwa3FsVTR2RHlQeGJJcm50WkFPcThMUzk5Vktr\\u000aUjdFL0w5OXNoZUxqd3I0bTJtQ21CZ2tGZVZhVG1Ca00vSFd4MUNEYjlIcVM0N25Z\\u000aSWJaQW94ampIK0QzR1EweXlES1R3aG1iSXNHMFQ4Ry96eStRR0pmNkg2MXg0M1ZJ\\u000abkNwRkxmQjNiQUNJay9OanhCeFdheGVwMXRMMTRBSlRMZlROTnA3K3dCT016THhm\\u000aSHBjSUlWT2dOeXJ6UVk2Q0x6eXlDM2hub212a0hadFJ2WmpBYmExMmJSZ3VoTUJX\\u000aOFZiaHNKMmZaekZ3TXp0amxzSEkwREc2OGs1R0JDemFDQVRPZlBBWnFPN2lEQ2JC\\u000aMW1KSEgzTmxvQ2xuL1pTY01rOUVqTERyTndIWHZ4ZEFTRFMwS1RrZVNxS21TZm54\\u000aUWlSQ3lLNjhrSEZNc0trUTRYS3JKZjZGMWRreVYrL3NFdzRsS1FFYW52VkVVSTJx\\u000aUExDSVZnVWVkQVFaeFAxeVp0dDA1V2ptSUdhZnhQMldWNE9PYm8vTGFaamo0YW9H\\u000aNjNxWkdGdGJyWUt4TVc1Ny9RL0ZkbjN5TUpmUlkxVGU0UCtpTTNHUjNRcU1QeVMr\\u000aZWZDMlRDNk9pYithOHZ2SVcxTFI4OGV0V2t4SHJzMEpVcVRpM1ZEY1lXNEcwUHVn\\u000aTFhsZEYwWVVod1RLaTlOUjZmWTNXMXBTQUlNRGYvbk5hcVBIUnNLVWU4Z3pwcll3\\u000aOUdWLytXWjkrNUxEQnYzWmNKVGlLcllOcG1TUHl2MDdvNWx2Mmo2MXJtaEdsQVJ6\\u000aODJzWlhDUzA5K0lyaUpmVUg4bko0NFRFUk8wb1pBd2RxZWhEVmQ2YzZIV044dlJI\\u000aeEVJZWhmeXJhUVZ5Q3FlQkU3d3VPcXZFSmI2R0Urc1czNlBMNGFwT2ZMcCtISU5V\\u000aMkRhbVBrWHJWdVV6Q1dWZWlXaGIzSVBPNk81WkNENVp5RHlQc0liV3RuMnc2bnpI\\u000aU3EyUDhOdmZZRHhTcmM2YlU1aThoQ0FOZFdudTliMWJia0tXTXhUazhjamQ2bk8w\\u000aN1FtZnJFZGJCQ1ptWmh6blJ2cmRYMDdHSXo0YXhtM0Z2UHBtazBvZ1FaUzBieDd1\\u000aSWhFTDhGR2ozQW9lSllpOFB0dFA3NmFKaTRPYndlUmhlWVE2L1p0NHlPcXhabUph\\u000aMEFnTjJieTlpT1kyZ2tLclg2RTY1UWMzM2Q0Wlh6aXdDc1BsNVlGQmY1bG9ndGFE\\u000acXFVU0p1TEQyUEMyZEZNeDAzaGkrcUpSNmxPZ3ozYjJrM3dUTjhGTjJBMnQycHo2\\u000aNjJSS3IyQVRuSklrZkdndHVTcFlicGdab05VL0pheS9qMERWMXRaMkFmODdsUU43\\u000ablphdmF0YjVvbWx1Vi8yU3ZVYk5rbW1HdUhrTmFjQnNuTjIza3FOTEFrMmZvQ0xZ\\u000aT1FZaG5uQm1ZTUdYdS9tOG9haXdmUzhxRlZyYllTc0tKSWpLU1ptaFZBU3hXa01t\\u000aT3lSVUcrYkhlQ3RuT3ljWmlhb25XZElvbFUzT2hJMi9JTkpDSUNzQjJNWGhtNkpa\\u000aOEFtcUlqSGQxR1JvVElRTDlFNlBUbGF1MVB5dDhmbnl0aERac2R5L1dmMGU2SGRy\\u000abXJleXBiaE5PYTh4NUF4ckhaRGxjemttaUJyOHEzU0dYU1JVWUt0YndGUk5DZjFX\\u000aYkVyci9uN3duVmlZOENiS0wxZGJzMzlDNmtaVGlUVE16b1NCaFVKcW0xeUpHZUM3\\u000aT2pLRC9VNUFUK2NmOXV3c2hVNDhKZHNUNDVOWjJnOFNkL21xODlyTFBRVTAxNG9h\\u000aNUhRbzV4bEkvaldPUE1MM0R3MmtFVkkyZ3R0eG5HamExVk9aZVlJSGM1amJWenBx\\u000aSDMxZ2ZNYkZLTTNqNHRyaFVKVmFyM29ZWndZWnR6c1IyNmg5NWxIVlNNQzJ2MGZH\\u000aZ29nRFBMYzROejFtelNUNzQ2OFFTeVJJTzZtOTVTOTV3UWxiWXFoRzhMLzJsZW13\\u000aS1JNMUNUSGVUeVFjQlRNb1lrdU9wNFRZaVlXZzAwMjlXelNyMkhCUlFXZm9zNzc0\\u000abWlBbjBEQWtxcysybzFOdUtjTmU3cVFmY1Vnd2lHNzZJK1FZcEZPbkJSeUh1d1px\\u000acHR1WmpKTWV5amtZWC9wRE5VRkxYMmNWRGgrT0FSRUFaT3NBSVlPbnU1OWZnRHVB\\u000aM2RrOVNHMGVIclNXVkR2dU5yTDJiWm1hUXJxQmZ4bXRaall2Q0lmdDFXcmQvUkFo\\u000aeUs4bEFMNWFJZ1pZajV4WjBtV2hXd2hHTFBKNXBnMXpCeHFmZ2hyNzhRSVBQNGEr\\u000aT3YwU21qTmdwbVNQQzc4d2RPNVh6N3NzeU1mUC9uWkhVZEVJbUNqUGVMM2lJalhn\\u000aVVY1SjRnckc1cWY3WHZJQzBpNGZBdktnZ01LYXFYWGRZclBCZzFWQm5vR3BNVWZm\\u000aUU9Wa29pcjNjL2hYNWxlN1BoQlp3OVlWaEN3UDg2VU1oeGFmclp6blQzbnVUV0lL\\u000aRUMxOWVXNDJSak0wU3V2dWlreFY0L1o1UUhxcUtvNmRPamJZL1NKR1FQU1VWczdx\\u000aU3owNks1bTF4Q3Mybk51QWR2V0lVS25leE1oRUxsRTVGbGJQVkZ0Nkc3d0dLNUxv\\u000aNkV0bVZPWnE3bXpxWS84RHdUMnpUbm1UbW1lZEdIZDlUUWRCM1gxU2orUHlFRDFr\\u000aT01kYUkvVlVOWCt4bFlmUkd4RHF1Rlp2YmdTVSsxaDJHSjQ5M3VsYk9KVmJjeXpP\\u000acFFmTks5UTNNNEp2V1hPRVUzT2NPVkMwbkZGUUVEbDFEZ2h2Wldoeit6dy9sZkg1\\u000ab3UvV0kvOUpmKzB6ajJNNDE2YytTbkpneCtaSVZUd0lTQlhDc1NicW5tbG54ZE9a\\u000aSnhrbElrWXlwMGVNZ0RkTzZscHdTbXlLc21KMFVaM3ZPUFRuQXBxdTROeUxLOXUw\\u000aNzFZRVB5WUhWWnRXOUdITm5LM3RvZm5TVVZpMSsrVEx5bDY4aWRqS0RCa2hFVWNy\\u000aeWU5QkFhak1VR3VSc00zQ0RNZGlrSEd6eDVwM2RoeGIwczJTcGhxREhFLzJMSlBj\\u000aU2kyQkFVWTA1WXNDUytiWDgzb3VESDRXSmozZDM0NFFTcnFwQnk0ek11UHJPdWdT\\u000aRWo1a1Z1MjhMT1RKcnZPL09jbmxoTUYvWndielBRVVI5TmhUV21GOFV4WEE0Vjd0\\u000aK2RQNDVnTFFvYnNnVHY4MXkrUDVuTnZ2alNtL2I3aVpzZXJhV0VaSHlwNGo0bis0\\u000aSWJJTmZrcXVYVG9pcTlyVHFvZFdyemN4TkJCdDBOMTFtRWpwM2ZvYjJiVFU5QkVn\\u000aalZlTHRFSGxqVFJJV1ovK1IvTHpTaXRJL241MlNvTUI4RlVZc2lXQzF3WVBOY2lR\\u000aeEJYdFRNZ2xLY3NiVkUyN0dxSEtueDVkMlVHSE9iQVVIOGpKdmVaZUNRYVExWEZu\\u000aZ1ROdXVNcVBzdERaSFNPQ1pWVXhJajkyQTFUNkVTaFo3cTY1VjhadFEwNmdYb3dB\\u000ab1ZDc2xjaUJEZHZwUEZCL2FlV3hjbHc3cFZBQ2xBQ0ltVmhMRG5YNEtGWUNIUE5n\\u000ac2FLYU9ua05SVVZSc0Vad1pad2x2bklRdXpBRW9KTmtremd3Z2dtdHgyL09EK0NY\\u000aaVlLdE5pT3hHWDlKZEUveVovUk9qbHlSNUo5Q09CL3JNMmdlY0FWZ2dmcXQ4RUc5\\u000aQUJNVHZhN3RpVHF0M2Q4V2NjREV5S1F0aTlySXhoNWZVWGkwbTFrNlJGblNEajZN\\u000aRXZBNjBULzRJY1hPUERtYTJ2WU9EZ0NBS21IMWtnNzY1dDI4MFNtcFNnMFlnQUpV\\u000adkphSXlsdGY4VWhPWE9DdE1RaXdEVlVjSCtDTHBiSXh4a25Pa2Q5K1hYNDU3bm1j\\u000adjc5S0FMbzRjbEp0RWpqS3h1aUIrK1ZwNGxzRVlENkI2RVkzMjJiNmk4ZExkQkJu\\u000aZ0JKdXUwMDFBSjlWUFlIWlJBeDNRNDh4UU11dUp3WWdZNmlEV3hzY3lheDdENkxu\\u000aS2czbnBaYmhmVzRlc1l2NjBqdkhTNDZwem1lSlVKVmNmVUFFeWQ4azFXK3huWHFi\\u000aN1dxRFRGNXhaTHgrZHRlQk90UmR5U1NIR2cvcUhQNEFvZ3VSc2JvVFU5OEJqOWIy\\u000aSysvSEU0ZTIveDk2bkg3VzRlU0tGRGsxaWxoNk9EckE5SE1uQ3h1QWFxZXB5VTFo\\u000aRGNsZjNEVXdGamdRR3Vnb29TNHpITElvbnpxVFVjcTRzcC9SZ0YzRk00TGxpL2NC\\u000aTDdSbTYxMHZBYUprcmZWRG1JZGZ0NHd0SVVTVysyRGtoQ2lyb21LL3RLckZUbC96\\u000aTk5HMGpBTmo3SjllRWhQaE9kdzFVMHRlN3ZlakVwMGRLb09NRkRTSTNaWWJieWNs\\u000aUHJ3bkw2ZW5ocmlrWHBzNXVMVDRqT2p2NFVJSVRQSjJLN2NjWUZmQzJqZlJKMDJt\\u000aRk1wRkc0MGplcEdHblJ3cTNRZzQ5NEVhVGN2dG13SVdjbEtlVmJ5MW04N3ppc3hV\\u000aT1JWQXlnUlljU3ZvVXdxdWMzakx3MGJYVzBmUkFYVTMyaFlWUWZJUTFwY01pSDRW\\u000aRStyL3AvRGpJWS9zYngzVm1Hc1dCTGhNOFIweElVWm5YSnJyejk3S09GQkE3NGdu\\u000abVluSXJQa3lmT2hQUGVFSDQyL2VpRHUybWRWL2U0UGEzS1VLZFhjeUo4cm85MjZC\\u000aSTF3aGk4Q2h4SVVtZzZNaDQrOHg4YjhjS3VpZWtFaWZ2cU52aG1KQ3hlaThTYSty\\u000aUVpQMEx2aHAvekEwRWIxY1d0ek1VTUlFdUhJcDREa1hhY1dNZ2NuV3U0L2d4Q3Vi\\u000aMXhHaE5xWDI5U2p4SUhHeFdJRkNvQU9lVkNkL2xiSlFPS3V4R3BnMmR2RjdDUUhM\\u000adGYxQVRQaEQxRVNsNnR5dTg0dndWcTk3U3lTcktweWJxenZydHdSTFhwb0kyUHA5\\u000aWEd6S3BtaXIrT1Fva1dwSUhZTElzU0hmditDWjJDaW5aaUpEWWdtL3ZyOUZWdFpv\\u000aU0JKN2puYlA2TkpKYTlidGd0QzBFZnRTcGxPSHpicm1nMVR4M3gvNytTRlRGc1Yz\\u000ac29yejcwTWxIZE43M1ZjK3B2a080LzM4ZVF6SEFqdkhlTVgybGFMT1Ntb2Z5Nmpw\\u000aOVBWV1RMWFJmSi9kOTRNbmhaK1lvQ04vSVl2cWsyTzlPcDlzWnY3SGNHdHBMYlFr\\u000aUkh3WG9od1VpSFRxVkhEQVVxbEszUkdHdDk3ZHZJY1owSUdlRFJROGtULytCUTZ4\\u000aVGpxN3pvQmpMaGwxT2M1cUxkYldUM2FLbVNoL09Tb1BPWlR1OG5QYXROdjFIektB\\u000aOUE1UGovaDlRTCtGeldrMXM1MzZYRzJHaXRwckdiMERQaUF6MzVaU3dCdVpGbFBs\\u000acmpZbVhONWdsOEpwSVh5c3R0SFdqNTVDSWlJbHYrSnhGOXBGaSs3M0pHNkNUVkNa\\u000acVEzM2p0SmVWLzVsTnFJcGhUUUQzcS9rbDlGNTNPMGRQa0UwM01lWDJkS3p2VkV3\\u000aYldDbnNQMm5rVEhDMDloVDdkSjhVU3NMaElCZnZ4dFJ3VG1nbnRoSE5seVZrR1pK\\u000aWmxVa21QMXFHZU9tdmU4RjgzYlpSMTBNK1dyZmV1ZEJYbVJZUHgzRW5FVHkvK3B4\\u000ad1d1cVczd21WV2JxM3BsRnJCNFd3eUZuc2NNUkNuSjNuQlJQK3ZCYXprb0hpVXk0\\u000aOEJPVkJvMm0zWFRUVmRVcWRmbksvUlpXc0RhaEZKYnpWQ3cvSTlJM0lySkFRa1N2\\u000aSG1qUkRsMW5aeDdCaHU2WTR2ODZKa2dmSk5UMzRocHlYQkRaUW1YNEh0NXZacnlj\\u000aVTE0cTJ4SWVoUGNVRmMyZmQxMmNkWERvazVrSi94ZWF4Zi9RbDMxRUFzQ0xDR0x6\\u000aWFI1b24zL1VaMGtGNEx2Y3IvTVJ0VjhJWWdjbDUxcHlMbjhnbnh0ZmErVmZpMStD\\u000aQ1kySXFJUkpTeGtmWGgvTlhWam5MeFZaem42d1pGWFZ4UXBBUE03TjR5V1pkT242\\u000aMFlXK3ZCTmRGVExKZkxnTVA2UDBZWFZNRlpUVFRtVE04eWRGd2tFZDF2OUUrcysx\\u000abDRzNU50Z01yaEZVTkwxOVo0VVdSNVE5YTQwSXhhK3hBbVdPTElDQjFuUmxkZHll\\u000aeDdmVmtYSDE2WUV3RnZDVlpTWGRZODdaK3JENmZCbEtKL2lvandRbnZPV1hPS1dj\\u000aTmdEemc2bFoyYnVtREJpM1FlSllkNnU1Vk1ybGIxYk81dGZMa0xvM25ZMXROL2ZO\\u000aWmF2NDY1MnM3K3dRaFh4eVZ5bzMzQmY5d0VxaGxwN2pmcnRmY011MS9zcEhwQ1ls\\u000aOWF0MFdVbTR4UytaN3gybkgxUWtJanh4U3RaUVNmQ21LbzdiN0pGUFloVGg4QktR\\u000aQ2U2VnYzemYrUlloMkVNR0d5RXFMdWIvdG1Od2FnRGdGYXk3L3NEaTNTNnUzSmpy\\u000aQlE2b2R2ZkNrU240cytaYUdqb1I2VkNtUHF3VlorTXZQRXBKQURRUm5HS1ludlhs\\u000aUVU4dUo2MWpZNXpUUE0rUExaYytCNmdpdzZlZmNIenp6ejJJUmRPWEJGNFE0RVFO\\u000aek55ZVFrYTNoUUk5TWtFbnc0SDlZV2ljTkV4NVpKazR2NmJzeVl6T0Y3dVdiMi84\\u000ab09NNnRhWHdOWWFTSWRyQ1JxVGl3MFZOR3hVOFgvNGNwU05lSmNsRGRxVXg4TEli\\u000aazdxaCtXYkkwSnNLdHE4d3c0VDlvN3Q5MExpSTl6RWdjUisrbGVvajhxV2Z1aDZp\\u000aL0tzRGtTNFBHMmw1VFBqUWhWMHJaY1FhdW1hRzU3dXc1eUl0RnM4QVVlbTF6VWxN\\u000adjcydDhSalNnTWdBOWdWdGNCcUNlWjIwZzk4ZThWc1FwQ1Y2SDlpSWRIalZTZkFK\\u000aMG5MbnJud1BucWJPZFdvL2xJYXR4dnFSb2hwWFhyR2loSjBPMEpNNkw4Y0JJQlFl\\u000adkZxSE9qVlRIVGFpSVhxL2dQcThVUzZtcTNIS0U0S2tUR09zMXdzV0ZFRmpKei9m\\u000aeUxmYk5sVklIQ0tRTjhjb1lKdFNlSEZUMTNZdm8reTNBa1VRb2hWTno4RXg1TUJ4\\u000aMkYyeGtoZ1BLdDl2aUlLWXdGRlpOQVU5ZzZDWVRjOVY3WmtHTFRBT1JqQ0IwNTVm\\u000aTnBkSGVvRWpydElMU1lTMjZhV3Q1TmtnVVJsV2dEalpTN0t1UWZuY1dXMjQrOVND\\u000ab0xCV1VzSXhVTWVsZTEwZDhwbGxsZ01YRUR6aWEyc0NEemxvOFdOa2h2M3hZZjFT\\u000aYXBjMk8wTnVmS1p2NEVWMXhzMy8wblIrMHc1b3ZHa1UyY0ZXMnpBVUcwaGU2azhZ\\u000aTjR6QVJRallUem4wajNVa3F3Vkl5dGZuUlRYUzZEODZkTVAxaG9ETWY3N0duMzI1\\u000aRUpKM1lGanpFbEFjaURlRkgvMS93Wm4ybm1ST3hDU0p5SUxXNnJiTUdyV1JDSjc0\\u000acFNyNkZUcXRsVFdNWkExL01ZeEk4a0JlWThHaEQwWGZ4bWdPaTI5NjcxSHI4SFVL\\u000admNLYk8zWUxHemhqaEtCWklEWkNwanlUY3p6VkN0MzVOcXpGUnMzM1Z6Y0VDU0I0\\u000aWmVZSCtxS1RDZEhPK0J6VE9HOVh1am5HazJVb3BkdldldkovdVh0SDlmTGhUQjJn\\u000abUQ4azZSa3FSTnUzUjZlN1NJTlhpejFuc3pqMmo3QTlDNXE1c1VkNThjVTdNRlg3\\u000aMGkzVHJ0NUh0MloyaFNQY1hPNTU3Sk1LRVdVcFZxS1l0WmhQTWN1a2hHb0hVekJJ\\u000aTUV1bDlSYXo5c3M2RndsZHo1QmFvWDZJcW5yd2pGaXRnTjVnWUZpaHJEbmlXUVhx\\u000aaXQyTWtETmFROTIvWUlHRlJGMm5iaUdPWDFUamxqQ0VDMU1DQUwvSWxqRU4vM0ZZ\\u000aOEJLWElpdkU0RTNNRGt0eXJzWC8zOGxUZjN0YXZOVk5aVnFESHMxUmxuRUM4WEZI\\u000aUVFNZXdXWjF1RlZVM3pGOVVlcXYzcTRxZUVQREZ5R2lFN2dEV2tNbW5xYnZURiti\\u000aVysyMVJzTHBpbUphS3dqclRMTWtoaCt4Z3hvK0paWml4c1NxNXgrK0NCdEtOQ3BC\\u000aNkUwTnc1SUlnUnVzL1kwMmxQMWZ5OFVsdjU4eHBNUjVETWRmeHZ1cjlPd05BTTY4\\u000aNi9zeUwrbHVwVDZhNnRhOC82YlNPVWphNGRtMXgxWHBhWkZ1Qy9EMGxkU3ZPdTZv\\u000aQmhVVUtuYXhCalpIeXl1UkNQVlpwY0tFZDFkemE4THdJcjY0Q09CeDl5OVJSZTlV\\u000abmN0L1dIanlQSnZsWWx5OTBLZ3JFOWYzMUdkeEFoK2hHVjZrbWhIUUhpRnB2ckRi\\u000ad05tRWdhNzZlTHRLdHpGNDh2cDdZYWdOaERjZlBCbzVJMW5pOGxZcFFDeW50WVB1\\u000aWnRIZWNyNWFDQS9RSWpGZGdUSkRXaGJkVW5rbzgwa1RGRTZ1czByVUNuLzNrcUhK\\u000aeC9Lc2R3S0VxQ2ZzNUVhWW5LbVhvQW5HZWZYYVdoNkU4Mm96Tk5qVzhBSUpJcENJ\\u000aTTZrbkFjWi9mVGVjL255azZmTisyeXltaWFXWkN1ai9lS0piMWZFK1MybWxpbjEw\\u000aM05oWmtNTkJHUDNqTUF2K0l6dGVuMFFDazdySmJ6cmlTeUFGYml2aFB4bjZqQnlx\\u000aaTJKRU4xd29KOU9MYWwvaURBSXNoRXUwQ0dwQ1JMRnUralI5WE9zdktjNTdGVVo0\\u000aSHo2Z0ZBYjEvNkszWnNWSXRGZElvL2tmbHJ3Ukttc0hTN2VuZ1phOVdYSVFHb3FR\\u000ablVaYXVjb1JRVWEwa0haN0UwK0szNVpZa1lZVFRwUHJuQWhQbTJBaXdmRUpzVmQy\\u000aM0tnWUx6QW9tQ0J4Wm41RkFFd3lMVUZSTFAzOGRZR0hlZnhyR1FiemNzOUtpS3I2\\u000aQUFVRTVSM09yMHdDTUpLV1Jmbk9QZjZQdmtIdlcrSFZhZStBeEV6ZXF4TzFwOVVU\\u000ab1hoVlcra3NoRzZ3QTIvL2NkR3Y0MHJrVEh1RFE1c0Y3Q0ZGckNodlJZb0MwMzJJ\\u000aS01qa1Rzc2FKS3dqSEZlSVMzc0tjbmdEL05WR3pTK2xOcGNwSDg2RkJGQTd5SzNq\\u000aVzBrZHRmblRaLzlSSkNXblV0YXFpM3BFaWFlak0rbEs2cXRuVzdVcHhVV2o2K21x\\u000aZzNtb1FCUjZ2Yk4vS0xrSkpsUjhsUWNnQzVLamJLOUd4YXpGZlErbGprcGhKRHBi\\u000adERUZThEZ3dBSmlraGlZT1YzYjU4aTA5MXo1V0JZSmFtQmxodS80MzF2TWIwNFJw\\u000aVVdOSlphSEdySWdCNXNwdFV2SVNxSDRBYm9xN0ZNMVZjZS9pOXpMcXlGVVhXZEhl\\u000aaDBmTWFKUVp1S3NPNDFmQUtsNHhLWE9icUF6eXo5ampGTnJjZDQ4MlNZVzhrVGlW\\u000aZklEUHN3eFc2aEVhd1psaUxRYUtIa1pSU1JYempUVE4wc1draXhmU0dPTDRYNXNy\\u000adXVuajQxNDJyRW80L0NYRzhwODRWTnBrVmRXYk1USEIwT3JmcDdvQWdiLzFRUlZt\\u000aUmpyaUhMZ0Jzb25sWUJvQmNKaVpjb1ljNFJoVmROSnVGdldUaUg5MWM5dXZkdUsz\\u000aeHhoMDNlUCtTRld3Wm44NDZjZ2lGL1pDZTY0d0tVemNPT0JvbkoyVm1JZlFWYUdq\\u000aTmUyY1ZDZVNhM0IwUi9PZXBBRk1ZQmozTTM4djdabFJRUXJMVnRzVXZXMEtjbnRJ\\u000aaHZWa2NYVkpZM3RRYkFKWm44aVUzWnhiN2VvUnF0MjFGem9raVVWbzV6d0FuNDV6\\u000aZVVWUUEwaFhaN0s2K2RmUnJCSGFaMkRob0RLc3FaYkFjVDhTTExxY3dJTlBsdHha\\u000aWkUrUUdMSGc2SXhHdWZmT1VEaEtmdUtoVUlOQ0dwSisycjJqSEZrZGJRaTl1R0Ux\\u000acWh5WmtrcGhEcDRnZ2Z4RjB6QkNQZWJDOHBXRDAxaEdSUFdDVkNzRjBMdGlQV1Mv\\u000aSnU2Q09MWXZKeWhlWURYeWNFLy8wOUkxYTdYRGFaLzBLSWlhNjY5YWNZQ3pGWnEv\\u000aYkxkZjZoWWg1UHp6RlZYNjI4eUJuRnRvbm9MMGlSdlo3eEkvbXQ1alBFc05CYXgx\\u000abGhhdXZJVXlNVEdvM0xGcHZrYStiN2dYZmFPZXgyajZwb0FDdVVZKzJtZmY5Und2\\u000aWitVQThheFB1N3NydUdCaEpJZ2JyeUx0QlNwL09ZZlIzZ0ZSdjA0a3l2bVdkL2w5\\u000aTGxRanVwQ2JvUm81RjFVb09Lb28vQ2l2dWp4WmVDd09QSmdEYndNVWZ1ZUZLazcr\\u000acjFCcktGdWNzbVlhc1dYYUNua0I2TUxOVDdoeHFqYk1hM3JXcVVFa1JyNXJzWWZq\\u000aSFo3SloxdGZacHVyK1Y4M2c5V01rSkFFclhaQnRibFJMM0UxamNicmdBRXQ5MzZP\\u000aR2U3MndPTUg4akNMU2FSSzVUSHlWZmdiUDluYlcxeWdsNHdIQ0tmQlh6RVZ3bWpa\\u000aSmdKWWxtbHp0SnBNcTZJNWJBc2Y2aWlKNFJyQUJmV1VKbkdGNEhuL1RoYTBVZi9p\\u000aMEQrSi9ZUE1RNWIrTmRvajNuSU15UFk3blJ5WWNNVEpaa1lFSWJ1dzd2MXhxUGJz\\u000aTmlSZkczMmJ3dll3QlBVNTduN2lLZXJFTmpnQll6RFVSZWtmVWVxYWZtUHBPWFU2\\u000aZDBBRDJTcjM4M1BnekhsdW0wWmhEUUlnaThycmkyNVU1eDEvdmEyK1YwZWlCdnhH\\u000aTE40b0dZQjZ4a2ZFa3NNTkV4ZlpYU1dCdzlzVnBMeEVxclVqV1NGdk4xbjV5c2Nk\\u000aTi9JY3EzTDhvWDZ6WmR6bFFqWFN4amZ0L0hMR3FrSTVZTTM2K0V0MStXUFFLcG5t\\u000acEpVVnFWemJ1ei9VK0dpcUhSVGVqRDY2a01lUUJnWHB1djFRY3FBU21Tcmtyd21E\\u000aRmVCbXA0amxHV1NCM0R6djBHb2tvK1VrRWxENmRhSGtjQkJCeTlPWEdCTXhKemt5\\u000admNhQkpOY1E5KzN0SjNnVUI2c2QzR3l6ZGNienhMcWFPcFh0bkkyRVZjYXlLekRL\\u000aZ0E5RGRUNHpva3hTTzhObVFOTVMrdFprQ0hJK2ErQW5iSFRvNlJQZ3JpRVg0TG0y\\u000aTGJsUy9UZjRKbjlHaVh0V2V0UWNpbU12UXJxd0UrbTRmTEpURGgxb0ViRFhXL3Vw\\u000aSDdFTktQV3F5bEhwTFZTV2ZJcjR0QVJMaEl4NlhLeXNwYTJvY1h1UWpzRXkvVmZ3\\u000aQUlyMi9NNVZOR3JDcEdmY2Y5U3U4NTBEWFMzVUg1Ri9KM1ZEWlYwL2tiOXNVT09s\\u000aa3dnZ3VGYXR0T3l2QmZFTnNOeklUd2V2VC9mOXgzMjlyL1MxYlhJbmRvM3NHRmNk\\u000aQnlKWUFROGM4OXFaaDJsSHkrWmRvWlRiTXZESFhKOTdJVERwb2dHOExrYU1EUWhv\\u000aaExjOUhHRFluVnkrRGsxWE56d1RlajJmWS9qZWRXcUxXVDcvNm1kSmlUL1NmZW55\\u000aQ0lzQ01TU0tTZ2pVenY0TmY3SUVyeUpvYXhET1UvRGRpOTBXWjlBZ29MUi9JK0F5\\u000acDZ4ZERMV1BUZGpsa0RYbHRaQlp5MXRmV3N0QWpqM0Y0Sm5xMHBHcDBqTVJNUXg3\\u000aQWtHMGpycVFpamh6NCsvd1lrNFhLUGtsZDlQQXQ3b1lQbHdWRERMSGtIVTBOeXBs\\u000aMTVNa1lvRks5TWhNVWdJZWpoTU1UZER0eHV5Q05PVWkzUHVrdmFFVmN6SWI2RXpM\\u000ad0JyYUpzNjN0VmhPQ3lMdXBuZ2VOajNLNHltSWxhVlpHVUdxWDlrRERzbG5oZmpi\\u000aeU1Gd3lVUERtUFM3VlpJdDFVRjJZTWE1ODBjNXFpZnF2YWxFZktlQmFXdUMvOStX\\u000aREgyM3VvYjRiazMxT1JxUjRvbTNrdzZRSzhkaDZETHllNTRoSFVhdnIwNkZ6SWF5\\u000aNkZNcDZhMUljbnpGT0tremtDeWk2OW8vdFZyWHg0alVnYnNtcDlQaFUweVpKRHFH\\u000aYWFINjJyeEcwZEpkNUh3ZkZkUnpXbnBSV0JEajlFbkFkaE5VYnpLNVRJaWZaZE5h\\u000aNnJ2aXBsUk1ZK2N6ZW9CSTU0VHd5d2FPZ0dCcjJIaUVqRUhCY3pvWXdkSXNrY3Rt\\u000aRjZtZTA1N3U1RS9uMFVkTmMzbENJZXNqZml5SVdDTUxkeFNnQktXalBjSnRDSjRR\\u000aTmFFK2p2bUpCbk13cFI3enhOMU85b2tCWHFZWnozWUFUY1ZtdTgvY3V0NWs1Rk12\\u000aZTkxUlF3MysyL0FTVnRmdU91L1JOMTBYWm40ZldiWEZjcDI3NG02OUs2RkRYOVcz\\u000aNXVSWEhZeHp6OHl1L1k2TitVNzBoOStXL0psRi8zTFh4S3FveVlwZUtXdlVWRG1r\\u000aT1ArMUhhNmxNbm1BQm1Cdy9KYVg2WWN3bk1ibkZuekFVWTJvRE9lT2o0dkt6cWly\\u000aMkZMQXVUSWo1Q0VWZStHa3ZHRU4wTFNkNlZzTzIrNXBVRHc3b0FmU0IrUXd6bzFx\\u000aN2Urbm8vWWtuancwOVdEeEtpVWxoWHRqN2s5K1p1VjVWYWhmczR2bExLaVBPbmhI\\u000aQTFlRHdXRFlVdDdRSDRQUWUrZjhaV2dtcTFaTnhVUzE2Q2d0ZU9MYjFJZXVucERN\\u000aeFZUSFZaVy9sQmlzakFCaEJpY2x6a3cvWTkrcTlEdU1hbGQvU3plVHZVaXpvaUVi\\u000aM1RTVGluVUozUUt6a2lJWityOFJrdnB0WDlnZks4VWdva1BFa0tleGd3bFdmTjRr\\u000aRzMrdDlsaGw4Mm1oZzQ3bTk3Z252Qnc0L1JtOGlaNXJXRzhqOWlEbHJaMkJWVzRz\\u000aMGNmdmZsaUFTVjMzRElNenJveWFFaXBFdlZMTW96a0loTm9OdkZpRXp3NWpUdWgv\\u000aWXB3c0NtaVJ0NDVnUURyUzF2WE9lRzNSdmdPdC9rMXdhUWZIQ0ZjNkFlWVRKdXd4\\u000aWENMOU1laDFhd05qd3BFZThBbU9oK1dkYk92ZklvVXRVcXRXb1pkR0NXdWZoY0d6\\u000aNldESUxpYmUrZ1Rsem1sTitEQml3ZXRNMGt0N2V4eGg5ank5MTA0a2pkdTMydkIz\\u000aa054WWtOaUVsWUNSMnBBSHNhWC9mczE4YjJzdTRUUlRUSG1MWFVrbXdwcmhSUXpG\\u000aMkpVOWlWV3NmbEVqN2d6SlBMNGRyckxsKzkrUUdGUG44VHZFY2U2TTdLRGZUWkNP\\u000aV3o4Y0FjcW9ibVJjNGZDVFRNN0ZKRXVGUklIcXdvaERRYXZlOFJSUG5BZk1XckZy\\u000aTUJOekpUTWllY3lpWWZIcGE2U2NseExoaU9aYm8wbWo4OGpLN2FXVXdqdng2THRJ\\u000aQ3RqbTk1LzZQcjV1L05lUDJORFZ5dXVBK1pCRjl0YXNhOVBLbVY5K25uMUg5bU11\\u000aR2pndlQvUHJmMS9RUGFMUEltUjhOTFlPamdhb3crRUEzWVBZMytIT0RDQzVlRnZF\\u000aOC9PNVg2QmRpTElzVU9uL21ReUZSS0JHNEpySThkSzRyZlJXTmgvYXg3a0h5amFB\\u000aVkNGV2pQdGp4TDJjaFZ5UjBUMDE5eWdGUGwrRVZUcDFML2UxWGo0RjhRTFZzZGYz\\u000aUXNaM2g0ZGpvREVUZ3V0OFZTOTFuSDRnMzJPYjJndnEzOWtQRjNERzRjUU1kRzha\\u000aeFZEaWtIbTJrU0RjMThaTE82RkFqeXpncmp4ZWVaeFhvVzc3QWZGM1YyaWt1Yi94\\u000aamQvOFhJZzFNZHkwVHNEbGorVEpBUVVwOVBOZkN4MmxUNlBuN0dZMVNBUGptSS9a\\u000aUkVJSEdncEx4cUcrSkdBVXlROTR6b1ZnM3ZYOTNkZStXV1JEWWpxaXRXYjlvbU9R\\u000aYXhmVDF5Mk5yeWtib1pXaWNTb3lMWnhZVFU2bktrbTdUb3lMU2F5ZFo2MWhzUlB6\\u000aZXNlcDA3S3NxTU1Zc2lRT0J4VHN5a1EwcHhVenRqczRJeVkxWWtmcUdvaXZPQW9E\\u000aVStxN1dOTEpuRDZnd2x3bklSSUR3aVpuREJrckNZc0JFK3c4QUNoaTBiN3RqR3Qy\\u000aaG4zVmRjd0FabmQzOWo2RlF2Z0JtWGZERzlJRi9SUTBTNWN1OFh4OTNFaGhoOE9B\\u000aK1hTNlkyci9rbTZwTm9NaVA3TERJSk02SmRrVlRGT1h6VWszdzVrS1liQVZwRy9r\\u000aandjRGJnZVlHUkNxVHBmMFBXeG1YTU4zWjZtS2J6MVFaNnd0TGx4L0FNYTA1Tkgx\\u000aYk1zbE14TE1WWlEwdHNsdVVqSWNVamRNdGlTb3BaYzBOOWZDY3pmN3VBMUl4Skc4\\u000adFIwdnltdkVQSGdKVXVSYXhxZ1crSHV5eDd4ZVAvNVJGS2VBZmdNcTBzaS85OHVS\\u000aSFlZZFVORUZSUmQ4WXluR2lqZFlxZ1lZZkNnZnM4bmcyWDlsdnUzaFNIMkdQM2Z0\\u000aVUdMS295L24ybE43ekdjMFdxQWxDYXh0WWdNMFVwMmpQWDd2N2ZySUlTc0sxYmdX\\u000aSnZXN0xEQThJMjVEVDZaVkdOY244WkZ6RWV3VGJSdlBFNk9oeDdSc1ZBL2JwbVBP\\u000aR3prQ3N1V3A5OVhSa2tQQTNaQmluejJ1RXIzQ0NTRU04eitIeTZrV2RRTExSTlpO\\u000aZnQyV3dBWFVwc25tL0YwNmpVZXU4Nk4yWnNMeEN4S28xYnNYYlorKzNCM0NTMFYz\\u000aYXVBYXN5aGwwa1NWczI4eTdYaTFSajFZV1VabHNmQVYvR282SXZyNE5YTklpK1hY\\u000aWVJtaXNRVGI0UzNHUXRvRmhvcXdOZ1p1L3A1dzBmc2lVTDBFK1BDMjRvVkIzNzlj\\u000aUG1pUXUzdTZ5eE0vUVVCVW4vNlQ1U215MEszaUFGdTJEVU5ZRkg5NllEdFNZK0RV\\u000aVDJJVTByK1F2K24rYUJ2SC9xRmVLWXhNZTZMVlF4KzRNTk8xZzh5M0ZvYTNzckZV\\u000aT0R5azM3YlVrQUZWUXNPUWNEV2d4S2l0TU1kbWdpc0JwQXNNeTRXQTAvTnVqVGZy\\u000aUmZWVFRWVjFxWFJZL2dMVVNGbmMxMjNkbW11WEF4UjM1cFVzWERwbk0vallRcHRM\\u000aSmtNcHpPWnZmTEhNVmpVQU05WUtSOUhxSFBxaWVoN1ZZT0t4ZnlTL21ZbnpVWE1T\\u000ad3l1VHdRL0VLaEFkaVo1bHdhYnBhcEYwb1RCWWN3ZkVnejRRZDZjZVgvOWh0S0xx\\u000ab3o3RGpMVVlqRThPK1JxanpVeGJTbThvMnpHWG5yL1B3Mm5COEw4bE1yQlpTaUN4\\u000aUkJuK3lkeHZ0UnRGSm4yMWZMVmlqYzVOVFpDUVZ1bThGUlpTa2FLc2JkQmVERFNJ\\u000aaVJ3NGErY09mc3FPZjNQa2ZScTNraDJ6TUd6Ylk5b1MzWnFxSTJHdGowUmJaMFZ5\\u000ac1VTVWJnVU5uQ0lSR1RtOHE0T3J0Skp6Rk1oYm5Yc0R1MUxJbFY4b3ZTaW9VanZr\\u000aU2I3bnhQUTQxMGljZEt2NkczNmx0VFhVVkhnM0RzMFFrK2Vha3ErUk85clhBYkxD\\u000aYzBxTDhkOUFELys5NFZ0eEZ3a1M4NzltUmhGZDlZQ1FPVU9HYWRXbzJUYnoxM0hs\\u000aRDNUUUVvQ3JkQ0lwdGdhVTZ3WURjZzRtbi9IcW1aK1RuMzFJTERDejlvb2pPM2dl\\u000aYVE2aUR2eTlhVEl2TUdrKy9GR1B1emRHYmhRWmorSFFvbWNDaVMvYWxES3h0c0Nx\\u000aU3RkaWRQTmZwa3ZVSHA5UmNERHorVmlMMUlKRGcwVkg4N1N6VmNjd3Bva0NIaW9B\\u000aZGsyLy9SQ1lwbHFQWGdHbFZSV05jK0w1M3BhVFpPT3IrQXpFNUI5dVNFRDI4c0lw\\u000aVnZIb0lBbGhpZFNDT3M5UzJjdGhqYTk5WlQzREFMbFRYcFd3NDdpZmhkZ09aVkZU\\u000aNFJEYUlpMm9TMVp0SStkNXJSQ21PN1lEa3liNjhkc201UGlLZUVGdHJNYm1mcUNV\\u000adDhSWUNEd0dnNHF1UEI3Z3V3bExhNnhHczNJQTV3VVNJN0FUWC9CME9Jc1NsSFRO\\u000aZU1TYjlVbTdQTGhieUc3T1JKaXNLUjMwWEtkVFVRUjJGMzZWdzErZDVHMTBUWisz\\u000aaE9XSEc2bWlHU2hPZkFJY1hBN205VkFNWXhJM2lSUFBqLzE2STRGeExTdVFDYmFa\\u000aUmptb1hDRGRidHRYNXFqS0NXRDBBTEl3RmZ1VEFMNlVQV0NDYzRKOHpnMnJpc2pm\\u000aZ09tU015RUJ6UHVBRkc1Uk1lZi9DNGJzdHVGd1JDaUc1WkZlNmhyMUE0RkxLODAw\\u000aemw2ZDVjYkQzN3Q3amxXNmIwVHZpaVFrUS81K2dqak5QaXdPTGxPRU8vWHhXN1gv\\u000ac00zWm1EZlovZUhLMDM3VXd0QkRpNTBGaURXSHJON2svNXladnZFL2lUcUh4OHBW\\u000aSjZ4UXF2QWdLRlpFamE1Y0hEcE5MdWFTb0RIMjBzelNNL0NmU3g1SyttZ2c4L2ht\\u000aRHlBbXVPT3RJVnk4N2RQY1phUWcyZ1d0K05vbnN5eXgwR2k0eGNuNWZEZzVPQ0xT\\u000aeC81dm95REJNQnltZFp3aS9QSEtBZlRMWlBlaGlvemRDb21vS01nQ21JQ2tJS0hl\\u000aM2M0TkFTN1B2S1hSWDI3V2gwbk1aNFo5TUQxVzlVeUIvMFVoVjJQUHdLVnpvY09w\\u000aT3NEZk1WWXI0TXdxZjlXTEtFME9BQ0E2T1ppZFJYRnBKN0lUNW8wMFNzNStXZTNh\\u000aa3dER0hRRVhPN1JQc0U5SzloVmJDUDBuUk1YUDU3bFZ4WXBPRG5pRS9lK21MekFT\\u000aVm5rVlYvWUM2N0ovM1E5ZXpQdlE5VzJYcDFRTzlRUjRkVGpnTTEyRVBmUEpyTDV3\\u000aaUxaeW0zeitVNlNpUFFXQTNMSDVOdzVCQlRGMGlGRGxOaEExTVorUlIzRXU5eEQ4\\u000aWkVaV0VMMkIySGR1L1JGcDRkaFI2VE9FZDNTTDhIaDJYcm9pRE1YVnBnWU5FS1lG\\u000abENQMnlDTUNsQkFEcnNuQWVRR1Q0bVh0Rm5aMmVCSGtHNEhTUVRtQkM1NVgzRjMv\\u000aYTAxRmtNcTBtelYwSWVzUGM2UTRVc1lMWHZIQkl4L1lrT2hhTnVMMmprWnRGejdL\\u000aTDFQblRESEt5bWJJcFc1RFZuVDlFU3pHbUlDSG0xZ0lleVRMN0x5MldSTCtBTFdw\\u000aOW1aaHhJS2FxdmdmK29jNWFGaGlQellEaDFjS3ZxVDdHakxBTHk1amJrbDI4QzhO\\u000aSlFXZU9QR0hFVjRsUXJmNy9oejEzK0VrTGRaUHJuM2tJOGVzVStURXVST3pkSXN4\\u000aWUgrU1hpOGhxeGt1ZVByN0Z2aEF6bXk1WWFXYTZJT3JHNkM1RTZNTndCcmhVYXNF\\u000aMlQ5bE5OcG05a0Ywc0o5aTFud2o3WW93S3BnTVR2cWJFWUszTE05SGUzMnhRN3ZI\\u000aN2dncHloVmhBYk85cCtBZHQzT0lsanVrTC9NUGxRM3dnWDNyS1lBM205RWlyaDJ4\\u000adHhQVWR6cTI2NzNabjMwaU9vcWRBQzhVaGZFN1R2RUdMS2dZb0FlSGlqMS8wekRC\\u000aUEJNUVkyaWNwblpyK2dNV2huRlBtN1dXUmNkQ00yOFhsZTVBa3ZoSGtmM25tOU9P\\u000aV0RESStERkRPOHJhQ0N5SzI0QVhMNWxMZWwySTRlTW8zNU5kT1dRaWtidU0vWlNW\\u000aM3Y1WUdSMjB1OHlSajdrZ2Uva2FvSXk5ck8xaFA1MDFxV0xOd2owUFpIZTZ3TDhI\\u000aT1d5WHhnMmZweFRlbjRpUVFRcDJqRmEzR3hJbDk5U042emJvcEVZL3FGa0hjR2t3\\u000aeFk5S3EyOE01Rzc0ek1xK1JaTFYxVFVRV1h0Sk9lOHZWUDFkMDZPRHFSMlZrOUla\\u000aaTRwSGd5Zk9XNlBWT01WcVRGRkpJWU53cW04alJCakV2OUZ3dUluajA3ekpXRUp2\\u000aMC9sdXdaRFQ4R3pEY0RoaHdyWVFFR3BaVkl1ZVlXbkRoZnRxVkloS25zTW5KREFG\\u000aQ04zSEhFTG1VbjdJRVpIdU9Sa3A0alpSc0x6dTliK1RmSDhGYmU1d0pJVHBiSDhB\\u000adzhweUx6VTdqMk5xd28vYU5oZ0FUUmcxL3BERWpOWlArcEJ1T3hIRy9ldVM4YTBz\\u000aeEVETXFTclUxSG5jaWxFSkpMRU9yZ0tURkx2ZDB0eE8wamRGUGFLOGttRWtmWVVn\\u000aSDdJbTNudVQxSjVScDEvRXR1d0E1Mmg3YTVHWEhaTmduR2hzbE9kN1ZRLzBCQ1dL\\u000aNG9OaHBTY0FybUZibEhVMDRLY1V4dlAzV2MwNGZJOEV5ZHdZczFDbm1iLzQ1TXU3\\u000abnRCM1RkUDJOdXVoZlZHQUJyOEF5eS9UTDBSYytZdTcyQUxFZ0w2MkNtekNyOG9R\\u000aaExEVkQ2RnRDM29PQ3lMNXJhbVNKTzVXZ2d4bTA1WlE1UFN0TWx2RmVrNnhnd216\\u000aeUNBSTRzUkc1SUV3NTQvM2N0TjZxUzRYTEFVVWNlRUg0eUQ3N1VyZEdmdWw0dU91\\u000aOGNJZEk3alFkcGZQMW5XSjZRZUgvRDFCUEZOREtwQkhCY3hRbjd3aTBGckZOSTZw\\u000aTFpEeTFZYjhYNHQxaVkvVzE1b0NQUGw1a0hoOGpyeXpUb2tRN3NSbWcvaHh0UEpv\\u000aaHNqM3dSeW9OS2ZWSHMzbzg4dExWTlpQYUNPKzhUWGxlRm5ycGU0N01QZE9ldU5n\\u000ac0luaWk4a0s4bDJ0UUVpMlVpTmtER1pGdGliR2pxdXE5cm9nUWpSMXZMNDF2czBy\\u000aaGdXL1I5OHp4RDgzUzV3c29qQndEWXpPTzBtNDB2WVFFUEVoV0NXV043SlRaWEN4\\u000aMXR2U0hDMmZUSDREa3RjaHkya29CZ28zUDdYTXZPUnYyU0w3ZGkrajlKdkVqVWxx\\u000aVkRFTWRQRDc2b1RYYXh5T3lLUzVVbE4xTDJYbWk3QlRYMmlxL2xueGwyd2VONEx6\\u000aWFBsTmdEaHN0KzRSS1VtYVB4a1QrdlJpdTZ6b3dEV0ZlNGQwUHE2azhRZU1HT1My\\u000aUFFETnhuWHNXUXZoc0UvWGJ1SEl2Y1ptUVlKTjh2bHdGSjBzdnFkV05URWlDNGdJ\\u000aWlJxWHJ1MnUybG03b2RCSVZrdjUwcVVnRENLVG9xS2tkdkYwOVhnKzZsOUNiZjJy\\u000aQWE3d1RjMlU0ZEVtR3VxZ1pyR3VYRnhVZmlKYVR5TFE5KzFLcDNnZFRJQTVFVVRZ\\u000aOUs4cWhnS2lHdjNlQmdIamU1VXhITUMvMGFwWGhiNkFySEM3RW5yOHhEbmN5YU5v\\u000aOXJmSTBjT3RCT1g1QVZsS0xZcVdnWEp1bDZTNmZSWWpvdVVjaVF2UHpBRU1iUERV\\u000aaU95ZVVTQzd6SHpHcTZ4LzlBQXFySEZrbkIxS1lYdFJYWk5zQlNJRCtTV2NNMEZG\\u000aK1B5amxJbVQ0K2pYOFJBVjVGdTNpL09hcjBJNk1NVldSZzhNQ1RsRzVWWDd3cmt4\\u000aQ2pGUW5scGs4U2NrbzlRZkNjb1FsTlhyK1Fuay9rcFROOHJHQktvQ0xZVkpNWS83\\u000aa2RYZlluOXBOWTJXejlYSlJXcXh1dFRoMXU0K0ZZUzcrY2h5b3g0Q3ZHTTZjR1BP\\u000adDFZY1BJMjl3cnlYOTFiMks1MWdOQkNzSThPQlJXTkdkdXhMUzA3aDh3eDFSOHVS\\u000aY2dETm9kWnJQQ0pnQ3ovYjd5R0EyMDFManUySEFqeUR4N0pnOUJzTmJ3dTZnZW1z\\u000ackNnOHpJQjdZOFdsQWZueUhuOWRma1dhNFRZMGx6VEZoUStOZUtEM1RaUklrV21J\\u000aQkpUcitwaW1FWmJUSFIxSk5PeUh4L0M0cFlTem94MXhGYmMxbndMck5rd1lyRElN\\u000aM3YxaDQ4eldub3Zad2hIUmk5d1kxdngzQ3RiVXVOMVYwZnVGU0U4K1pvYmNaYzd4\\u000aZDVNdUJ4RW1rYUFneWJSQ2JSRlZvUFgxdjdGMklkZGd3TFRYM1ozSGNZdG85eWJM\\u000acWowZ0FNbUpadTJGM3pYUkkxUFczc25STFpubTd6TnBCYVUrL1luQzRjSUlYL0Er\\u000aMy9zZ0tYeDR1U2tqTGlwN2lTU2xoTTRmZFQwcFBSaUVoTkRyTG16UzErWmM1UXpN\\u000aaVVFVGM5L3Q4bFJDa0E1UXhYZkdmZmJvTFNGT2VMNTV5NWEzYXhNMUtZK0VzOFBx\\u000aRnk0cGhYY0dLVHZ6dDcrdXRlOEVUdWJKUUR2cStFUnhTeWkwWm9kK2RyTC9zSmty\\u000aa2tMRnU0ZGEzOTlkS3VobGRMekM3MlZxS3VDTUN6eGtOU2NOT3ZRSlRYVHlEblkz\\u000aa3pXRnFKK2l6SXRvTm9ydVRNUEJTNkpOMEJWQmlBOFF2bjhWd1dyOXEySDBzWlJ2\\u000aNWxsUkZZZnM1bEZ5TkI5bkpONnVPZ2JMU0pNSm02ZGc2NHlITDdFOXE4OE5rZDVx\\u000aMXVhY21pd0VUN0VzVGpSUXdLMm5oN05lMC96VGVpSzdiVG1RMW1KUGpwZEEycXp6\\u000aZ3lIRGoxRVlNenhoZFZIb3lHQW4wWlhDak96T21SR0F3U05pY3VhR1I3aERpRzNU\\u000aZllxSkxLWUorUHBnYTh4NlRha0xwcnZyK2F4c01wSWNPWkFpQy9jQUV0REFQV1lN\\u000aQmZaeEI3cFdSR2NqVThPbDhzUnlwTXZ4ZDByWlpoZDR6K2NSQ0p4aEM2RDl4blMv\\u000aVHd5MWVxOFd5TmNLdDYyRkVaU0dMWXFCaWVUSUp6ODRLMnpTWFdYVzBDZnhrcDVu\\u000aZXlnbTc2eFlyWmJLUndPcmxuRVFwaEVUbVl1SzB6RjdtOERKOVBtNlBNeVl3SVVP\\u000aL2t5aVYwU0R3WW5CM05HMFdSNEtFN01jOUZOMWFtM3l2N2IvOFBPRWlNVDBpK2o5\\u000aWm5lajRMT2ZVcnVVTDBqc1UyRkxSLy9RVXpaZUpxL2NaenBKc1VEY2ZvcW1qNERI\\u000abTk1YW5IQXNPdnZJZXBqdDJsQ0dLZVExRm1yb1h1NzQyc1BQMndySmtyMDd1SThM\\u000abnN0R2xucFNPNzZ2ZnRDa2kvYjc4THJOc0VIRm42ZDgzM1JXbzUrWVhaUXllWWUw\\u000aUEovWUpad0c4bFkyRS9YZWFrTjAxSjJpT2tNK0lmVkhnYWsvUG5PRVhhOFFqOXdu\\u000aejBNKzY5eVFGVksyVDJxRW5PUmtEZmtacFJtM2x0WXdqcFhCbDJrdDVKUE5qVStH\\u000ad1A5SjJHdExWR2IyNmJleCs1QmlVNWtxbUQzaGdHUlRsVmp1WXFkS3pYL3Z5bVJP\\u000acm9MZWhHMEZtMjFpYXFvZitQd1I3ZmlOUHh4WitLa1Axb2JGb2xDalo3S2o0OWdj\\u000aR1JNSnE5U3lya3BWcVkwS21YMGw1SnpERE9QUWdiRDhlRlQ1ckhjbFc2SHVCZFdB\\u000aOHAyckhQNG5BaXhiazIrSGRsMG5Rd3QwalNwUHNsSmJrYkpYQWtaZnZJNVVwU0RY\\u000aZGpRQmlXOFNJRWY1QXhPaUFveEdGQksxKzZzS2xJMzMzNCtKYmlSOVZDQlE1akQx\\u000acjM0MnlPcDlzc2VjZEFGVmRNQXZOQk1jQlQ3Nmx1ZmVlRkNCUFRQOC9sZFF4dmxy\\u000ac1Z0SEZoRHBHa2FYSk9hck5TVlV6d25uU0djTTZUMEM3ZTJLV3l3VUpLb1pYdmwv\\u000ac3czdG5KaFhTaDE5SUJxS3BLYjBTV1piTTZFaHlPTmZHc0hqSkhuR28rVHlBQlRu\\u000abWtNY25tTkxPSjcxYzNnMjJKdk8zS0diMGRQZTNYMTEyS09LNmpEdFZPVjRIS1Ax\\u000aK3UzRkRCT2pqYWU2SC8vYjN4RVNXWTB0VmlNSEN2YUVVYkhKL0dyQXpNWElwNTNB\\u000aYVRoSXEzVlVOckJlTDVraFFjbDl3ejcxM3JLRHkzSG0wRWxnQUpYSEt2cHpYS3BC\\u000aUm1pUDFJVHdRQ1F6L3lTREF5ZldpK2pxT0hNdUxaR1oxcW9qT3V1UnhIdWFTeU95\\u000aQWFwU3F3TUtFQTlIeGlZeFB3UUEvcHFySENJS0JDRWtSUnRrNDloQlY2VXdsOVdv\\u000aMnlJQm11cC93UE9rRVVRRW9NckxKL1FMSlZyUzd0N3BaRkNXdmdwV3RoZXcwMjBj\\u000aNTQ4QmkreEl5UjdFeVFmaXB4NmFtM3JzUUNLdDdMTXIwTXkvNVBkL2d4bWVNRjlG\\u000aUmNCdUtEQ3FlWEwzeWZWZmhwMjZQQzZTenFBdmJsbzh2ZG9EWXZKenFkWGVlMXFw\\u000aYzJmeHF6bFBkMXpicEJzeTh5NjRMM2V6M1NqWDBubnMwU2NvaVVuQkozci9hUG1E\\u000aR2tzUU1UaFBlbzVOcWpVTmc2d3FUQXlDMThqc1ByNkd0VXFMQ3lSOU9UZW5RaDdM\\u000aNXVSK0FMTVRscC81N1pMMjJkc2liUUJEdmVhNEtISGhzWjZzbDBGKy9YdmR5a1gr\\u000aZWU1eExVMnFES1RlRVkwNmt3elNQSTVxWkYrTXRtVVJTUWtoYVRuRGJYRy9kd1Ir\\u000aaHdRb1RQcXpBeURLRi9ITmRZVDdzM0lxYS9zQkEyTjJZVXFJbElId3Y1TUFGclE5\\u000abXYwbFhrc0FHbzF6TUpKdVRNUFY4alFmdDh0NFB4aUY1Uml6b0s4cWI4TjBLK3RQ\\u000aTGRJdWJtcnlJRitYSXhkV0t6NDhvMWR5MWYyalFIV0V5eVJNZTNvM2NTSCtDRU5S\\u000aanM2aDdPUjhyekd3ZFJxVmlEeHRtR3FMc3lhYVZYWUoreVZ4Zm5kNmg1RGNTNlI2\\u000aclAzOS96WEtSS0dYU05zd0EyMjBjTy9ER3VsYVdtT0pLand1TkNFRHpFM01sWHc2\\u000aLzB1cllNUktsVUVVTmpDTVVxbEFPSUJ1Y3g5YnhEYmpzU0lHN0wrSDUzSFFXZnI4\\u000abVlaOXhjYnFidXc2Yk1PQi94Z28xK0RyZkQ3VzJ3YVdoOGpKUW03NFN1L1ltQldT\\u000aUjBOVEQyNXd5R21zTVJOYmZvS3VTbUZNM05pVXdOcU40eVNQa1FOaTZod1ErNmVC\\u000aT2lPcmY3aDJqdE1VUU1HVFk2dEYyZzhzUVRRZVRVa0NqRkordExVVXBlR3BRaTE2\\u000aKytHa0UwV1dJWlBzeGtuT2Q0U1lXdHZBUWxBWTV3RXlTejFYQVNLNU45cmx3TldX\\u000aWE4vSjVIaVZacE5tVDUycjkvSTlzRlhpeWN4d3NPL1prd3lMeWFnaUw1cE9hQ1g5\\u000aUzJuNmVDcmk0cjBpcUtSWTE0QlhaZEdrNGlnbHpQR2tPMU1zc3JEU2FsejZIdGJY\\u000aMWgyd1VSMHdTZGlETHpUc3o1QmR6USs1ZlVwOHMxNkFicWlxQU82Y2Y3WlpPRWFs\\u000aOFBVZlI1bzZQZ2llZVFqN1lQUjdqcmVtT1RwUDZqaXZZLzFyQzBJYThLQ2pyNzF1\\u000adVBEa3VVVlZ0MXJiZzNZaCtWVE00aWU5VS95U3lXSFUwejZIbU1icHZCZ3AzUTV5\\u000aaXN2azdtVFFDdE1uNkR5VTlKSWlDRHBhZWVGUGpaVWJiSXRqbytiWFV2SW5ZbUxu\\u000aankwaUVJYW80YmhOcERGSjAzcnltQ3NMeTRSb1ZZczQ4NWxMd3hEcEFLbG4vMWFY\\u000abUFiK0p2VFFlTE1xNmMrRUtqR1FITXJycmU2T3VaamxiKzRDVVlBYkdLclA3b2Mz\\u000aL0tVL0JrTGVpdm9lQjFXaUgvSHBncDZSNVh3VTNvUXBXTUtlc244UkhMU0NsYWUz\\u000aaW5ic2FsNUpGK25KUDFSaXZldnNya0IyMWU0OXcxU2NIbmJVdDgrZEJJc1ZqOGhD\\u000aT1p2SjdqTVR1YUJteDV6UnJGUk9OSHJuTjdOMlFPQklpUmxDVFRmSUJTci8zdkwr\\u000admxObm9GLzlMcTU5c1gxY0JrVk9qQmI5cEFJRm85TnFRMHFLdGw1YXZiSkxXdG02\\u000aa21lei9xcG9HT0FRWnF3VE4xeHpwTWtSRTBpVExPQk50TkcyazM1RUJwUUI4WmQr\\u000aekFJM3d2ZGFPV3FsRk1oSHVQTHVTejliaHhEa1RicTVwSzhMWGxNVldURFVUM29L\\u000aM0g5d1M4bTE4aW9IRnpPUUtSMnVXc0FrZ09yMEt5b0Iyb1pEN0cxejJOYWNLTmgr\\u000aOFlyZXdOanVnZTBSbDJaWmVSVkNLc015UTRqT0diSmV5K1hQWkVyWHRGNWtsMC8w\\u000aZDdMT3BVQjRUcWM2NVp3NmpBOTFRK0c0dURuN0xicXY5LzVoUFllblBHeHM2Snhl\\u000aQVNhTW41OVR4L2JYUlEyQVIrbnpyNDRMTG9xVEN2dzJCRzJ5ZlBzb3pwZlpITlIv\\u000aMWE3cGRRdjdvVzhwdWV2WjYrb1p5R3p1NDhPRmRTZjFjWnNVMUhXdnUxd2J0blgx\\u000aSGdFWU1hNm10MWR4WjlNMktzMWpMc252eDdyTjJBMHlUeXA3WndadTZCQlRTeHVS\\u000aSjJiYjY4THJFZDlSbU9FN0VKZkhpZjB1a0tKWnIwZndJM2o5bkNnWk1hMml2Yzk0\\u000ac0NSMXV5c2pWcGc3d2FoOGUyRkg5cFN4U2VZa3RqVzBnY3ZvVndLNmZiRThiWVp5\\u000aQU1DL1A0Z2JxSlRIWkZzeVA3dVVIaVhQdXoxTEhnNXdOSk5BdXYxSFEvVTlLQlBF\\u000ac1lKd1R3YmxEa0RqK0RCbE4yZEVtVHpaVkpWbGU4SGlINGhzT1NoNDQ1Q2xHREFn\\u000aL2hZTE1kYTBqSDJaS2NneVZSMnhNMVlYd3NMZTR3QnNBNUdLRkJTWERFQjZmMkIv\\u000adDJIU3VZczFmNldpbEFEaDBqaU1JcllTTnM0Z2tOTFJYU3IxbkxpaGxMV1FWNzZk\\u000aU09YOW55MTJONFFwZ2wxTzVSSzUwWjB4SktNNE0xN09xZldHcVVFNnlSYWx5V29D\\u000aakFjZzhSdE5TZzViSjhDUnRQaFJFcnNZeE51VzRVZHJSaEk5dThxU3dERTl5QmNQ\\u000aUWoyUzhodm9FYlRMbXV0SW9zRXdvdFFOeXVvU1NuN2lVQXJwSWpuVzhLc1U2VTAy\\u000aeCtzd2NYSDl4VU92ZE9ZczhCWE1tSC84bXFxV0UzMkpVcGJGNUlaWEw3TUIzMEc1\\u000aTTg2NFZmWG5HK1FUbmkzbFlSWEhyd0Z4R1FPUTY0M2hzVkZDSVVvYVhiczRkM2RE\\u000aajZPUVZhVGxtM0k4R0ttYVNNSSszR0pYNWZFVHNOYkdGcCs0ZStNZEZkak1Yb1hR\\u000abjZjSFVGN3NYd2FIVVRtekphNDZaZDBLSjVVeEdicU1oMUo5cWJLamUvWWJzNjNZ\\u000aTjAzanNWNGljZy9qNngzb1VvRWdnd2lDSW1td3pIbDZVd20zNGNmZ3g2WEFJM3BW\\u000aaTIxMHhBTll3K2M4WDNPbGxnbHlEWjlaOHE1bTZOMnV6UUZMTFRDYzVIUVU2eWkx\\u000aU2g5d2pjOUdkakJSSDErdFZ2cVVDbnUrZXZNanBZL1A4R1hDZXRIdEhGa2xER3dF\\u000aMnNQRUI1WkZVZFkvcm9WeDdRczVSWVpkMVdOVEovRkMxRk1YTkVtTkNqRFNUUk9X\\u000aVUZlaHF2d3RjUmVQVHdkdEdjVWdONmVqSXBOdTlzSWNoUFI3UkVOYWtRRWR2UERF\\u000adWl0dWpQc1g5a2ptV3A3TnB6MU1XQzV3MGlEOXdLVkhHc01jWGF1SlBwVFVCdzUz\\u000aS2M5RTNGc3F3Q0J1cGNscDRZMWpzRk94WkYrbTBweFlnSUxPS2JSTjBjZHFGT2ll\\u000aRzhKcVJidXBpaGovOEpwaVg2RlI4dWxXSXZzZ3RSU21pSVZodlo5L3V5cjVXbkxJ\\u000aNklDV1hWVHRWYVY0clF0QUFSV1VlY0JYY0FXRHcwOEhzL0sydGpNQ0t3WXIxYzg4\\u000aSU4veXdaVnBuT0lveHdxNU9wczg3cnBqS2hvaHlCMk9ORUlNZlBEM0hYZG9OQWRY\\u000aTlF0SysreG4xN05XNHF0WHFxQitFeFRDNWRGQVpvT0I3QnpiVFdKbjV4NGMvUTNw\\u000aeEMxY3Q4L291ZERnQ1drTGZpT0NYWEwxbzlqRjN4SEsvL3hhMEducFh3Nm1IRndw\\u000aNW5XZk5UMFFDSmRJcWRrM05WbklIcTJwRmhSTDFwSUptdHBTOUNuSlFiNWZLVkcr\\u000aNXFTM2pXMkNzdTZTTWFiSkpNQm5vT2l0cWpTRzJxL0pIMENKaElCZk5IeXVxK1NF\\u000aN3FhaEJmZ2dtNlRQUkMzWXFjc2V1R2Zqa1N2RnBXN3hNU3c2QlNvZWljdktVTUNp\\u000aQW1GQVB1MXBNam5MMUp3VkpFUkxHcVZrVFdZanZqanduY0pWZWhJQTFNeHNHWWsv\\u000ab0ZpbnF5TDVsSVUySmNYMi9kcXlKclB1dzR6eWxIU0ZXT0FPSWtsSEN6eVFSN0lr\\u000aeFphbGJDYmpjWGRFVFZFV1YxSnJsZzVaMHhNbG5jYnZjQnUyNWtUMC9oYmh0alNK\\u000aUnJMU0dqOGx0Vm9ONCtCWmt4Y1ZTVUtLVGhSTGtKeENBdlQwV0RkQjM4aDh3eWtD\\u000aODVib0ZmU092UWsvdXFWalczK3ZzY283V2NzRmE2OEVKdWN1Y1Y1QzhiOEJ2dFV4\\u000aRWRiUXZuMlNkcjNUTEFqazlsQ2ZtcUM2Mm05VEpHOXVxdi9Fc1BxNmxtWFNLdHpv\\u000aWmo2Z1Z5ZGd2T2FXajZLMnF2R20xSGZiOTlpWkdhWEV3Y1U1bUZGNVBZYlMrdVVl\\u000aTlRPODgwdTl1dVJlYzJlR2dBMVR4SlZTVHY3N3ZuRTI4cnBzQUZycWl0ZklwTXll\\u000aUW10RzAvQU05bTNMelJmT3dLNTRBeEdDRk5CV2txYmpRUll0bUlaa0hWdDVkQS9Z\\u000aaXF3KytQQjkxaWJIQ0l3WnAwdWYvL1AzdHRzVDRHUy9KNjBoZ2pWNEJwek5FVVJJ\\u000aODNkSEo2SGZHM2dlaXlNeGYwd0ZuNjVpd1loc2s0bng2WjlleDVEN0J6Y0U5K24z\\u000aWFVBVkJmcXV1V3d2Qitxb0RBK1RpMVRDQ1gzTElteVM2RkhJZU50Y0lOQTc0UldO\\u000ac3ZtY01mZTlYUi9IQ1RERzMydXk3QzhiR29RQ3JFcllreTRXTVlhSGZScXN2cjRa\\u000aWGV6TGpENTJkbHkrV3UxQVd0YmtxbzU4am9pNzgrYjhhaEREVG5ib2ZFOXdoeGxW\\u000abTdGYXB0Z2NET3E1TER1WDlNTHdZRmM2WGludDZIUGtHMUhoeE1rMGdIRk1xTzJs\\u000acm1lQ09nb2t2MndwYk1MZ0txRUxZR252amNzR3R3WDZQMzlWNnlFRmcrOCtFZzFP\\u000aR2tRUmkvbzRScTRjSm1QZ0x6ajZKVC9FK1VZV2NjQitLaXc4S29NOEJBVGVsNEsz\\u000aVFlhcHlBeUVyYW13d1NGWldKOGJDdUx6WWNRODVEWkxCRy9UaWtDUHA2RmZzQy9V\\u000aNDBCWGdzZ2IvOERKS3U4SnNQRWZ5WEhFR1I2cEZSVHoyVmE0YXRiL1hCc3NMcmpm\\u000aTUsrTVJ3dXZnTTZmQjBjbUh5eXRkbjVrdVBCUitSa0FnLzgwMVRhR3RJUml5UnlQ\\u000aYmU2aXZSa21tY29idTVGc3F4eFlCa3V0VUxoZm1JaE5Ma3EvQUhvWGZZTzdpZnRW\\u000aMkljTmE2QkZQU0NaajZ1SlY2MDBKN2swRjRnZ292UmVWZmlTMFFoSk5TeEZ2YUQ4\\u000aZVRuUHlVc21SWjY3blMvenp4QVFyN0FrTXN1S2xLVlBReVlVOTAwcFZsaGRlNEVH\\u000aalRTREcxTjYvV0crdWN0SFo3Mm1DM3VYQTdoUUVLZEdxbUs5WER6Qmp2MU1UWDQ1\\u000aakhFR3JWbU5GaytKVHJFSkVsdEdRTmJqRE96UklORklxMVgzalRtN1pZTWQ4MVNv\\u000aOS91Tk14Y2hDcXExUzkybHMrUkl0elJJSVRjZVVDMkp5NVdtQjUzUHNqdDNWYW4x\\u000aSThBaTN1OUxUa2djaGk4N2QyNXVRbEhFd0RGMWZydjgrb3NubUZBQy9GbXQ0YXA3\\u000abjRKenFzVUhDV0RucVU4RjNEVVBTRXBsSEY2UFFNc04wd0JnaEdDNmdpTDFVU2ti\\u000aci81UUlhNlZWV1B1MHE5OFdyVlNCT2dnMUxHVVZvUFVXOHdlaWdRelpXYW1PU1hs\\u000aY0FkL2lrQmVaSW9iVlY5VDlDZytWbUN4Ynk2eGhBL2kvRzZDSmVjc0c4UnpTM1dN\\u000aY1did3RyeFZicy82bVhoWGtRZWhCckhTSDZyUTdvckdMakljQk52WXRyR3FJeFF4\\u000aNDRKQjJIdUdyTUR2QW9rSEJCYXMvWlBsOGdOTVZ0L2ZqQm1ZbFdRSi84WFdBT0Rm\\u000aa0JHMG5HLzRBUldUanpkM1lsb2xKQW10Qnp0YkNGWWkvNTlaWFZvV1hBbVg2b0g3\\u000aNUhvZmcrRHdmQW1nalYzR0VvKzhUR3VnQ1BqMFRJRERvUEUzV0IvR0wvUlAyRHRz\\u000aZVZ3c0pxak1UM0tWYjVTTHZkdjNLWFJXdVF4K2JNaVZCckZQSy9uKzhZNTJENjJi\\u000aT1NPZHVka01jQVVnaHpuRUpNWUJPZGtZNnplUjRLbnljVW5wc2xiTXhVRUtsMGht\\u000aL0JiM0FCUWdzMXVGZmg5QUVEUjJ0ZmJKNEd5RE5lZSswVEVYbDlTRHFRazB1eFAv\\u000aTEFMTUp2Z1ZPdHZqaVg1bjQ5a21icVdQbldWRGo2OUxPNGgxN05IWFNhQU9uNHk4\\u000acnVrSnh0akw4VTZLdTNST0tjMnlEZVpwNUc0V1dUNVVndjJQSUdyencyM2FqMWNj\\u000abE0ycmpqeFF2V1RQS0cvaDl5bm9GWjMzWm5LNkdGSnRYUTJFQ21VTGZ4OVZ3UDZj\\u000adWpzdVNwRVQwUlo5NXk4Tzc1dmNBRnhXNnpubnZSNkkvRlBxbHE3MzM5UnBJRUFH\\u000aTFRuaUQvZkJLSi9hS1RyMXlaM0IveldiVmlsYkdYWlp3UW9uZnptYy9qS1orVTl6\\u000aWXlTMTZ2Yy9TV0k0aytiQmpNM2hoS1pKaWJFeGpGalpIQStVU2lQS2Z1VDV3T0tx\\u000aU2lsbWJLcWJNbWtNLzNKelZCTlJtSnZwNkxHdnRJdDVJMkYyRS9DTXlPMjRHQ3RQ\\u000aajdlYjlYNlA4cUd3SG81VHlmWm9Vb2VPaXNMVFFmZXpISHhXUHFGeVdKY2VmSE9B\\u000aM0VjVTgwWHhPdlhyUWlKR2laUlRWWVB6dnAzU1ovYnJRRk51bHM2Rm5FYW1hRER2\\u000aNDJqSTRyVi9TYVFPZ3dRTHdYMEd0MCtvdGRRbjd4S1diZVNHNWhNbzFXMkdFRC9r\\u000aelpJRGM5ay8vZXdkMXg0UGhGekRFcjMzSDVtQ09mYTcvTi9KR2wvYXpFUnl3Qm1j\\u000aTDZ1enBFQWd0YXRrSjViQytnVy9objM3WDRRZml6cnZzQURXVU5uMTljK3ZzZG9M\\u000aelNwUmVzNDB2azQxUk9SakZ6eFEraUZnRTluVXZLSEx2ZnpwSHVkeGZKRzlRZGQ3\\u000aTk9mU2NRaisvTzBHbnhOZDgySnBXZ1p0SnZHRzBGWkZ6Z29aaXhBcWorLzIrRHJJ\\u000aUjRYeUdQa29aVDJLVGYxU0RNbTR1dEhuRkYyRldtV0hxWVYxSjdwMkwxZ01kYW8z\\u000aeVA5TDFFME8xMWNBSVVNaGIvMWhvSEFIbldBYlF2OEJQUnNVTE9SdUI2dENWTGNj\\u000aenlEY3UrR01nYWU3bUdPWERaTmczM0gyTnNmV1RJMWpCd0JSYUhYaGoxUHhJc0tQ\\u000aOVdnWENNQkxlWHdHV0s0WUpDdmNUTjZoUlIzZWZ6aHd2UzZjM0k5clVDc05HaTBk\\u000aWEdIc0QyRWV5RjdtYm96cm9Zb0tSWDhXL0Ntejh4TnI2eitNS1RwSWZmb3QrZ0NP\\u000aaTN4QkJxQ2pLdmg5eTdLMVQ2MkdEVElqUjdOaXEwUkwxTEU0cVFSbDFmNkNWMGJI\\u000aMzQvMzMraERCWnJmREVmekRSNlpSTGhycmI0c01DU0ZiaUYyaXlqY1QycVJTZkVH\\u000aZENwanlHcVZQZWpWT3VvK0JZUkhoZURqVHZwNHUwV0NBS0cyNHViM0VQWnYwS3Ey\\u000aNHZGOEhQclJIcFBSVkNqdUZHa0dNK3NqWWlkeHh4VnBDa2hsZmxZZnJFUjJSMGtM\\u000aTW9Hamkway9wYnlRdEd1dnk3RDFQZ0V6UEhCUUVHSzZhaTc2U2pWNU9HUUdzMzFz\\u000aYzJKMFlRME14Ky9wNEZtb3hvek02bkxrVkNObUxWMStPSXZHaFV3cEFUd25XZTZP\\u000aUFBHeUVyVFpvalZlZXVqa3Q2ejFzNUtVdEo2YVRpMWZxRlRiY2tmUGpaaGt0K2Ru\\u000aTUdmNHVxdXhza0VDYmJTOEVEUm1DUlM4Z0poM05GQ3VGR0pzWW94OVBvWk5BaHhK\\u000abEYzaDhFNk1UWkxNUFRrWHhHS3B0VndqR3IxTmx0VGRycVNKRVFtSUZTWDQ4cUwx\\u000aeWtudXY3WEV0TWxxUGxVUVBrd1l2THhpeHNqTHJEV1R5UG5MY3RRR3EvVDJ0cFp1\\u000aYjc4cXM3Y0NoSFNMVWV5OEt3ejVxS0ZpS3ZBTjBBOEhvalhzOElZa0F0NDFJdVZm\\u000aYW9oTHVEcER2Nk5wTmtLaUV5ckZyclVuZjY4cFNybHNiTHpSTmgyek9DTitDaXZ0\\u000aOTB5S0JXbjlUeXkrdHhIcy9EL25qMzl3Y3ExWXc2VDhlR0txVDR1OExOUGJ3L05o\\u000aMm1ramxQaE5SR0R1SUZON3MyKzlmYjhlYmJQRG5LL2ozdUtieWRjNEM1QWhDbUFk\\u000aYWpzVXA0Q3dpNTVGTjJreXRZZkZ6TTlyZk95T0VlZ084bzdDOFB6WDVjcENIbHdo\\u000aZmtMWHFwMDBPUktXZ0RQQlZnaVkyT2JFaU1CeUFOZFVOK2k0dVJqUjZJUnBMMXlU\\u000aY1F4Z3JlWmVkK1hWK3BwWEtWb1dVMEowR3o1cE94MDRYY244UUh2Zno3MjdtN1NL\\u000aWDdKaVVwY1dJc1g5UmZjdFlJb1FxSkY1endSN0s0WDJYV252NVBtTk9YLzVGU2Qy\\u000abXcyN240WlFqRjZYdFRUbzZZeTF5d2dzOUpELzdnSmIwTkczMjhQcU5Hd3FFUzBo\\u000aUnBYR2RydHY5S21hbzFjWFNGN2drVHZ5RFRScXRYcHYzeER5bXROSW1pUlNOOXlk\\u000abHV4aFUydG50dXVUVlN1WEUrTkJ1QXovQXdPSU05cnNOL1F6QzZXT2hGWkNjd1lF\\u000aK3pGa0FLVUJLUzBvSG4xbmR5dVQ5d1ZqbnVDL3ZhbWNTVmwwWnhJODlpcTc1Tzd1\\u000aS0V1dGt3Wlhnei9YekdVS01NZmo4Qi9oYW40WlE3MFRidHZDNkszYUpLWXB5RlQ5\\u000aby9OazZkMzQ5MFV4Z3AyclZVQnprV3JucmtZUy8rRkV2VUd1cW51V3BrZzZra2Y2\\u000aWmFtbTVidVk2Rmx3WTJIODVxQkV5a0haWGc4RU5tWVBtc09QOFM1TU10bEZYbXgz\\u000adnJUVUlRY2RtUHV4V1RYNlArSEtvOWZyandLMkxFTmhYUXN0aldZbW5VWW93TUZH\\u000aY3l1NlR2TTdWZDUrb2VOU0tGaldQNGgxbUFMNVYyTHZWU0JSYTYxb29mQ3VPODZI\\u000aWmNQbzRPNEZoVlFXeFkrYzBLT0tFbzVlSjZiemlneTVvclM5WmY3OTlQTXdRbVJy\\u000aZmVjWDF6R3ZYMEZTeE9KdzZEM0FVZ1VhR3dSb3M3d1FlREd3QWdmUGJ3bTJLcFda\\u000aK3pGK204cTJXOHlUbitGR3J5czJ2bXJKczRTZ1YybU4yN28wRFRQV1p0a3h6Y3gx\\u000aU1JoUjM3Z3d1NUdreGVpL3A5NVdTeHNVdEozUUd4Rk91dnQ3T284V09rRjNlN3FK\\u000aSnQ5U2tYSVVpMVNGYzVRblZ6Mno1MmYzVStabzlwdlBVVnN2UlkwelFuSU1xVTFE\\u000aN2FwTEdhWGltMm84MWszQ1gwVmRJQXlaYmlGUHVEcGtZOWdvcE1FcjgrclFIQWRB\\u000aMlRZalpwQlhCV3NyNDg2Z202Um5tc1luVXlRRnFTSkNFcWhCUnhXekhBQk5GdVZS\\u000abEF6ZE5DV1Z2L1RLVXV4WmV2bTVCTWNyL3V4ZmgyTDNpUmh4Zm96cU5HMnh1RXFS\\u000adTFSR1pTRWFkVmUwaUdUVlhWcnQ1WHU5QXMxdXY0QlJGcm1GY0FpbWkxQ1ZqbUJq\\u000ad1pPNTVmeUdrL1haNGgrQklkaXJyK2Vxdm01ZmhZV1JKMmk1YmNUUE9WYTFpeXlm\\u000aZUlaNkppMC8wMk1BTVdlSzB4L0puWW90clJXblA1MGJFOC9XT3hTZ2VMRFNaLy90\\u000ad2pGaUpSTlpEQkdZcCszZGFrZ0R5VHo3Q1hWV1FRTFlGL0NLOGpXRXI4RE9ySUFp\\u000aVjNheFBaNG96YVlqWGVXNHNxQkpkTkdkZ1VzV203bmJnMDRNcCtIL2dDbmQva0py\\u000aOVNmSklaaXdtbnpJR1hXVHV6ZjlTV1ljYU5DK3dzTVBpQURPNjJsUDhoN29xWk5F\\u000ac1dpQmRTTEZ6ak9zdm5rM0Rvak1GeFFxTzlGaHF4ZWtFbmtiS0xoTFQ1d0hhZ1V6\\u000aNE43Vmk5ejNRMFI0VUoxV1pHVGF5dDVkVElYZVppWkpyc0dVc3BiVEFQTElndnM0\\u000aais4aXFwL2pGZWNpclpDRUpuOEo0V3R3UWYxYXROWC8yMlpQWWpZb2lqYXVWTm1l\\u000ac3lTUXRIbzNFYVZmVmljRzUrcHQxYm1ReE5rNlh2ZHUvbVlkVUpMSFZ6VHVpcDVO\\u000aYjdId2VYTFo5WjZwSnZMeEdJSndmR21HZjY5a3Ara2RZODhHN3JvQnN0bk9lMVZU\\u000aUjVuR0lyblhJRDlqcXdQZWF2RlAzV3BjWXRsdzJVQStZdUVVRkJkUkpDRiszdkx0\\u000aQ1pyUm4xNnlYU2tRN1FpSmdHeXV2V0p4QUdZRzYxZGJ4bG41d1ArejlWcUlyMUVr\\u000aY0pXcjZtME9takNJOCswL3lFNXdGbjdEbHlWRWxVRW5ZNzdyOGh6QXFJTUMwSTI5\\u000aNUpnc3BGY2lSaTI1eWRLMzE5c3dLc1dHVFEwZ0xFWlVnNDVxWjAyalBqRWRsM2ZJ\\u000aTm90VGl6TVBVWkdHeTlmK2JpOE9UYld6NlF1K2YxNFk5UkltbWx6N1BmUmltRzVJ\\u000aZ254ZUljRkpxcDBacW9WZ3NpeWtyTVdIaUdDVUMzejZ0d2FnT2lFZlU1bXJ0RGJn\\u000aVkU4NkFROVhWZ3hhZitpRzhYb1JVNmhIVkpNM2dhWk9EVmFYY0tiQkg5L1NaN3p4\\u000aZlI3UjBwVnJyc0U1UHE5cGJ0VUphRmRvK2hpQnpxdGRLdEJrUDdjYkFEVER2eHU4\\u000aYjhkSDdhYVMzUzlxS0dmaHUzMW0xK0hVSjZHYmhTRW9sYnlGcTJySVkyV1p1K3FX\\u000aUHVxU3NtV3NEeVRDSGJ0d2N6RVkvOCtUdEhUa1pFYmpkN0F0RGZ6dmlJRW1aazRh\\u000aRFpCdEdYMTc1NlFIb2hJT21KdGVPTWlqSEtqdk1VNHlYZVh3VkkwcFVwc09JZVhZ\\u000aNStSOWVGQVFFZUJTTG9FOU93ekpOYm1idFJvSHMyQVJWUFlaN0lZMUxOM1oxdnNI\\u000aYVY4czZVbnB6TXZNRjBMdGw1UmEycmxwa0NsOHR0a3p3bDF0T0NVYmRmc0d2UVhu\\u000aZktjVllNN3d3bXFQakFRdWJpK2dEcHZrcnVFZTFxekd1NlA4cFlsY28yN1o3WUFE\\u000aL2dzL0s2ZittSGI0VXlpeXI3cklaampSb2c5UWN4NDR3TXF3RWZvbWQwQXFlbWo0\\u000aQTZ3Q1ZVSjFUN1ZwVmYyc0FSWWVnLzAzbWMvTzZySTZtSTVTQ0tKZ0J2UWhvNEN2\\u000aWVYrNzNNbVg3Z1dNUHRkUExydE9vbk13M1V5aEtxODNuV05nSUFhbDZySlhaV1Bl\\u000aYXVVbjVVdm5jeElNZFMzWjFjRndsRHhVd0ltRytGWnJrTGpqWm1XaDRjdzVGOGNj\\u000aOXhSZk93WW5aaTJJMVRUeExLcTlDOUgrak1sOUxna2hoemtWZDFSZUFkcFpZYUdw\\u000aZnlSUzZsWlBWaDZiNlA3a0lsdlhremplcDhkZUprNm5ycWlQL2ZBdFNTQVNUcTdY\\u000aVVVQUEhnSW0rNTR4UWcrdlQ2MHVHY2ZPaHljN0owd29ia1lYMDJ1Q3p0c2lranRa\\u000aRW03WTEvOWRjekx2c2xodUZ0d1UzTWF5Q0QwakRmRkhKbVJCMmVLWmxRZHZmU1A0\\u000acmJ6SGdwMEpzQUJlNndTMlkzdDd2VTJDdklqM3djTlZRTkZCQnZYbmk5SWNxQVNm\\u000aREVWMGhYc3F4YWtQNFAvRTVDMCtkNVR6eDBIRlF6czk2ajNEcnlHNjl4eTByRzBV\\u000adGZLRDBmK3VMc3NQVERybWNhU1ppVXh0WmJqbGtpR0hDU2R5YVo2RlNSYWhMcXpH\\u000aWVJ3YW9wRENDVHhQNXh6WnZaMGIxWDlveWE5c2JRZWFEVEtJZmdmMnc3RVEyZEZn\\u000aLzdCN25lZUxJSVdWTXZvK1pzMUpsR0RuWWpvVUdRYU9ITWI4ZFlIWUJnbEZ6UjJp\\u000aZUN4SjFhU3haQkFQNGFtalErQWp2RDE0MXk3WWsrVnNMeG9jdHcrbzVCRndHOU5m\\u000aVHJzT3MyQ09IckRoZW43TzYwMFNuNWh6MVNhclJHbzBTQjZBOUxJdnc3OUwxZFJ1\\u000aeUc4aWVjaURhRmVVb0M3OERCTjFGRFJyNEpxYmlHTjdXZ0JLQUpyRmd0L1dZMjNV\\u000aSEJPTFpOSHBGZ2lwNnFmNEtTNENRWFFuL1o1MUx3MXhHQUFRSWc0RUxGbjlDcitz\\u000aME94czZkWXZmeVhMWVhiOXkwa3ZyTnZXZDVZUkFWWHZENkFpVTRtOUJZNmZEWFNa\\u000aWm9ma0w5em1BU3Q4anpVZnRPWU94OWVqNzRJeDRQdmRyYmdVV2MyV3hvOWc0U092\\u000aTy9jVlFjd1RPYmFxNkFuVjZIVkl4dGtpakRkeG96dDhYTEJCdVBncFlZWnRWcHJ4\\u000aTGlVb3g3ZGpDRml3cVVYZEo4Mzg1a1gvcXdVNXlYZWwyMnM2c1BHSU95RlI4REw1\\u000ac2ZacW1Qei95bDA1RGJMaTBoTjlBaU9jQStVQ1ExT1ByVllNZ3ZqUjl3ODIwemZh\\u000aTStmOTgvNC9FNW5mVWoxdXlwU3RpbC9tWTJqeWZxd2hnaUpjcFdhWWNZenFQYkY5\\u000aMDVsUkJpa0hNQTBzSGxyeVJpUVdBc1Baa0lxclN1SHg2aGpHSDNGeGpTSnYxZzhp\\u000aVHllL1V4MDBucGVYV1c2ZFg5cGJHYWlOcmZDeGZlOHQzWDcvc3dPTUJyR0VEdEhr\\u000aZWhoWWNybm16U01yZVY4dTV5dDVFL3dmUzJKejNTeGVoTmp5cHhEQUNFSDk4dTFJ\\u000aUUg2d0ZaanlHYVhSQWNqTnVqTTNPbk12NHFKSThzVTdHcE02VHZFcXdrSG0zUjF5\\u000aY3ZhSTRDd0l3d3FzUFlFdUQ4dkIrNks0WGIzQXJzTnd3Qm45ZjZqZzYzZlFvbERL\\u000aZG1zbEJiUGhkdXY3QzJYM21qVnJBUnl4bWdKZGhKckNmbG1hU05rTTIzTWxCZzRQ\\u000aSVR2ZTNhSGFxVnVFVy9jUHVPMTR3alBGdzNDa2RzSWtuancvWTNkOWJiQzl0UHVC\\u000abG0zcXRMQWhSWVJtT1dvWE9malFCUG93WldlMm1RQnJ1TFV1VzhhRG5WU0NTVUNw\\u000ab2lWWnVNYXhuVWpscTAzZ3V1OUcrOVRPZU8xMnJFQkY4cDhtWVA1STU3aWF2enVP\\u000aUjZQa3BWSU5ERVRrQWxqNjZOMDA3T1Zid0IzUk80bDJYTHV5emQxWDI2b1VFUTVl\\u000aamp4LzY1RUdZd0E5ajZpMFE0YTZkZzkxbDBMTndiaGhVbk4wM3dvM3BTRmoraU9F\\u000acUpMc2RUY3pkalllazFlMFlDYU1wVW9ITDlzVkFlcStld1A3VU9wdisxTlF1SnM3\\u000aTWQzUVJnNW9RSzN1NzhYdXNzaGpTZHFpd3RkQTcvVm5SQzN3Mk01bWJLd0VlVGNT\\u000abjl3Ri9GZXBGcTkwQ29wL0hGc1hxeXNVRU51NWtTY3E5dHpESmhnOGJpSmJkVXN4\\u000acU54NFRYWmExZnA2ZU52ZGFzdjVsOUo1bnBmWDZvbjA2MG9CelZvMk9JNXhRMTBH\\u000ac0J0MW5YNWIrQ2UySjk0ekVObXQrYnFLZ0VoNUlzWlZ0YTlhNnYzcWhtYmQvNGJK\\u000admdhTzVmNmd1Y1BRL3JxcjFVbGtDa2dQdnZyWm1zWWVyUDlzeWE2YWhBbDJHaGo0\\u000aekh6eTBDSytEdkxBU0s4MEhCN0tWZFc0dUpxRDYycGlLYkxKVUU5aUhoVTRRVVpu\\u000aeG14eGtNZmJnQS9pdVR0NG9vdy9LOWtIcDkrUWJVazlFUGc5Rno0TVE3bDNiTUxo\\u000aZzdVMjR1N1hTdlR4TUxuMis4ODB6TDNudUJhRUhkYTRic2VDYzBwaDdOS2s5YUFl\\u000aTWF0cWZycjNTSVpycklDZHVETkNhMmRVZXl1d0x1Lzd1Zi92Wm1oVEpaV3c2MjlG\\u000ad2thdjdhaGJRYU1NZ042NXBhL29BR2IwMXJrc1NYZ1hkRjdhc3JVR3YzSGM5ajhu\\u000aSXh1NThqWHh6TGM1d2l1WmIxRFB0OE9mSmdXYTBGeVJKajZBSEY1SEdicWFGTTlV\\u000aRU15SXU5Q3I4c3BGNHJURTVBNjRrb3hqZTNtWGZIVVNVanBUemtLMlllMkpLaFk2\\u000aY0dYc0t2aE4xbHlBblNQTEZ4Tm9sc2k2cHJDWTFaeUdQdVl2bm8ybDdQbFRGblAx\\u000aM1orMCtRMGxCdG02eHZCQm4rUGl5bWxtOWV2TUpoeHNOeGlaN2NZMzNPQnl3NGJ4\\u000aRlQvN2RmUngyUWxxT09BTHI2a1c2ZXI2WUVuQ21CNWdGWDVsSEZML3UzQTRPUFAz\\u000aZ3k2aUdjQ1pPVnJrOTdUQ0NZZDJ6UTVkZVFKSWlKeFFQQnlGbVlQTzg5eU40QlVI\\u000aOWtRVFNDZUdvbVYveWNIYVpkSGwyQ2JIVFd2aGdCcWFiTWJYSnhWRVdac1MrLzJN\\u000aaGttZE5aSThaV0VnYm5odFlXVHUybjhtOGZBREYwMll4UjFjTG9Fa25FN3p0TkpZ\\u000aZE1MZWUyOEMxRk5kbDNtUzVyRlYvclhXVUdtQXAzZ09Lb1NXUmJMRDNlSi9ybE9U\\u000aL1NwVGJFUDVJNGdsQ3AwOHYxOXBMK2krTDlpSkVhWmp3dHd2M1BXRElBekkrWWlr\\u000aZGJnR01uYitYeWwyUDk0R2c0cVk1RTRQN2ZTcFllaVZiVEJleUpRMG9JUzhuUDlI\\u000aUHpwV2NSRjNFOGkyVmhCSU1aYjdSNWtJSVdxa0lMbXJwNnBrejA2NUNKQlNDay9U\\u000aYkYzaVhadU1kcE9udFhMYk5Wc3VGdVJud2FYZkpwVE5LT3U2K2VTcC9rSDE1cFda\\u000adjVJMlFSN0FGaElXSHFCYXo4Z3k0QzdVcS9uVWVqN2ZHM0V2c2ozTVJ4YlNTUjhG\\u000aSnFGZDB4MSt4SzgxTnM4QmlqYUVPV2xBRDFvMU05WEFGTXFWM3pVNEVuQjIwaUl3\\u000aYW5DclBGemJidWNUcVU4RHMzb2k3Yy83emU5Z3ByRHFtK2hKcXRTYXEyNkIxeXZp\\u000acXl6VTd4UVZEczU5VCt0VGkvdDFwalZkclJIVWNWZVZSQ3h6NFl1N1k5TFVaWDA3\\u000aM2o4eXk1MktLZXk3dk95VzBkNWxKVHpkWEpmZkhlQlNhQ2ltMnVwZWZaeTZKeTla\\u000aZWkydDBOMENIUUtzRnkyQk90bTl0MnNUUXFQREJFR0dDdGVRTFB1Y1BOL1doZS93\\u000aZC9Ma0cyNXFOTit2MTJybUNWTE9CM1JiRFpOYnB2Yldxcks5azR0UFF4MkM3M0d4\\u000aeXNIMjNzNWhJOEtvWVVJSEgrQnUvMWF6SDVZTjVhanVXcTNKV1hZVHk1S1crOE4y\\u000aamdvNk9qTENIVzBzUzU5TXcrQU1MajFCaWl2WG5Uc0xTeHBTSVByb21Dei80c2Ri\\u000aM0N3a296akZSOUxLRUJTS0NNK3RxMXA4ZUtTZ3NqUzVuaCtwU2NNRkpxWjdhekRB\\u000aeEhXYVoyNTQ1bWpEdVJOV0Z2M1lsTEhXczZBM24xSExCdnVOUWs1ek05RnYzT2tm\\u000aTzBqOVlVUWFnWjdCMTlUVjVCNDhwQnAxNGdYNS9TR1VmOTZOaWQwWmdURVhQRU8x\\u000aM1JnRU45cWVsazRPQk1icXJQNlZ0d1FPT3BjNXVEWHgzcEdWQkhTejZrb2JRNDV5\\u000aU2l5SUI2L3BiUGlsbjlDdmhNSWVyNWp2YlZneEtCdkFyajB4RFRWWVpGcVVYZVhz\\u000abHRlSE5WN0czd0E2dG9DWU1ZZ3R5UHRtWjd6MDMxZGVEemtwQnBBV21HOW85OVEw\\u000aSC8yV0EwaXNQdVVhbU8zbjFFUG9BRFZQZHF6UFpUOThPeDRjS3kyQmdBWmJBZVgr\\u000aR3lRTzgyblhudE1hWmUwbVV3cnFPbE13clZZNGhlaXY0aFEwOG1VekdkVXRSY0lL\\u000aTGpITm1OcXZvdTdlY2ZHdVhTcnhvMXVJdkdIbzNuVlVZTWc2ZEFRRlpnWUh2ejdZ\\u000aREFKWTBEWGYzTHVFZTR6bVh1azhlNm4vVU5BbE1ZQUlvdEsxY2Z2TDV0bnQ0akVD\\u000aRFFjb3lZaDRjUlVFei9XUXdudEE4Wm5sQUxRMlJOUDY0NXhjU0JOMEVCYUkyb2tB\\u000aNXI5TEYzK1h2UjdxQTB4b3VoNEMrNWZRTnpHdTdwTjFUck9WblYvQXBsMlNaMmtD\\u000aTEJQN0hjWWt2b3ZBYWFick8zeGtrUmtsdFRCd01rR3RmRC9NTm13WW14NTN3U0RL\\u000aUjE3NG1uckRCRDdOb2d0S3NTNG03Yk5iZUZyTE1hdDYwYmZVWWsweFp0YWxuSDdP\\u000aU0xqcURHdmhYQlBDaVFLNzNNVXppdU1qWFZXMTVUWWJDempuMHV0Q3d4Szk4TVlv\\u000aY1lNV0o1UGQ3WG0zejRva2prNDVFTU9DZVRGRmdZclpVNzlWYmdERVFpbUd4a0Ni\\u000aOGR4ejRMZkh4N1NGUXVhSEpNSjh4SUxZTWFSL3doQ2F4ODUydlNRaElJWG0zZ05n\\u000aWHNyeTZ3M3EzLzQ1WDd4OHVPd0p1T29GUGd1NEtNVDBTUkUwSmZRaFhQUDdpTXVJ\\u000aYnRrd0ZXeWxGQno1SmhVMzhzZ2JGdjlaVnczQzcvbnFZVUVDMXZRWHRnbEs4bGJj\\u000aazlUMzU5YVFpclBkcHF3NjA5OFFGVktyNmliTlMySk0wTHFlM21neTBYQ1RTYXUx\\u000aVE4xeXN2SHBpdU1jSW5BZWFyL3d5b1lsek5BZU1kbUQxUTduaWNBK0pWTWM4elJn\\u000aZ1NKcnRoZDZ0emd4NTFFTUNoQUpFaGR6UkpjRG03Z2c5eE9TTzNPTGpRdW05K29k\\u000adjY0b3NZNVNtbDJHSkgzZ0pzRmdyc2d0TXpTMCt1dnYwdGlZY1BoY0VsL040Vlh6\\u000aV1FTNjByZERQMTlUMFFYREMxc1luSS9rZFREcG40WnNyNFZOUzRkM0cwaEQ2Rnh3\\u000aZzlVdXBzN3k0MjRzcmlOWDgzZS9CWFhZTzNBWlZCS3czUlBVWnl1RFRZY0V4cnFM\\u000ad1RPWnJNQUJrVTBuNnBpYVRqMWZhRDJpZUZxcEFycGxIZzdrTW5ZdVN2MVFDekl3\\u000aL21GR0VEWVFqSWFiWXNRelZMRzd4YjJxbkkvTWdTbUdGUFN1VkhKNDBMNzRPYTh5\\u000aSklyeUxvV29ZSDZYZGo2WkdqZXlpT25YcEJFOUgwT2RlMUJJMkJTTjVwWFFZc0hH\\u000abFUzQ1preHdHdUZ5WnVzamVDRW9kZURPQ2lveUJha2kwSzB0cE4wTWZYS0Zubjd0\\u000aVitWb2FXV0dQSEtBa2c0eGJIcjJnYWltWW43UlN5cVcvcUVkdzFVTEgrR1RMQVds\\u000aS0F0eG1LR0ZnNkhtNzFtY2kzNXBGTW1QakROeER0RktZWm40Y3RMZURIR2ZVSEI3\\u000aZlBEOHRjZ0c0VmxTSktwTWVYR2RRT21qMkJubFQrTFYvN2JLbFQ3aSsxTWk2QnVZ\\u000aUmNBbW1GZnU3ZGF2Z2IyVFRvMVM4aTNPdkNieTgyMW16OXNjZllyVjd1bWhYWTJU\\u000aU2ZIQllyeXFtTzlHOXBuSGpTejlsTko0aEdpdU1hR3hNSWhOYUE1Q0trNTd5OEE2\\u000aSW9hWjFWL01BRmJyNXB6RXNlckx4VzdLbld3cjB5WGE2U2hCSDVwSGFXR3hRRlBS\\u000aNEs2bEJKZXpjUlM1ZUcwdjV1SHBQWTYrR2J3dFBUNHBDcENIdHBKNk56dlNVNlFP\\u000aNGVHYUY4b1NEV3pPRXRJVEJCdlBuUWFxa010L2V3Vi9qZldMNVhJbll1aHV2RGtu\\u000aNnZhbTRzenBONWs2WFRYVjh1QXNWY3VaQ3dLRXBKZldSQ0V4dGZqZVIzZ2E4U28x\\u000aeWg4Qm1QSFNBd2FxOUVHc3pBcmdScm40QllKZ1B3VWZ2WkY2c0pIV0pKSm54YUdI\\u000adUNBK1dHejBrcFRpVlJLYVM0SkUvODBHOUxKZjcvTTlvWEVULzFTbWRUaWEzM3lY\\u000abFVSb0xGdVE2OWZuTzhDUzVNM0IxM01HTHN4Wll4aUdTUkpYYkxHVWQ2bnNsQzJ0\\u000aNlh5SUZNdVFtSFcvQVJSNXVNL0o0VStWSUdUZlFPTlowVnZoQStuNlUxNDRtR3Jk\\u000aU251dWROWEpXRk83N0JzZWp2dHMvRWJXNHFOcHE1NWNQQmY0MzFEQ0NoMVJNdTJ3\\u000aNnZUZUJRNitJcllOMGo3aTllcng1UFEvYXN1NkRvMnNRWFZhNTZHVXFNUmJKVUNs\\u000aaFBNM0F0SDFmZ3VucnAvODU3a290UEhkUURBM05hOURNT2lvTEpSM3puN0tiSWlU\\u000aNEo3THFtbUpET05WcW10LzdpeGwwTVlDTDh3azFHOXlnWUhxR0ZsWGoxUXpxTlVS\\u000acHhUU0pualYyTjZOejZmYy9MVW9NR1E5OE5yb1Q5YjhhclNBcVN1TmhCaGwvbEto\\u000aNDJ4QXp0UVdDNkZEY3Nmd2FrUUpGeGs4OEdWWk9hMHJ3UFNEM29LcUMxc05sc2VW\\u000adzVzMWRjK2dodzJKTGRmeUcwWk1yZ3NaQm5uV3RHanhEdFg1WmUxZ0VKbUo3cnN3\\u000aTGsvWW80S1VuWkZ2REF5d2t5VllMY2hwMVJ2ejJKeTNGcHVpWU5sRXRkMHZKRjlX\\u000aR2dkeUd2L1JpN1pEd2tybzYxS3lMallvMVhaelBmUTlscEVqMGRTKzBCZllZUjcv\\u000ac0crcW1qZEZFb2YybmJLRWVaU1N0K010UTdnR1ZGUy9ENmtvWmZNSlM3c0svSTBh\\u000aekVrdkxRR0hTWDN0QW13YXB6K284VDlEYUZxTDFDYjZSNXluUUNucjZ2Vk1QMG1F\\u000aRm5GbURxWVMzY2c4cldyeEdrQmFUcTFDTDZKblhzb0x4dHMxV2N3QmVmR3NyM2Yy\\u000adEZMcXN2TjFHOG9nYm1pN0JDSWthcFdEK3FzRUI2UmtNeStGRVQxaEhuMEZyNEk4\\u000ad2l2YnE0cVpsd0NncHZ4Ui9tYU9iRTZiTjBjK093a1dxcEpRTUl5aDZJcXZsTUtP\\u000aR1d5YmR2aWEzemJMNk5XY05IUnk5aWl0bERzdjJSNy9QMXNqR1I1ZmI1NGRkbXhO\\u000aMmlFVzZLdEFZRU5Bb2VwSUtrWkVDNUJ3QUNYajZrM1Y5dXBNYzcrZnlOSEFBbmZr\\u000aaTZ5amRVa1BZMzVsbmNhcTJRcDd6Q3BWdk1qbTlTK1dtWHV2ZlNwc3EwZlVxWlN3\\u000aNmluZnpncjhlNy9zZDhIc1hVL1BmSDY3S0ZzWElOQlpMVm41QXF5b01YTVVNY3dV\\u000aVCs3RjhnSGl3NUpRcnhELzhvcVhUL3dvLzIxcFJObXF2ZDQreG5hcGtDZnBpOUlv\\u000adFNjd054ZlpmelkrdDZyRmJyU3VWMXZQVHJaSWNrT2ZXNmt5MHp2UmRCL2hna2Ur\\u000aNVBvVGRnd0diSnp0Ylo5R1pYSGpGZFVLWFFKVWxscmJWRGhUTkNoakhxNGE2QzhH\\u000aWWRMV1hxNzZxWlEwWnhvRjJxdUtkM3NjazEvaUxIY3owMEVuRGExK3BXd2VTMVhU\\u000adUZaR1lFTXNGeUptWSt5QmdRK3Z4aHQ2bFArKzZzSW9pbUF4cUMweWU1SC9McHFM\\u000aaFBTQlVpZHppcnlTblZ2SjZmcjI3TVRQUTBoci9JYUFXRlZnUG1yNEdqd3gxdWh0\\u000ad1J4aVU3K0lwUUxNSVVZYU1nVldnaTZvbU5aM25mcHZyYUdwWWxvaE84Z3ZXK0lL\\u000aWFJNWEJBR0Y4TlQ5UG1ZazNXa3NPVU8rVS9XKzlOL1d2algzc2haZWpGd21GYVg1\\u000aWVhyREE1MS9icDRvQWlIMzd2TmZqTGxzd1piZ2o4NVFsbXBydlhuY1dnS1RZN1pP\\u000aSmMxcmhmQnA5ZUhuUm1nQkVyNHZXOGROdkxibVFSa1dhTmxrTFBSeGd5NHU3d1p3\\u000aN1dmZnYvOG5uWEhsbWoxNDVWQ0NxOHlJR2FiM2tqQ1dvQnFQbnh0Vko5VVFNME9D\\u000aSVFhay9mWjJvdDV6Vk92dGhJeE1pK0MzNVAwRjVkUi80RVBaS3g4a1AyVnZ6RkZy\\u000aN3hFUlBSZFJnbjRqWDlFREVZQTJoWVlwRWRLRUdGai9aZTlKRlJrNmxQZjlVY05Y\\u000aRkgxd0srMW5HZi83WnZzd3dSYnNzalZjRXlMODVQU2F5eVl1ZXQrMUZ5UFpKRk9J\\u000aRnVSRm9vMWhaYUp1cGlTdm5yL1VSSXlGWEhMQ1B2Sld5MnZQVzBibVphR1NRVEJZ\\u000aYlRMcVl0UzBvdTJxOHVBd01vZUYyT25FVDdaTENjMVhTV3lFWWErWFJ0MkduMHBl\\u000aUEkxUW91NGduby8yRGlrN3NxTERydnFRbVpTOFNISlFSQVJaSnh1UUJBWDUrNzgy\\u000aYU9uaWN1aUtTbmwyeHFkM2pYRTRuUS82S2phbmhlVXpzdVRrWHFQcG4xbWlPQi9H\\u000aTFNUQ3VaWHRXcjdlSFpFb3RhZ0pOQm9OSlBYdG5KSElQb1VTdHpGTG9HM01Vc3dY\\u000aeFlCMG0xc2FjaTdaRlJ5cU1sMGtvKytlN1VCSEZOMi9UNS9ybXdsbEhaZ3A3Mm8r\\u000aWjZzWERyVXdxMW8zSVVocnRYNkJPYzJKOWladTVaenVRNkxNNkRhY0Z4bEdtcXRh\\u000aeDB3SlQyZkxpblRRU1ZIeDZDeWRMU3dTcDREOHlPd00zUEc5Zks5VklSRm05S2VY\\u000aaEd3dWxyMXBHVTAwTDU4QUVBb2ZxRmt6eEZneE0vRlRBTVZ1NWxCd29QNDYycSt6\\u000aM3pHQXkyemFTcndJKzdiWnd2OHVTMnpKOEtPajU4MHpKb2JOdU9YdC8vVHlMOGFV\\u000aZ1BtVFB2aTV3eDJGMHRVUGlzL0tUemZoZkR1NTExQXJOS2szZXIva1BrUTVmL1BC\\u000aTVBBSEpPQ3crLzh6NEVDdE9tL3g0UkliR3VIbDExNzdhQkh2WDc1TzloYnBaSkhV\\u000ac1ZlWGJOa3VUQjU2YWVoVkl3T3hHQitDeTR5eGZDb1JJRENXdy9oa1FVNjlZUUhL\\u000aQ1dhUXYydE16eVRkOXFsMFlRc3VBR0h3TDJTWTVKeDJ3RjZ6elMwRUVCMGtCU281\\u000aNlhYZmVwRGZnclVleUlzV2Rwc2hrQUQ2T1NsVDVaQTFHMWtpZHMzRUZiSFlxbmJh\\u000aVzFTZUtoc05QamVBcWErWE4zNnFYQ0NVclIrNlJDK01xTVc5a29XWjFqSzZqMkNq\\u000abHNWVjhkVGI5OXY4alVuSEgrbCtrbituaWo1MllRRzk3eCsrQkVMZ0FZVWQ5Ykxi\\u000aMmI3OWYwSnJYc2s4V1psajZ4Q0l4VXI5ZnZ0c05aa3NEWTI2NXl1VGtoNzE3Smho\\u000aaXFaUHowVi9HcGdVaHJDSmdhbVR1WEo1SmdMdEtJZ1Y4WFVQWXd5QWFUdGpvcGJT\\u000aSmx0MDVJVGtka25LVEZidjNxd28xNWllS1ZBUHhvNVVoZEN6a0xUZ1hyWStjMldo\\u000aOGd1R0JPbFlSVGVRbUlHK1Qram0zRGpyMHVLSEx1U2lmQ3JlMXdyaHp6dUF6MTd4\\u000aaXVkbFczR1I2UGVmbDZOdUt5WG1VU25LL1F6MXJNZVVjT2p1UzBmTkdlWVQ5bHNz\\u000adGt0Mm5TVVdKZnBaQzhZRGlPWDd2TUZSUFZOSXo2Vk9lbHJDS0hHMXlTc3Vkc2JP\\u000aVTRiMEg2KzVPVWphYlJuOSt2YnQ4T1BNbE9BVDBEcDJ1TnMxNlBSYjJPMGp6NWlo\\u000aL3FwYjVZMENnK0VlYWFPMGdxdXN0WGdDUHJPbktYM3JLcU4wUG5lMXpmYkZqVklJ\\u000abWk4NjcvRGUyYmt0RThtdTQrWTJIeUg1K3JUVnBkMlRxWExaOUhEaUFMaWZ5NjJL\\u000aWFVjQ3NEanJEMGhyWTdYZzdTNnVjSW00ejNqSDV0amtOczZxMEFqMnhscG5zbi9D\\u000aejVmd2FPUS93ZEpPSjB5aTVtanRjOFBRdnJ6UFhNQ0tIZU9hUGJmVHZ1SmFwOC9Z\\u000aVmpTNkw2NjNxNVVkaFlGcTJlblp5ek1LYUwvU0RmYVhyZzZrREw4d1podXZuRlJx\\u000aYmthVmp5S0FQYlFFUGhvdmJCYW5DajVwUGh1MHJoeFh4T05rbkhmaDhneGxudWlx\\u000aKzdzTmxoeXBSUXk2N3NNSVluMmdnS3dRL0ZCVlZ4SXBRNG5oMUw0ZldOS29MY0tX\\u000aZFBCSktHUUQxNCtPUXRXcVEydDRKYS9KVlpxZVlQRFJxSUtPNStEeUdLemRPK2Q4\\u000adTJhNUZkaUo5UG9SUmJqekszbnhYa1A1TTgvYytCWkdMK1lURmtVOGREZW83L3I1\\u000aeDVVOWk2TEhpT1FhMDZMWlpGQWttSEdMbjhtNVRPbllWbGhzdUVlZUdWU1hscVVh\\u000aV1dhSFppc3FrWVl6am1Cako5T3JsUU55aEhRR3Q1cXFNM0FTandMQitoQ3dwaXZH\\u000aRXZ0aStHdy9IbDZiQlpFa3FoaDlCUlh0TU0zT2d4Rm9kd25nTmpHSUpDak1xZGhk\\u000aTkFjNWpBQWlsUlJ5dWRQdFFsQ2tObHpCV3gyZjhCMDBDVmZQNkwvd1J6WFRFOEhR\\u000aK2JiL0F6SkhCYnM0YjR4M2o1ZnpOS1doOFJZc0x2VklmVkdBUjJEcjlJTUp5NkpP\\u000aTzIzdlRmbWVPcFBudmpvdlhkbTI3WlcrdzdGSElrdU1peENqckh3NTgvQjkvWUx4\\u000aVGRoSzlFY1dOcXMvclA0TEYvMEJVSS8xdVdsa05pdTBJNjk5UHRkWTdzQThNVUdO\\u000aT3VhTTYveGNZN25DMGRjVXRCcjBXSmoyZmRtYmlTM0Nld0VrT2c2L2tQQkNHVHVi\\u000adVNSdUVLYUNWNXRFZktlZEtERStIaTFuK3g0U3h6U09KanhYZUJTb2hEWTdlNVVu\\u000aN2ZRcHdvVEdiTUVHUjZJc0pOaUNzR0dSbkR6ajd0aDFSOE94ckVLRWx1dXQ0Ym9u\\u000aOEo5ejlxWGRVSUtlQ09va0dQNStrWW5BbHBrNWVQNzltM1gwS2dSUW9kSGN1N1pP\\u000aeTRBdm9GTXpYd0pFVDdzYnNaQVB4Z21VeXZFbDVRdzNBQzhBaXRybmFBWm40Sml6\\u000aZTdKSEtFdXpHczlBa0IyVG9hWXcwRE5zbWdzSncwWElTSzFsSzBUWjVDUTlPQ1VN\\u000aeHFZYWNPRTEwa3VTVUtQTUpoTHo5UHhrRDhnbE0vZEV2OWFLc2VqczFXMkF1VytU\\u000adldzM0crZ0cwRkNHajljeEJBa3VRSDZNb0tOMG96VWExUTBxcU9JRjRiRFZJZFFI\\u000aTHE1ODRvbTluU1IvV0ZIRHY1dWxSeTZteWpIMU0xUFB6azJ6K1drQW84TFhRaXpM\\u000aWjZmblFpTEZ6OFVzZGQvTzVIM2xCcUFUZUpvRzRVdTRCMjVuRjhOK2JabEdoM2d6\\u000aK2xTZG16YVlUR0oxWFZPNTdNR0hla0dyZjJRZndoeU1zZFlsZFpQZXBNQnB5YU5R\\u000aOXpvR3ZNQ0ZnYlR4c0JFRmN4aWM5TmdZUWNDVk5xcTBnS1F6SmtxUHZtV2o3WnpP\\u000aMWZJS3Rnb1FmZ1k4a2JSSFRPMGJIRXlsNm5EcldRR2RXbkQ4d2ErNGNLSnU2bkpH\\u000aWng2QWVGdXI5QzJsZzBWdWZGNGlqVGVrcWlEb3U2Y2x3czkzRHdWa2VPNmxsQzJm\\u000acUpUcm1zQy9DTC9oYzZuckZ0RERsV3Buc0Jkc29ydEtxN2lVTGF1ekRIRnA5MVI3\\u000aaTdCanBuMTNWcXlZMjVUVXlSWUovYlN0NWVGR0FINnpQZHE5RkhqTWhyeGZpTURC\\u000aK3NTRUxqd2FJR2ZxWDBQSG82UmZ1Ky9tOWlpRWwzRWxrSWJpYVMycmdFWHkxZFgr\\u000admdBZkYzOWQzWEFTdmI5aElrNXg0OGltcHRtaDBPaHgwWENOMThtNnpvQndKajNw\\u000acmNnK2ZNWHE0UzZMdlJjQTdtV0MwRzcrdVdXdi9GblkxYUg0a3NPcHRmeWkydU16\\u000aS3kwQTJFbWNad3YyZktYdmljcnQ0Ry9yWU1ZZnlic2loQS8rcXhReTlERmlEek9n\\u000aZXZzZTZ2NnFTUE5TY1lYLzlYRUxKMzh2dmpMTTNjZHlQNEJOMVF3UENtRmFrVm1K\\u000aRTNKRzU0RXhycHRUdGdKTERaNW5FYTY4Mjc4dnRJL3JVR3k2OFFuNTJyMHVXc0ZX\\u000abk5obFRPR2RxYzZzdjdNTGdTYkQ3RUVmNWNiVHNKV3JQZ1ZHbUQ1Q2o5Y3ZmRjlR\\u000aakMvM1RiSXFWVE5QSkhhbXpnbUJsSFJZSGJQN1p0a3ZUZDBnTkF2SXllZGY1MkdY\\u000aUzhESkQwTStrSS8xNmF4dm0zSlB4RC9BVHE1Ri9xdmtIWFRUVStCSEtUTWk2dnk1\\u000aMkNEUmh0YkQ1dVNNa1YyQmROK0c5Y0xnL3hTeTc3TjBnTEc4WDZ6ODM1cllYbE0r\\u000aaGloeGx2UWtiSHR0eE9EN3VBYnpFcExEaC95NFFtZVRSK1FaQU9QeUc3azhGdENG\\u000aam5TM0lLWkFTVldFTVVFODlGTG1hdFhMNERvaHlXWnViSDJPVXlGUHp5ZnNvNWNF\\u000aNEpLVnBIb21NVWZWcjk5bUZnVk1ESUdyUEdFcFRmU2NqZ01wRmlDaEFxU1djUWFH\\u000aU2cwdlBrRkdlWXFIek15SENqMndxc3VDV3BIZWlyU25ncHNXa1RLMjFLRG42TDVx\\u000aaENpRk5wM3JWNUJFMkwwcEhqQnZEVmFrZXdqcnF0a1puZ3FKcHhZalhyV0dxUjVP\\u000aV3IraWhxZ0VJZ011WGhkdUxqR2wrWVZkU1d5ZTlER05OS29DN2FlUGhJMTJQRmg3\\u000aSlJoZjdIYWVlQUNPaGZaTndDWitXMndRb3hCZHpwYzltVCtDVlpxOUo2NkNyTlFI\\u000adTBtaStlaVRTdXNEVHR2b3RmQi9IQ20wMXVaZmgxbE1JQWdMNXozSTFHRVcvREpX\\u000aMk8wdWZBKzVPV2pnWFlzOG9aUlRCMnhYOWhmSW81eDREVXNiTFM1ZzgvbFBUVndF\\u000aamYxQlg2dU9vaTVvV2lJWVJqQmpmSWdVTEVURnhMTGtBUnJQTzJETzU1ekJnMi9Q\\u000adE9mdG00SzFjeWI3V0h2QkdrcmRYanlQUXlYYzRJVXU0SzR0aTlPSlE1eVRmWUN0\\u000aY2o1OWMya05BNHlOWmdwd3kxVnAvSytGdHVlZ0xsd2l4ZTRwakR5ekNJSnBnU0ZD\\u000acmtxREV1K0hqOFZWNXMweFFXc1d5ZWdOUUpldVBheWVSY0RGMzBoMWc2WmZGQjNa\\u000adE9RWWpFQnFyVWVZNkJndk5OWU42TWFrUndnRDBja2NDbEoyMUhZNGpvU2twcE9Z\\u000aZ3NUeTNrR1laNHFUelJNY0lsQ0REaXQ4ZENHZm9Cb3JKQ2t5NTUvNDFiV3FtbTdt\\u000aTElRVzJBTG9kdktQbVVXeFhibzN5WGNnSTRKdnFjZlAzRVVXTytjV3VIZEFSN2VF\\u000aOTc3MytSVUV2TXROdnMzWWxqeERrTmFNNzZ0VjhqanhRcFJZNEc0RWRSaUs0MTN3\\u000aWUkyWTE3UWE2ZEs4K2FhaHRad0JtVWpBSVkvREdZa2VOY2wzWjdxaWpJMTMvUnpn\\u000aNXlWcjl4VUsvSUFGUVlhNDlXQ1RRYTlzVWYzeEgzZUYvTW9HN0ZmMTdrOC8xMURx\\u000aTE5YQzUvSGhOeDJ2S09CTmx1RXJodURjYjNMZmJ5TGlRVllEMkhYeGRyTkc5M1E0\\u000aNGJPajRWb0xZV0hndTI5UG9sL0htRHhUSDFwdHBQVmM5K0U0R2RwN21yVmF1bHU1\\u000acXhDOWliRzlKV3ljUUdkMUJuMG9RMjluSGlMcGd4K25HOFlkZHdPVWRkRzRndkpq\\u000aS21iUTl5aTAwYXdUamhOUE9GZXEvejVuVFJHQ3liSDZsWW9MVGtueE9UQiszMkpy\\u000aQ2pBbDVMRG90amtDZWtBUllwbVVxOWhSY2I3c3l0ME1RY1BBZUg0VlBHNmhFMUpN\\u000aYkxpTXdUWVdKNWtTM3F1elp1SkZQSUl4SFp3UmtJUzFjTnBjL0FtSUpwZm04RCtL\\u000aYUEvVmdoRkJpdnZzZnlUNndoNVRybENBcE9DcHNOTlNWbWRLRHF5QVBFTENuaURj\\u000adTRwcmpZRU5JU2tKdExUTVdBSzVCWWdRZ1ZQOVcrekJyMjNuSGlZVnhLWWhjdm9M\\u000aYTh6dUdLYlJtY2xpL3o0cXpmWnk5RGlJNmoxdWFUT1FMQzEvMzIwT2xBRGtSOVUy\\u000aT3hYZFVuSTFaSzFyY0hRZnllS3BsbUFsRTJDM3MzYkFkR3V5bXRKTDQ2M1dqZm9P\\u000aUkhHWWpvZnZNQTI0cHhnY3hFRnU5YVRFamdFVVBNeHBzN2Y4TVMyaVJvL3dxU3pX\\u000aZ0lwN1EvZHVYY1FQb0dSS2JrR0FySnNJVGdVT3BSQ3hxTFlXbk5UUy8xbmxCeXk3\\u000aQVBjcGRaRmk1WjRqM1IvbGJ0T2Era1ZiYmo4ZC8wazMwTnlDVjJGRVZGV2tPbG9z\\u000aNTFQNUNOUiswNUh6QkhQM3V3N3VyODRZYkRGdHd2UjhNM29UMXNtbXljYUsxMkpE\\u000aZGNBOUQ2YWErY2k5Wmh0UWNhbUw0Z1pjZmVpZllHNEt6NWsyT3lpMlpUNkZKOUV4\\u000aMHQ1T1d5MjZUSjllQmlCcGRaV25XZDB3bzZOMU5ST0xLdFY5L052d3R1WlZSRkxS\\u000aRUg1WGNLMnRMcTFWczFaVkg4MXM4R29UOUQ4VkFEaGFwVDBCU0xsR3A4TkNZdUdK\\u000aeXI1YVVwODdPZEl4RCt3S244NTRteVlKaXlVZnIwWmtGNGhoOEtkTXcvemg3RVQv\\u000aYkxIWlVxUXozdUV3QkcvODRuR1E9PTwveGVuYzpDaXBoZXJWYWx1ZT48L3hlbmM6\\u000aQ2lwaGVyRGF0YT48L3hlbmM6RW5jcnlwdGVkRGF0YT48eGVuYzpFbmNyeXB0ZWRL\\u000aZXkgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMj\\u000aIiBJZD0iX2E3NDBjZjA5MTViZDE1MmRiNzRkMDNjZDQ1NzUyMTM3Ij48eGVuYzpF\\u000abmNyeXB0aW9uTWV0aG9kIEFsZ29yaXRobT0iaHR0cDovL3d3dy53My5vcmcvMjAw\\u000aMS8wNC94bWxlbmMjcnNhLW9hZXAtbWdmMXAiIHhtbG5zOnhlbmM9Imh0dHA6Ly93\\u000ad3cudzMub3JnLzIwMDEvMDQveG1sZW5jIyI+PGRzOkRpZ2VzdE1ldGhvZCB4bWxu\\u000aczpkcz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC8wOS94bWxkc2lnIyIgQWxnb3Jp\\u000adGhtPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjc2hhMSIvPjwv\\u000aeGVuYzpFbmNyeXB0aW9uTWV0aG9kPjxkczpLZXlJbmZvIHhtbG5zOmRzPSJodHRw\\u000aOi8vd3d3LnczLm9yZy8yMDAwLzA5L3htbGRzaWcjIj48ZHM6WDUwOURhdGE+PGRz\\u000aOlg1MDlDZXJ0aWZpY2F0ZT5NSUlERlRDQ0FmMENCRlVCbkw0d0RRWUpLb1pJaHZj\\u000aTkFRRUxCUUF3VHpFTE1Ba0dBMVVFQmhNQ1FWUXhEVEFMQmdOVkJBY01CRWR5CllY\\u000ab3hEVEFMQmdOVkJBb01CRVZIU1ZveElqQWdCZ05WQkFNTUdVMVBRUzFKUkNCSlJG\\u000aQWdLRlJsYzNRdFZtVnljMmx2Ymlrd0hoY04KTVRVd016RXlNVFF3TXpReVdoY05N\\u000aVGN4TWpBMU1UUXdNelF5V2pCUE1Rc3dDUVlEVlFRR0V3SkJWREVOTUFzR0ExVUVC\\u000ad3dFUjNKaAplakVOTUFzR0ExVUVDZ3dFUlVkSldqRWlNQ0FHQTFVRUF3d1pUVTlC\\u000aTFVsRUlFbEVVQ0FvVkdWemRDMVdaWEp6YVc5dUtUQ0NBU0l3CkRRWUpLb1pJaHZj\\u000aTkFRRUJCUUFEZ2dFUEFEQ0NBUW9DZ2dFQkFJSnYwcWU5VWR2RllTTDVJMDJHb2t3\\u000aRVZmc0lHYzdJN0VoVk5PeFkKOW10VWVubWhxTnJMc0xCRmcxSWlQYmswSVNXaE9S\\u000ad1B5VnAvUDMrR3lHUDMzOXFaNjhVQ0dWMzYxRTBRbTdjalBlL08zK3IzSEFNMgpa\\u000aQk44b0Fab0htcGhyTlM2ZktmWTU4a3lndHJVYStaeU16WVdUVGlTMzJTQ004SDU1\\u000aYmx1RUZiZVprc25iUDBZOTRJamtmSmRndnpsCk14enJsU3lvVjJ5bVdCanZTNXdl\\u000abERIZ2JDS3lqc2pJaFRSakp1L29sR0p5ZW4wMS9FcElWdFN5RFhPLzJJUzJ2Mk85\\u000aVWlGd0FveUIKWUFqUG5sM0h4SzJBNTc3blI2M014bGdQMC9zK3I4NHVCcU9BbGI0\\u000acW5icFU3bHU1R3hsQ1BrWm1wUm9vQ1FZVVJpb0Mrd2pTNmxNQwpBd0VBQVRBTkJn\\u000aa3Foa2lHOXcwQkFRc0ZBQU9DQVFFQUJxTzdra3EvZ1JhaEF2cHNRZzVMTFpST0dG\\u000acjlwSVByeU45eG1KR2dQbzdqCktObDdyczdnTlMwbG11bHVZV1duSmN3QVBid0Zl\\u000aYjk1NFZNQjl4OXA5UUV3NVJuWGFtVVk5cWEwTGdjUy90L1dYNnZKa1pQTmhXcGgK\\u000aOGJYd2gwTXZsc2JmcnZEVEpyOGNqSDNxZnhJVHA3cGEzeGIxcUU3c3VSZmZWVWRE\\u000aWGF3aVhYbldKL1dKcit0d1ZWSEhFcW5aejFsQQpyU0RMeE04c0NqRzhEZUp3OHZu\\u000aUXk1bVBHckdWVEJiYTR1cGM4VVRZMW5QVjlVMkdCSlZZdUFrb1ZSamJUbE52ckw1\\u000aSnFOcXlwS2NHCmJlampXeGdyelprZVFlVTJoRmNqdW5tZ3dHWit1ZzJmcTRrS2tR\\u000aZnR3Y3FlSlR6eXpCb28yK09vNFRtZmJzaC9vbnhQV0E9PTwvZHM6WDUwOUNlcnRp\\u000aZmljYXRlPjwvZHM6WDUwOURhdGE+PC9kczpLZXlJbmZvPjx4ZW5jOkNpcGhlckRh\\u000adGEgeG1sbnM6eGVuYz0iaHR0cDovL3d3dy53My5vcmcvMjAwMS8wNC94bWxlbmMj\\u000aIj48eGVuYzpDaXBoZXJWYWx1ZT5Sb1NHTGFDbDN3ZkRXdDlXMm9JSDNUQ3JPTVN4\\u000aL3Y1S0pQV2hndmhWNml2RmZXSWFJeDB5RnV2NVZTME5VZ2FUVGIwVjhUYnNGN1Vz\\u000aRllzQ0xldkVUa2lWbG5OeWE4dlVoL2lYTDYzT0JmdzR3T3pSNVZheVBuaWFwWFdM\\u000aa0RHTmQ5Y3E2QU8zR1JoTWJaZDdma2NhRWNJVTB2bGtZeUJJNmE0Yms4bHM3Mm0v\\u000aZkxKQS8vaWl5L2piODkzQkZ4dk9EMk5hT1pabXhzSlI4YlFmWWpBMHdXa1pBcW56\\u000aN0EzY3lhcHV3aXVTc01wc1hYSnFjVXp2TS9GS090dE1wTnhSUVprdk1RZlNnMCtM\\u000aUVM5M0IxN0ZUZFE2OHNRL3dZQmhubFBEZXFZK0NnY1VjeVYzOVdjTjAwcUtVYmNQ\\u000aM2kzSWRWUVRkcEJQUTdRS01HR2JmS1Y0RlE9PTwveGVuYzpDaXBoZXJWYWx1ZT48\\u000aL3hlbmM6Q2lwaGVyRGF0YT48eGVuYzpSZWZlcmVuY2VMaXN0Pjx4ZW5jOkRhdGFS\\u000aZWZlcmVuY2UgVVJJPSIjXzNmZDM1ODkyZTlhOGVhY2I4ZTA4ZjI4MGE4M2ZjYjc0\\u000aIi8+PC94ZW5jOlJlZmVyZW5jZUxpc3Q+PC94ZW5jOkVuY3J5cHRlZEtleT48L3Nh\\u000abWwyOkVuY3J5cHRlZEFzc2VydGlvbj48L3NhbWwycDpSZXNwb25zZT4=\",\"dateTimeCreated\":\"2015-10-09T10:36:02.075Z\",\"id\":1}}}"; // @@ -57,19 +304,19 @@ public class Tests { - JsonObject responseMsg = new JsonObject(); - responseMsg.addProperty( - SSOTransferConstants.SSOCONTAINER_KEY_STATUS, - "OK"); - - - JsonObject levelTwo = new JsonObject(); - levelTwo.addProperty("test", "12345"); - - responseMsg.add("levelTwo", levelTwo ); - - - System.out.println(responseMsg.toString()); +// JsonObject responseMsg = new JsonObject(); +// responseMsg.addProperty( +// SSOTransferConstants.SSOCONTAINER_KEY_STATUS, +// "OK"); +// +// +// JsonObject levelTwo = new JsonObject(); +// levelTwo.addProperty("test", "12345"); +// +// responseMsg.add("levelTwo", levelTwo ); +// +// +// System.out.println(responseMsg.toString()); // } catch (IOException e) { // // TODO Auto-generated catch block @@ -80,4 +327,7 @@ public class Tests { } + + + } diff --git a/id/server/modules/pom.xml b/id/server/modules/pom.xml index 3ca3497a0..000851a5f 100644 --- a/id/server/modules/pom.xml +++ b/id/server/modules/pom.xml @@ -32,6 +32,7 @@ <module>moa-id-module-elga_mandate_service</module> <module>moa-id-module-ssoTransfer</module> + <module>moa-id-module-bkaMobilaAuthSAML2Test</module> </modules> <dependencies> |