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"