diff --git a/patterns/1d81bd987455a8e1ee044ccf_authStatesFile/epd_idp.xml b/patterns/1d81bd987455a8e1ee044ccf_authStatesFile/epd_idp.xml
index a74ef90..b52e3b4 100644
--- a/patterns/1d81bd987455a8e1ee044ccf_authStatesFile/epd_idp.xml
+++ b/patterns/1d81bd987455a8e1ee044ccf_authStatesFile/epd_idp.xml
@@ -60,9 +60,15 @@
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/1f0702aaabef60a615abf41f_resources/resources.zip b/patterns/1f0702aaabef60a615abf41f_resources/resources.zip
index 413d251..9bb69c5 100644
Binary files a/patterns/1f0702aaabef60a615abf41f_resources/resources.zip and b/patterns/1f0702aaabef60a615abf41f_resources/resources.zip differ
diff --git a/patterns/204c22beaccdfd22727af378_labels/labels.zip b/patterns/204c22beaccdfd22727af378_labels/labels.zip
index d1ccdcb..c242b81 100644
Binary files a/patterns/204c22beaccdfd22727af378_labels/labels.zip and b/patterns/204c22beaccdfd22727af378_labels/labels.zip differ
diff --git a/patterns/204c22beaccdfd22727af378_template/webdata.zip b/patterns/204c22beaccdfd22727af378_template/webdata.zip
index 4bf894c..01e6d03 100644
Binary files a/patterns/204c22beaccdfd22727af378_template/webdata.zip and b/patterns/204c22beaccdfd22727af378_template/webdata.zip differ
diff --git a/patterns/2cdd910036aa06b102863a4f_scriptFile/checkLoa.groovy b/patterns/2cdd910036aa06b102863a4f_scriptFile/checkLoa.groovy
index 58cbde7..bec686c 100644
--- a/patterns/2cdd910036aa06b102863a4f_scriptFile/checkLoa.groovy
+++ b/patterns/2cdd910036aa06b102863a4f_scriptFile/checkLoa.groovy
@@ -140,7 +140,7 @@ try {
s.setAttribute('ch.nevis.idm.User.gender', '2')
}
if(s.get('ch.nevis.idm.User.gender') == 'OTHER'){
- session.setAttribute('ch.nevis.idm.User.gender', '3')
+ s.setAttribute('ch.nevis.idm.User.gender', '3')
}
@@ -223,7 +223,7 @@ try {
if (recoveryRoleList.contains('mustRecover')) {
s.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:mustRecover')
- s.setAttribute('agov.recovery.authenticatedWith', session.getAttribute('authenticatedWith') ?: 'unknown' )
+ s.setAttribute('agov.recovery.authenticatedWith', session.get('authenticatedWith') ?: 'unknown' )
def origIdVerification = getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString()) ?: 'None'
def idVerification = getUserIdVerificationForRecovery() ?: origIdVerification
@@ -247,8 +247,8 @@ try {
} else {
s.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recovery')
}
- s.setAttribute('agov.recovery.authenticatedWith', session.getAttribute('authenticatedWith') ?: 'unknown')
- s.setAttribute('agov.recovery.currentAgovAq', session.getAttribute('contextClassRefToSet') ?: 'urn:qa.agov.ch:names:tc:ac:classes:100' )
+ s.setAttribute('agov.recovery.authenticatedWith', session.get('authenticatedWith') ?: 'unknown')
+ s.setAttribute('agov.recovery.currentAgovAq', session.get('contextClassRefToSet') ?: 'urn:qa.agov.ch:names:tc:ac:classes:100' )
LOG.debug('CheckLoa: idVerification2= '+ getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString()))
def idVerification = getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString())
s.setAttribute('agov.recovery.currentIdVerification', (idVerification.isEmpty() ? 'None' : idVerification.first()))
diff --git a/patterns/328e529ed345d17cacb4ec66_authStatesFile/eid_start_agov_account_linking.xml b/patterns/328e529ed345d17cacb4ec66_authStatesFile/eid_start_agov_account_linking.xml
new file mode 100644
index 0000000..7fda219
--- /dev/null
+++ b/patterns/328e529ed345d17cacb4ec66_authStatesFile/eid_start_agov_account_linking.xml
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/328e529ed345d17cacb4ec66_resources/eid_start_account_linking.groovy b/patterns/328e529ed345d17cacb4ec66_resources/eid_start_account_linking.groovy
new file mode 100644
index 0000000..3760554
--- /dev/null
+++ b/patterns/328e529ed345d17cacb4ec66_resources/eid_start_account_linking.groovy
@@ -0,0 +1,27 @@
+import ch.nevis.esauth.auth.engine.AuthResponse
+
+def sess = request.getAuthSession(true)
+
+if(inargs['cancelEid']){
+ LOG.debug("Account registration canceled: Send response with error")
+ response.setResult('cancel')
+ return
+}
+
+if(inargs['continue'] == 'link_account'){
+ LOG.debug("AGOV account linking")
+ //sess.setAttribute("eid.placeholder.text", "EId: Implicit account linking not implemented yet")
+ response.setResult('link')
+ return
+}
+
+if(inargs['continue'] == 'register_account'){
+ LOG.debug("AGOV account registration was selected")
+ sess.setAttribute("eid.placeholder.text", "EId: Account registration with implicit linking not implemented yet")
+ response.setResult('register')
+ return
+}
+
+LOG.debug("Show GUI")
+response.setStatus(AuthResponse.AUTH_CONTINUE)
+return
\ No newline at end of file
diff --git a/patterns/359792ce61c28c723ab7d354_authStatesFile/eid_account_linking_redirect_to_agovme.xml b/patterns/359792ce61c28c723ab7d354_authStatesFile/eid_account_linking_redirect_to_agovme.xml
new file mode 100644
index 0000000..a0387b9
--- /dev/null
+++ b/patterns/359792ce61c28c723ab7d354_authStatesFile/eid_account_linking_redirect_to_agovme.xml
@@ -0,0 +1,61 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/359792ce61c28c723ab7d354_resources/eid_account_linking_redirect_to_agovme.groovy b/patterns/359792ce61c28c723ab7d354_resources/eid_account_linking_redirect_to_agovme.groovy
new file mode 100644
index 0000000..b6c12d2
--- /dev/null
+++ b/patterns/359792ce61c28c723ab7d354_resources/eid_account_linking_redirect_to_agovme.groovy
@@ -0,0 +1,23 @@
+if(outargs.containsKey('saml.SAMLResponse')) {
+ // Accounting
+ def requester = session['ch.nevis.auth.saml.request.scoping.requesterId'] ?: 'unknown'
+ def requestId = session['ch.nevis.auth.saml.request.id'] ?: 'unknown'
+ def requestedAq = session['agov.requestedRoleLevel'] ?: 'unknown'
+ def user = session['ch.adnovum.nevisidm.user.extId'] ?: 'unknown'
+ def credentialType = session['agov.authenticatedWith'] ?: 'unknown'
+ def sourceIp = request.getLoginContext()['connection.HttpHeader.X-Real-IP'] ?: 'unknown'
+ def userAgent = request.getLoginContext()['connection.HttpHeader.user-agent'] ?: request.getLoginContext()['connection.HttpHeader.User-Agent'] ?: 'unknown'
+
+ LOG.info("Event='GOTOEIDLINKING', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}'")
+
+ // Redirect
+ response.addOutArg('nevis.transfer.destination', parameters.get('agovmedirecturl'))
+ response.addOutArg('nevis.transfer.field.SAMLResponse', outargs.getProperty('saml.SAMLResponse').bytes.encodeBase64().toString())
+ response.setStatus(ch.nevis.esauth.auth.engine.AuthResponse.AUTH_CONTINUE)
+ response.setIsRedirectTransfer(false)
+
+ response.removeOutArg('saml.SAMLResponse')
+}
+else {
+ response.setResult('ok')
+}
\ No newline at end of file
diff --git a/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua b/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua
index 7d66fb4..25f8bf7 100644
--- a/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua
+++ b/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua
@@ -6,7 +6,7 @@ validLanguages["DE"]=true
validLanguages["FR"]=true
validLanguages["IT"]=true
validLanguages["EN"]=true
-validLanguages["RS"]=true
+validLanguages["RM"]=true
function inputHeader(req, resp)
local trace = req:getTracer()
diff --git a/patterns/4f15bae09cbda04a7a515158_resources/eid_fetch_linked_accounts.groovy b/patterns/4f15bae09cbda04a7a515158_resources/eid_fetch_linked_accounts.groovy
index 6b1141e..de2a2fb 100644
--- a/patterns/4f15bae09cbda04a7a515158_resources/eid_fetch_linked_accounts.groovy
+++ b/patterns/4f15bae09cbda04a7a515158_resources/eid_fetch_linked_accounts.groovy
@@ -6,8 +6,6 @@ import ch.nevis.idm.client.HTTPRequestWrapper
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
-
-
def getHeader(String name) {
def inctx = request.getLoginContext()
// case-insensitive lookup of HTTP headers
@@ -34,6 +32,7 @@ def clearEidSession(){
}
def getAccounts(json, String svnr) {
+ String svnrWithPrefix = "urn:ch-agov-eid:$svnr"
def idm_users_dto = json["Resources"]
def accounts = [:]
def frontend_dto = []
@@ -50,8 +49,8 @@ def getAccounts(json, String svnr) {
def extId = user["externalId"]
//TODO/aca/2025/06/11: Can we have multiple email adresses? -> if yes search for primary
String email = user["emails"][0]["value"]
- if(cred["type"] == "SAMLFEDERATION" && cred["issuerNameId"] == svnr){
- // we found a second federation credential in one AGOV account -> Throw data error
+ if(cred["type"] == "SAMLFEDERATION" && ( cred["issuerNameId"] == svnr || cred["issuerNameId"] == svnrWithPrefix )){
+ // we found more than one federation credential in one AGOV account -> Throw data error
if(foundCredential){
LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${extId}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Multiple EId linking credentials found in one AGOV account'")
return [null,null]
@@ -140,7 +139,7 @@ LOG.debug("search for accounts with SVNR: $svnr")
// Pepare GET request
String attributes = "externalId,emails,urn:nevis:idm:scim:schemas:v1:extension:User.credentials.type,urn:nevis:idm:scim:schemas:v1:extension:User.credentials.issuerNameId,urn:nevis:idm:scim:schemas:v1:extension:User.credentials.subjectNameId,urn:nevis:idm:scim:schemas:v1:extension:User.credentials.extId,urn:nevis:idm:scim:schemas:v1:extension:User.credentials.credentialLoginInfo.lastLogin"
-String filter = "urn:nevis:idm:scim:schemas:v1:extension:User.credentials.type=='SAMLFEDERATION'%20AND%20urn:nevis:idm:scim:schemas:v1:extension:User.credentials.issuerNameId=='$svnr'"
+String filter = "urn:nevis:idm:scim:schemas:v1:extension:User.credentials.type=='SAMLFEDERATION'%20AND%20%28%20urn:nevis:idm:scim:schemas:v1:extension:User.credentials.issuerNameId%20==%20'$svnr'%20OR%20urn:nevis:idm:scim:schemas:v1:extension:User.credentials.issuerNameId%20==%20'urn:ch-agov-eid:$svnr'%29"
String requestUrl = "$endPoint?count=20&attributes=$attributes&filter=$filter"
@@ -157,7 +156,7 @@ try {
def (accounts, frontend_dto) = getAccounts(json, svnr)
// unrecoverable DATA ERROR happend
- if(!accounts){
+ if(accounts == null){
response.setResult('error')
return
}
@@ -167,9 +166,7 @@ try {
LOG.debug("Linked accounts found: " + frontend_dto.toString())
if(numAccounts == 0){
- //TODO/aca/2025-06-10: Implement next step
- // Redirect to an error page or linking page when that's ready and decided
- sess.setAttribute("eid.placeholder.text", "EId: No AGOV Account found case not implemented yet")
+ // No account found => show account linking dialog options
response.setResult('noAccount')
return
}else if(numAccounts == 1){
diff --git a/patterns/4f6692a69e4f33c8ed4c145f_script/responseHeaderPostProcessing.lua b/patterns/4f6692a69e4f33c8ed4c145f_script/responseHeaderPostProcessing.lua
index ce29239..b724e0b 100644
--- a/patterns/4f6692a69e4f33c8ed4c145f_script/responseHeaderPostProcessing.lua
+++ b/patterns/4f6692a69e4f33c8ed4c145f_script/responseHeaderPostProcessing.lua
@@ -2,11 +2,20 @@ function outputHeader(request, response)
trace = request:getTracer()
-- rename Set-Cookie2 header
- local setCookieHeader = response:getHeader("Set-Cookie2")
- if (setCookieHeader ~= nil) then
- trace:debug("Set a new cookie: " .. setCookieHeader)
- response:addHeader("Set-Cookie", setCookieHeader)
+ local setCookieHeader2 = response:getHeader("Set-Cookie2")
+ if (setCookieHeader2 ~= nil) then
+ trace:debug("Set a new cookie: " .. setCookieHeader2)
+ response:addHeader("Set-Cookie", setCookieHeader2)
response:removeHeader("Set-Cookie2")
end
+ -- BUNDBITBK-5688: We need to somtimes set 3 cookies with the new LOGINMETHOD cookie
+ -- rename Set-Cookie3 header
+ local setCookieHeader3 = response:getHeader("Set-Cookie3")
+ if (setCookieHeader3 ~= nil) then
+ trace:debug("Set a new cookie: " .. setCookieHeader3)
+ response:addHeader("Set-Cookie", setCookieHeader3)
+ response:removeHeader("Set-Cookie3")
+ end
+
end
\ No newline at end of file
diff --git a/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip b/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip
index d1ccdcb..c242b81 100644
Binary files a/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip and b/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip differ
diff --git a/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip b/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip
index 4bf894c..01e6d03 100644
Binary files a/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip and b/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip differ
diff --git a/patterns/5a75ffc73b91b88cfab6168e_authStatesFile/epd_artifact_idp.xml b/patterns/5a75ffc73b91b88cfab6168e_authStatesFile/epd_artifact_idp.xml
index 9cd7979..7004588 100644
--- a/patterns/5a75ffc73b91b88cfab6168e_authStatesFile/epd_artifact_idp.xml
+++ b/patterns/5a75ffc73b91b88cfab6168e_authStatesFile/epd_artifact_idp.xml
@@ -64,11 +64,16 @@
-
+
-
-
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/68665057549fd887ea09fb86_scriptFile/requestedRoleLevel.groovy b/patterns/68665057549fd887ea09fb86_scriptFile/requestedRoleLevel.groovy
index 69f33db..269f27c 100644
--- a/patterns/68665057549fd887ea09fb86_scriptFile/requestedRoleLevel.groovy
+++ b/patterns/68665057549fd887ea09fb86_scriptFile/requestedRoleLevel.groovy
@@ -105,7 +105,8 @@ try {
session.setAttribute('agov.appDisplayNameFR', '' + json.displayNameFr)
session.setAttribute('agov.appDisplayNameIT', '' + json.displayNameIt)
session.setAttribute('agov.appDisplayNameEN', '' + json.displayNameEn)
- session.setAttribute('agov.appDisplayNameRM', '' + ((json.appDisplayNameRM) ? json.appDisplayNameRM : json.appDisplayNameDE))
+ session.setAttribute('agov.appDisplayNameRM', '' + json.displayNameRm)
+ //session.setAttribute('agov.appDisplayNameRM', '' + ( (json.displayNameRm) ? json.displayNameDe : json.displayNameRm))
// if aq500 or 600 is requested -> the only available login method is eid -> continue directly there
// if eid is disabled -> show an error page
diff --git a/patterns/7702342f21437f3de530e10c_authStatesFile/eid_account_linking_check_account_state.xml b/patterns/7702342f21437f3de530e10c_authStatesFile/eid_account_linking_check_account_state.xml
new file mode 100644
index 0000000..afb7d3f
--- /dev/null
+++ b/patterns/7702342f21437f3de530e10c_authStatesFile/eid_account_linking_check_account_state.xml
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/7702342f21437f3de530e10c_resources/eid_account_linking_check_account_state.groovy b/patterns/7702342f21437f3de530e10c_resources/eid_account_linking_check_account_state.groovy
new file mode 100644
index 0000000..3a52259
--- /dev/null
+++ b/patterns/7702342f21437f3de530e10c_resources/eid_account_linking_check_account_state.groovy
@@ -0,0 +1,40 @@
+import ch.nevis.idm.client.IdmRestClient
+import ch.nevis.idm.client.IdmRestClientFactory
+
+
+// TODO/aca/2025/08/15
+
+String user_notification_dto = '''
+{
+ "clientExtId": "{{clientExtId}}",
+ "userExtId": "{{userExtId}}",
+ "notificationType": "userNotification3",
+ "sendingMethod": [
+ "Email"
+ ],
+ "async": false
+}
+'''
+
+IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)
+def sess = request.getAuthSession(true)
+
+String baseUrl = parameters.get("baseUrl")
+String clientExtId = parameters.get("clientExtId")
+String endPoint = "$baseUrl/api/notification/v1/"
+
+String userExtId = sess.getAttribute("ch.nevis.idm.User.extId")
+
+String restRequest = user_notification_dto.replaceAll("\\{\\{clientExtId}}", clientExtId).replaceAll("\\{\\{userExtId}}", userExtId)
+
+try {
+ idmRestClient.post(endPoint, restRequest)
+
+}catch(Exception e) {
+ LOG.error("Failed to send User Notification: Idm Update with EId data: ${e}")
+ response.setResult('error')
+ return
+}
+
+response.setResult('ok')
+return
\ No newline at end of file
diff --git a/patterns/92cb6d5256008a32f12ceb93_authStatesFile/agov_idp.xml b/patterns/92cb6d5256008a32f12ceb93_authStatesFile/agov_idp.xml
index a4182e8..f64a4eb 100644
--- a/patterns/92cb6d5256008a32f12ceb93_authStatesFile/agov_idp.xml
+++ b/patterns/92cb6d5256008a32f12ceb93_authStatesFile/agov_idp.xml
@@ -71,6 +71,7 @@
+
@@ -85,5 +86,5 @@
-
+
\ No newline at end of file
diff --git a/patterns/DefaultErrorPages_ecf4381f4653b0aa9a69b417.yml b/patterns/DefaultErrorPages_ecf4381f4653b0aa9a69b417.yml
index 36a7e75..9f43a32 100644
--- a/patterns/DefaultErrorPages_ecf4381f4653b0aa9a69b417.yml
+++ b/patterns/DefaultErrorPages_ecf4381f4653b0aa9a69b417.yml
@@ -5,34 +5,66 @@ pattern:
name: "DefaultErrorPages"
label: "UTILS"
properties:
- filters: "\n DefaultErrorFilter\n ch::nevis::isiweb4::filter::error::ErrorFilter\n\
- \ \n StatusCode\n \n\
- \ 400:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/404.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ 403:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/403.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ 404:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/404.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ 408:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/timeout.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ 500:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/500.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ 502:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/errorPages/502.vm?logrendresourcepath=/nevislogrend:keep-status-code\n\
- \ \n \n \n CheckAcceptHeader\n\
- \ true\n \n \n\
- \ PlaceHolders\n \n \
- \ TransferIdHolder:TRANSFER_ID\n TimestampHolder:TIMESTAMP\n\
- \ \n \n\n\n FallbackErrorFilter\n\
- \ ch::nevis::isiweb4::filter::error::ErrorFilter\n\
- \ \n StatusCode\n \n\
- \ 500:file:/resources/errorPages/500.html:reset-header:reset-status-code\n\
- \ 502:file:/resources/errorPages/502.html:reset-header:reset-status-code\n\
- \ 503:file:/resources/errorPages/500.html:reset-header:reset-status-code\n\
- \ 504:file:/resources/errorPages/500.html:reset-header:reset-status-code\n\
- \ \n \n \n CheckAcceptHeader\n\
- \ true\n \n \n\
- \ PlaceHolders\n \n \
- \ TransferIdHolder:TRANSFER_ID\n TimestampHolder:TIMESTAMP\n\
- \ \n \n\n\n\
- \ DefaultErrorFilter\n /*\n\
- \n\n FallbackErrorFilter\n\
- \ NevisLogrendConnector_${param.logrendInstancePatternName}\n\
- "
+ filters: |-
+
+ DefaultErrorFilter
+ ch::nevis::isiweb4::filter::error::ErrorFilter
+
+ StatusCode
+
+ 400:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/404.vm?logrendresourcepath=/nevislogrend:keep-status-code
+ 403:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/403.vm?logrendresourcepath=/nevislogrend:keep-status-code
+ 404:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/404.vm?logrendresourcepath=/nevislogrend:keep-status-code
+ 408:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/timeout.vm?logrendresourcepath=/nevislogrend:keep-status-code
+ 500:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/500.vm?logrendresourcepath=/nevislogrend:keep-status-code
+ 502:NevisLogrendConnector_${param.logrendInstancePatternName}:/nevislogrend/webdata/template/502.vm?logrendresourcepath=/nevislogrend:keep-status-code
+
+
+
+ CheckAcceptHeader
+ true
+
+
+ PlaceHolders
+
+ TransferIdHolder:TRANSFER_ID
+ TimestampHolder:TIMESTAMP
+
+
+
+
+ FallbackErrorFilter
+ ch::nevis::isiweb4::filter::error::ErrorFilter
+
+ StatusCode
+
+ 500:file:/resources/errorPages/500.html:reset-header:reset-status-code
+ 502:file:/resources/errorPages/502.html:reset-header:reset-status-code
+ 503:file:/resources/errorPages/500.html:reset-header:reset-status-code
+ 504:file:/resources/errorPages/500.html:reset-header:reset-status-code
+
+
+
+ CheckAcceptHeader
+ true
+
+
+ PlaceHolders
+
+ TransferIdHolder:TRANSFER_ID
+ TimestampHolder:TIMESTAMP
+
+
+
+
+ DefaultErrorFilter
+ /*
+ ^/oidc4vp/.*$|^/resource/utility/.*$
+
+
+ FallbackErrorFilter
+ NevisLogrendConnector_${param.logrendInstancePatternName}
+
filterMappings: "manual"
phase: "START"
parameters: "logrendInstancePatternName: nevisLogrend"
diff --git a/patterns/EId_Account_Linking_Mobile_NLess_Auth_da38e049a1ff97663fb30a45.yml b/patterns/EId_Account_Linking_Mobile_NLess_Auth_da38e049a1ff97663fb30a45.yml
new file mode 100644
index 0000000..ad33ca7
--- /dev/null
+++ b/patterns/EId_Account_Linking_Mobile_NLess_Auth_da38e049a1ff97663fb30a45.yml
@@ -0,0 +1,16 @@
+schemaVersion: "1.0"
+pattern:
+ id: "da38e049a1ff97663fb30a45"
+ className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
+ name: "EId_Account_Linking_Mobile_NLess_Auth"
+ label: "EID LINKING"
+ properties:
+ authStatesFile: "res://da38e049a1ff97663fb30a45#authStatesFile"
+ onSuccess:
+ - "pattern://359792ce61c28c723ab7d354"
+ nextSteps:
+ - "pattern://47f8f6ef24f62431fbe1b530"
+ - "pattern://4c65de021d362462324a3a5f"
+ resources: "res://da38e049a1ff97663fb30a45#resources"
+ keyObjects:
+ - "pattern://95220b3005deb118adeb01aa"
diff --git a/patterns/EId_Select_AGOV_Account_4f15bae09cbda04a7a515158.yml b/patterns/EId_Select_AGOV_Account_4f15bae09cbda04a7a515158.yml
index 5773a2a..f6f465d 100644
--- a/patterns/EId_Select_AGOV_Account_4f15bae09cbda04a7a515158.yml
+++ b/patterns/EId_Select_AGOV_Account_4f15bae09cbda04a7a515158.yml
@@ -11,7 +11,7 @@ pattern:
onFailure:
- "pattern://4c65de021d362462324a3a5f"
nextSteps:
- - "pattern://47f8f6ef24f62431fbe1b530"
+ - "pattern://328e529ed345d17cacb4ec66"
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://4f15bae09cbda04a7a515158#resources"
keyObjects:
diff --git a/patterns/IDP_OIDC4VP_Service_450d8070d6c0b395c98a013f.yml b/patterns/IDP_OID4VP_Service_450d8070d6c0b395c98a013f.yml
similarity index 53%
rename from patterns/IDP_OIDC4VP_Service_450d8070d6c0b395c98a013f.yml
rename to patterns/IDP_OID4VP_Service_450d8070d6c0b395c98a013f.yml
index bb92b69..255cd44 100644
--- a/patterns/IDP_OIDC4VP_Service_450d8070d6c0b395c98a013f.yml
+++ b/patterns/IDP_OID4VP_Service_450d8070d6c0b395c98a013f.yml
@@ -2,9 +2,12 @@ schemaVersion: "1.0"
pattern:
id: "450d8070d6c0b395c98a013f"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.RESTServiceAccess"
- name: "IDP_OIDC4VP_Service"
+ name: "IDP_OID4VP_Service"
properties:
host:
- "pattern://1f0702aaabef60a615abf41f"
- path: "/oidc4vp/"
- backends: "var://eid-oidc4vp-service-url"
+ path: "/oid4vp/"
+ backends: "var://eid-oid4vp-service-url"
+ hostHeader: "backend"
+ responseRewrite: "header"
+ jsonValidation: "disabled"
diff --git a/patterns/IDP_SP_Connector_27cefc3861bce987f6766342.yml b/patterns/IDP_SP_Connector_27cefc3861bce987f6766342.yml
index c7fcab5..0543752 100644
--- a/patterns/IDP_SP_Connector_27cefc3861bce987f6766342.yml
+++ b/patterns/IDP_SP_Connector_27cefc3861bce987f6766342.yml
@@ -4,11 +4,11 @@ pattern:
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns.SamlSpConnector"
name: "IDP_SP_Connector"
label: "IDP"
- notes: "- Subject NameID Format -> urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified\n\
- - dateOfBirth: to have a date suitable for SAML and OIDC, we remove the TimeZone\
- \ charachter ('1993-03-03Z' --> '1993-03-03')\n- verificationMethod: BUNDBITBK-2892\
- \ SelfPaid is only for internal use, we remove this from the public assertion\n\
- - address.verificationMethod: BUNDBITBK-2921 avoid interface change for hotfix"
+ notes: |-
+ - Subject NameID Format -> urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified
+ - dateOfBirth: to have a date suitable for SAML and OIDC, we remove the TimeZone charachter ('1993-03-03Z' --> '1993-03-03')
+ - verificationMethod: BUNDBITBK-2892 SelfPaid is only for internal use, we remove this from the public assertion
+ - address.verificationMethod: BUNDBITBK-2921 avoid interface change for hotfix
link:
sourceProjectKey: "DEFAULT-IAM-JAKOB"
sourcePatternId: "27cefc3861bce987f6766342"
@@ -58,6 +58,9 @@ pattern:
\ 'Domicile') : '' }"
- http://schemas.agov.ch/ws/2024/02/identity/claims/address/countryName: "#{ (sess['agov.appAddressRequired']\
\ == 'true') ? sess['agov.countryName'] : ''}"
+ - http://schemas.agov.ch/ws/2025/07/identity/claims/placeOfOrigin: "#{ (sess['agov.appSvnrAllowed']\\\
+ \ \\ == 'true') ? sess['agov.eid.User.placeOfOrigin'] : ''}"
+ - http://schemas.agov.ch/ws/2025/07/identity/claims/op/conversationId: "${inctx:connection.HttpHeader.traceparent:^([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)-([0-9a-f]+)$:$2}"
context: "PasswordProtectedTransport"
assertionLifetime: "30s"
sign:
diff --git a/patterns/_EId_Account_Linking_Check_Account_State_7702342f21437f3de530e10c.yml b/patterns/_EId_Account_Linking_Check_Account_State_7702342f21437f3de530e10c.yml
new file mode 100644
index 0000000..bbdef01
--- /dev/null
+++ b/patterns/_EId_Account_Linking_Check_Account_State_7702342f21437f3de530e10c.yml
@@ -0,0 +1,9 @@
+schemaVersion: "1.0"
+pattern:
+ id: "7702342f21437f3de530e10c"
+ className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
+ name: " EId_Account_Linking_Check_Account_State"
+ label: "EID LINKING"
+ properties:
+ authStatesFile: "res://7702342f21437f3de530e10c#authStatesFile"
+ resources: "res://7702342f21437f3de530e10c#resources"
diff --git a/patterns/_EId_Account_Linking_Redirect_To_Agovme_359792ce61c28c723ab7d354.yml b/patterns/_EId_Account_Linking_Redirect_To_Agovme_359792ce61c28c723ab7d354.yml
new file mode 100644
index 0000000..22f8cd2
--- /dev/null
+++ b/patterns/_EId_Account_Linking_Redirect_To_Agovme_359792ce61c28c723ab7d354.yml
@@ -0,0 +1,10 @@
+schemaVersion: "1.0"
+pattern:
+ id: "359792ce61c28c723ab7d354"
+ className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
+ name: " EId_Account_Linking_Redirect_To_Agovme"
+ label: "EID LINKING"
+ properties:
+ authStatesFile: "res://359792ce61c28c723ab7d354#authStatesFile"
+ parameters: "var://service_provider_state-template-parameters"
+ resources: "res://359792ce61c28c723ab7d354#resources"
diff --git a/patterns/_EId_Start_AGOV_Account_Linking_328e529ed345d17cacb4ec66.yml b/patterns/_EId_Start_AGOV_Account_Linking_328e529ed345d17cacb4ec66.yml
new file mode 100644
index 0000000..23fbd2c
--- /dev/null
+++ b/patterns/_EId_Start_AGOV_Account_Linking_328e529ed345d17cacb4ec66.yml
@@ -0,0 +1,14 @@
+schemaVersion: "1.0"
+pattern:
+ id: "328e529ed345d17cacb4ec66"
+ className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
+ name: " EId_Start_AGOV_Account_Linking"
+ label: "EID"
+ properties:
+ authStatesFile: "res://328e529ed345d17cacb4ec66#authStatesFile"
+ onFailure:
+ - "pattern://4c65de021d362462324a3a5f"
+ nextSteps:
+ - "pattern://da38e049a1ff97663fb30a45"
+ - "pattern://47f8f6ef24f62431fbe1b530"
+ resources: "res://328e529ed345d17cacb4ec66#resources"
diff --git a/patterns/b87d0d2b640e8e545ad70234_resources/SendSamlResponseWithAssertion.groovy b/patterns/b87d0d2b640e8e545ad70234_resources/SendSamlResponseWithAssertion.groovy
index 97f51f6..f8fad88 100644
--- a/patterns/b87d0d2b640e8e545ad70234_resources/SendSamlResponseWithAssertion.groovy
+++ b/patterns/b87d0d2b640e8e545ad70234_resources/SendSamlResponseWithAssertion.groovy
@@ -40,7 +40,7 @@ if(loa_str){
// BUNDBITBK-5005: Set cookie to remember the last authentication method
def agovAuthMethodCookie = "LOGINMETHOD=${AUTHENTICATON_URN_TO_COOKIE_MAPPER[session.getAttribute('authenticatedWith')]}; Domain=${parameters.get('cookie.domain')}; Path=/; Max-Age=1800; SameSite=Strict; Secure; HttpOnly"
-response.setHeader('Set-Cookie2', agovAuthMethodCookie)
+response.setHeader('Set-Cookie3', agovAuthMethodCookie)
// delete the login cookie
def agovLoginCookie = "agovLogin=deleted; Domain=${parameters.get('cookie.domain')}; Path=/; Max-Age=0; SameSite=Strict; Secure; HttpOnly"
diff --git a/patterns/da38e049a1ff97663fb30a45_authStatesFile/eid_account_linking_mobile_nless_auth.xml b/patterns/da38e049a1ff97663fb30a45_authStatesFile/eid_account_linking_mobile_nless_auth.xml
new file mode 100644
index 0000000..af83c8c
--- /dev/null
+++ b/patterns/da38e049a1ff97663fb30a45_authStatesFile/eid_account_linking_mobile_nless_auth.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/da38e049a1ff97663fb30a45_resources/eid_account_linking_mobile_nless_auth.groovy b/patterns/da38e049a1ff97663fb30a45_resources/eid_account_linking_mobile_nless_auth.groovy
new file mode 100644
index 0000000..30cd19f
--- /dev/null
+++ b/patterns/da38e049a1ff97663fb30a45_resources/eid_account_linking_mobile_nless_auth.groovy
@@ -0,0 +1,100 @@
+import groovy.json.JsonBuilder
+import ch.nevis.esauth.auth.engine.AuthResponse
+
+
+def getHeader(String name) {
+ def inctx = request.getLoginContext()
+ // case-insensitive lookup of HTTP headers
+ def map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER)
+ map.putAll(inctx)
+ return map['connection.HttpHeader.' + name]
+}
+
+def clearFidoUAFSession() {
+ LOG.debug("start new FIDO UAF session (skipping ${session['ch.nevis.auth.fido.uaf.fidouafsessionid']}")
+ def s = request.getAuthSession(true)
+ s.removeAttribute('ch.nevis.auth.fido.uaf.fidouafsessionid')
+ inargs.remove('fallback')
+}
+
+
+def clearIdmSessionAttributes() {
+ def s = request.getAuthSession(true)
+ def sessionKeySet = new HashSet(session.keySet())
+ sessionKeySet.each { key ->
+ if ( key ==~ /ch.nevis.idm.*/ || key ==~ /ch.adnovum.nevisidm.*/ ) {
+ s.removeAttribute(key)
+ }
+ }
+}
+
+
+def sess = request.getAuthSession(true)
+
+// dispatch AJAX calls and form POST when operation is done
+if (inargs['fidoUafDone'] == 'true' ||
+ inargs.containsKey('o.fidoUafSessionId.v') ||
+ getHeader('Content-Type') == 'application/json') {
+
+ if (inargs.containsKey('o.fidoUafSessionId.v') && (inargs['o.fidoUafSessionId.v'] != session['ch.nevis.auth.fido.uaf.fidouafsessionid'])) {
+ // received polling for wrong fido session; make sure, that stops
+ LOG.debug("received polling for wrong fido session ${inargs['o.fidoUafSessionId.v']} (correct: ${session['ch.nevis.auth.fido.uaf.fidouafsessionid']})")
+ def json = new JsonBuilder()
+ json {
+ "status" "unknown"
+ "timestamp" org.joda.time.DateTime.now().toString()
+ }
+ String body = json.toString()
+
+ response.setContent(body)
+ response.setContentType('application/json')
+ response.setHttpStatusCode(200)
+ response.setIsDirectResponse(true)
+ response.setStatus(AuthResponse.AUTH_CONTINUE)
+ return
+ }
+
+ if (inargs['fidoUafDone'] == 'true') {
+ // get clean state, before validating user in IDM
+ LOG.debug("clear IDM session attributes")
+ clearIdmSessionAttributes()
+ }
+
+ // continue with OutOfBandFidoUafAuthState
+ response.setResult('ok')
+}
+
+// dispatch form post with fallback input field : transition to FIDO Token authentication
+if (inargs['fallback'] == 'fallback') {
+ sess.setAttribute("eid.placeholder.text", "Fido2 login not implemented yet")
+ response.setResult('fido2')
+}
+
+// dispatch to recovery
+if (inargs['fallback'] == 'recovery') {
+ response.addOutArg('nevis.transfer.destination', parameters.get('recoveryurl'))
+ response.setStatus(ch.nevis.esauth.auth.engine.AuthResponse.AUTH_CONTINUE)
+ response.setIsRedirectTransfer(true)
+ // Remove existing cookies before redirecting to RECOVERY
+ def agovRecoveryCookie = "agovRecovery=deleted; Path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Strict; Secure; HttpOnly"
+ response.setHeader('Set-Cookie', agovRecoveryCookie)
+ return
+}
+
+// dispatch form post with fallback input field : go to registration with right loa
+if (inargs['fallback'] == 'register') {
+ sess.setAttribute("eid.placeholder.text", "Registration should not be called here?")
+ response.setResult('registration')
+}
+
+// cancel and go back to login
+if (inargs['fallback'] == 'back') {
+ response.setResult('back')
+}
+
+
+// dispatch form post with onReload input field : refresh QR-code FIDO UAF
+if (inargs.containsKey('onReload')) {
+ clearFidoUAFSession()
+ response.setResult('default')
+}
diff --git a/patterns/e335f57d4c64dfc97223697a_resources/eid_verification_auth.groovy b/patterns/e335f57d4c64dfc97223697a_resources/eid_verification_auth.groovy
index 002db22..9e0029f 100644
--- a/patterns/e335f57d4c64dfc97223697a_resources/eid_verification_auth.groovy
+++ b/patterns/e335f57d4c64dfc97223697a_resources/eid_verification_auth.groovy
@@ -355,6 +355,7 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
sess.setAttribute('agov.eid.User.gender', claims.sex)
sess.setAttribute('agov.eid.User.svnr', claims.personal_administrative_number.replace('.',''))
sess.setAttribute('agov.eid.User.placeOfBirth', claims.birth_place)
+ sess.setAttribute('agov.eid.User.placeOfOrigin', claims.place_of_origin)
sess.setAttribute('agov.eid.User.eIdNumber', claims.document_number)
// Simpler for later comparison -> Is converted again to upper case in the saml assertion
sess.setAttribute('agov.eid.User.nationality', claims.nationality.toString().toLowerCase())
diff --git a/patterns/f63c475c35b616b7c6c1901c_authStatesFile/Mobile_NLess_Auth.xml b/patterns/f63c475c35b616b7c6c1901c_authStatesFile/Mobile_NLess_Auth.xml
index c80e91b..7853b63 100644
--- a/patterns/f63c475c35b616b7c6c1901c_authStatesFile/Mobile_NLess_Auth.xml
+++ b/patterns/f63c475c35b616b7c6c1901c_authStatesFile/Mobile_NLess_Auth.xml
@@ -10,6 +10,7 @@
+
diff --git a/variables.yml b/variables.yml
index ab64113..146752b 100644
--- a/variables.yml
+++ b/variables.yml
@@ -90,11 +90,14 @@ variables:
parameters:
required: false
syntax: "YAML"
- value: "cert.source: \"#{request:actorCertAsString}\"\ntechuser.client.name: Default\n\
- accounts.client.name: agov\nshadow-accounts.client.name: AGOV-S\nsaml.assertion.audience:\
- \ \"https://me.agov-d.azure.adnovum.net/account/api/saml2/service-provider-metadata/agovidpdirect\"\
- \nsaml.assertion.acsurl: \"https://me.agov-d.azure.adnovum.net/login/saml2/sso/agovidp\"\
- \nsaml.assertion.max_age: 30"
+ value: |-
+ cert.source: "#{request:actorCertAsString}"
+ techuser.client.name: Default
+ accounts.client.name: agov
+ shadow-accounts.client.name: AGOV-S
+ saml.assertion.audience: "https://me.agov-d.azure.adnovum.net/account/api/saml2/service-provider-metadata/agovidpdirect"
+ saml.assertion.acsurl: "https://me.agov-d.azure.adnovum.net/login/saml2/sso/agovidp"
+ saml.assertion.max_age: 30
requireOverloading: true
auth_soap-backend-addresses:
className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"
@@ -112,7 +115,9 @@ variables:
parameters:
required: false
syntax: "YAML"
- value: "fido2.serviceAndPort: fido2:9443\nrpId: auth.agov.admin.ch"
+ value: |-
+ fido2.serviceAndPort: fido2:9443
+ rpId: auth.agov.admin.ch
requireOverloading: true
backendAppIconUrl:
className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"
@@ -159,7 +164,7 @@ variables:
\ font-src 'self';"
- param_report_only_csp: "none"
requireOverloading: true
- eid-oidc4vp-service-url:
+ eid-oid4vp-service-url:
className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"
parameters:
minRequired: 1
@@ -168,16 +173,19 @@ variables:
hostNameInputMode: "REQUIRED"
portInputMode: "OPTIONAL"
pathInputMode: "OPTIONAL"
- value: "http://eid-verifier-oid4vp.adn-agov-eid-01-dev:8081/api"
+ value: "http://eid-verifier-oid4vp.adn-agov-eid-01-dev:8081/oid4vp/"
requireOverloading: true
ensure_recovery_code-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters:
required: false
syntax: "YAML"
- value: "utility-service.baseUrl: http://me-application-me-be.adn-agov-me-01-dev:8081/utility\n\
- token.algorithm: RS512\ntoken.time_to_live: 600\ntoken.keystoreref: DefaultKeyStore\n\
- token.keyobjectref: DefaultSigner"
+ value: |-
+ utility-service.baseUrl: http://me-application-me-be.adn-agov-me-01-dev:8081/utility
+ token.algorithm: RS512
+ token.time_to_live: 600
+ token.keystoreref: DefaultKeyStore
+ token.keyobjectref: DefaultSigner
requireOverloading: true
env_ca-trusted-certificates:
className: "ch.nevis.admin.v4.plugin.base.generation.property.AttachmentProperty"
@@ -224,9 +232,12 @@ variables:
parameters:
required: false
syntax: "YAML"
- value: "client.name: agov\nattributes: loginId,extId,firstName,name,email,gender,birthDate,language,sex,addressLine1,postalCode,city,country,street,houseNumber,locality,mobile\n\
- properties: eIdNumber,placeOfBirth,svnr,nationality\nagov.unitExtId: 1000\n\
- agov.level100.roleExtid: aee52e9f-7084-4e55-9aea-9383ac7757f7\n"
+ value: |
+ client.name: agov
+ attributes: loginId,extId,firstName,name,email,gender,birthDate,language,sex,addressLine1,postalCode,city,country,street,houseNumber,locality,mobile
+ properties: eIdNumber,placeOfBirth,svnr,nationality
+ agov.unitExtId: 1000
+ agov.level100.roleExtid: aee52e9f-7084-4e55-9aea-9383ac7757f7
requireOverloading: false
fido-session-store-database-host:
className: "ch.nevis.admin.v4.plugin.base.generation.property.HostPortProperty"
@@ -811,11 +822,12 @@ variables:
parameters:
required: false
syntax: "YAML"
- value: "issuer: https://me.agov-d.azure.adnovum.net/saml2/service-provider-metadata/agovidp\n\
- agovmedirecturl: https://me.agov-d.azure.adnovum.net/account/api/login/saml2/sso/agovidpdirect\n\
- directAudience: https://me.agov-d.azure.adnovum.net/account/api/saml2/service-provider-metadata/agovidpdirect\n\
- consumerURL: https://me.agov-d.azure.adnovum.net/login/saml2/sso/agovidp\nassertionValidityTime:\
- \ 20"
+ value: |-
+ issuer: https://me.agov-d.azure.adnovum.net/saml2/service-provider-metadata/agovidp
+ agovmedirecturl: https://me.agov-d.azure.adnovum.net/account/api/login/saml2/sso/agovidpdirect
+ directAudience: https://me.agov-d.azure.adnovum.net/account/api/saml2/service-provider-metadata/agovidpdirect
+ consumerURL: https://me.agov-d.azure.adnovum.net/login/saml2/sso/agovidp
+ assertionValidityTime: 20
requireOverloading: true
sts_saml-template-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
@@ -853,7 +865,9 @@ variables:
parameters:
required: false
syntax: "YAML"
- value: "client.name: AGOV-S\nattributes: loginId,extId\n"
+ value: |
+ client.name: AGOV-S
+ attributes: loginId,extId
requireOverloading: true
virtual_host-frontend-addresses:
className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"