diff --git a/patterns/1f0702aaabef60a615abf41f_resources/resources.zip b/patterns/1f0702aaabef60a615abf41f_resources/resources.zip
index 6a75363..d6e5de4 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 a7d7c14..e28691b 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 38b8d20..06a0a69 100644
Binary files a/patterns/204c22beaccdfd22727af378_template/webdata.zip and b/patterns/204c22beaccdfd22727af378_template/webdata.zip differ
diff --git a/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua b/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua
new file mode 100644
index 0000000..e685e93
--- /dev/null
+++ b/patterns/3a982aa242ff4f8ebd823693_script/countries_security_filter.lua
@@ -0,0 +1,42 @@
+package.path = package.path .. ";/opt/nevisproxy/webapp/WEB-INF/lib/lua/Utils.lua"
+local Utils = require "Utils"
+
+function inputHeader(request, response)
+ local trace = request:getTracer()
+
+ local queryParams = Utils.getQueryParameters(request)
+ local path = request:getRequestPath()
+
+ -- only allow calls to the countries service
+ if path == nil then
+ trace:error("path is nil")
+ end
+
+ if path ~= nil and path ~= '/resource/utility/api/v1/countries' then
+ trace:info("utility service called with invalid path " .. request:getRequestPath())
+ response:send(404)
+ return
+ end
+
+ -- only alloq one query-parameter 'lang' with the values DE, FR, IT, EN, RS
+ for param, values in pairs(queryParams) do
+ if (param ~= 'lang') then
+ trace:info("utility service called with invalid query param " .. param)
+ response:send(404)
+ return
+ end
+ if Helpers.tableLength(values) ~= 1 then
+ trace:info("utility service called with invalid value for query param " .. param)
+ response:send(404)
+ return
+ end
+ for i, value in pairs(values) do
+ local lang = string.upper(value)
+ if not ('DE' == lang or 'FR' == lang or 'IT' == lang or 'EN' == lang or 'RS' == lang) then
+ trace:info("utility service called with invalid value for query param " .. param .. "=" .. value)
+ response:send(404)
+ return
+ end
+ end
+ end
+end
diff --git a/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip b/patterns/4fcfadb4a5c946ead7e6e995_labels/labels.zip
index a7d7c14..e28691b 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 38b8d20..06a0a69 100644
Binary files a/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip and b/patterns/4fcfadb4a5c946ead7e6e995_template/webdata.zip differ
diff --git a/patterns/584964c837512845d7940809_authStatesFile/recovery-preprocessing.xml b/patterns/584964c837512845d7940809_authStatesFile/recovery-preprocessing.xml
index 2d2cd26..4ec3281 100644
--- a/patterns/584964c837512845d7940809_authStatesFile/recovery-preprocessing.xml
+++ b/patterns/584964c837512845d7940809_authStatesFile/recovery-preprocessing.xml
@@ -193,11 +193,12 @@
-
+
-
-
+
+
+
@@ -209,6 +210,7 @@
+
@@ -220,6 +222,11 @@
+
+
+
+
+
diff --git a/patterns/584964c837512845d7940809_resources/recovery-preprocessing.groovy b/patterns/584964c837512845d7940809_resources/recovery-processing.groovy
similarity index 96%
rename from patterns/584964c837512845d7940809_resources/recovery-preprocessing.groovy
rename to patterns/584964c837512845d7940809_resources/recovery-processing.groovy
index 9c0733c..e7d096d 100644
--- a/patterns/584964c837512845d7940809_resources/recovery-preprocessing.groovy
+++ b/patterns/584964c837512845d7940809_resources/recovery-processing.groovy
@@ -1,192 +1,191 @@
-import org.codehaus.groovy.runtime.StackTraceUtils
-import groovy.xml.XmlSlurper
-
-
-// AGOVaq conversion
-def maxLoiRoleToCtxClssConvertorMap = [
- "level100": "urn:qa.agov.ch:names:tc:ac:classes:100",
- "level200": "urn:qa.agov.ch:names:tc:ac:classes:200",
- "level300": "urn:qa.agov.ch:names:tc:ac:classes:300",
- "level400": "urn:qa.agov.ch:names:tc:ac:classes:400",
- "level500": "urn:qa.agov.ch:names:tc:ac:classes:500"
-]
-
-def getUserIdVerificationForRecovery(currentLoaRole) {
- // application is AGOV-AccountStatus
- def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
- def result = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-AccountStatus,mustRecover'}?.value?.text()
-
- if (!result) {
- // fallback if not explicitly set
- def chDomicile = list.country.text() == 'ch'
- def lastIdVerification = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + currentLoaRole}?.value?.text() ?: 'missing'
- switch (currentLoaRole) {
- case 'level100':
- result = chDomicile ? 'SimpleLetter' : 'Video'
- break
- case 'level200':
- result = chDomicile ? 'Bmid' : 'Video'
- break
- case 'level300':
- case 'level400':
- result = chDomicile ? lastIdVerification : 'Video'
- break
- default:
- LOG.warn("unexpected loa on account: ${currentLoaRole}")
- // safest default, should work in any case
- result = 'Video'
- }
- LOG.warn("Recovery method not set, choosing ${result} (based on currentLoad: ${currentLoaRole}, CH-domicile: ${chDomicile}, last verification method: ${lastIdVerification})")
- }
- return result
-}
-
-def getAqLevelBasedOnIdVerificationForRecovery(idVerification, highestRoleLevel) {
- def result = 'level'
-
- switch (idVerification) {
- case 'None':
- result = result.concat('100')
- break
- case 'SimpleLetter':
- result = result.concat('200')
- break
- case 'Video':
- case 'VideoSelfPaid':
- case 'Bmid':
- case 'BmidSelfPaid':
- case 'Counter':
- result = result.concat((highestRoleLevel == 'level400') ? '400' : '300')
- break
- default:
- LOG.warn("unexpected idVerification for recovery on account: ${idVerification}")
- // safest default, should work in any case
- result = highestRoleLevel
- }
-
- return result
-}
-
-def getUserMustRecoverValidFrom() {
- // set attibutes from DTO: -> validFrom
- def payload = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
- def authzNode = payload.'**'.find {node -> node.name() == 'authorizations' && node.role.name.text() == 'mustRecover'}
- return (authzNode) ? ((authzNode.validFrom && !authzNode.validFrom.text().isEmpty()) ? authzNode.validFrom?.text() : authzNode.ctlCreDat?.text()) : ''
-}
-
-
-// for autditing
-def user = session['ch.adnovum.nevisidm.user.extId'] ?: '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'
-def maxLoi = null
-
-
-// new
-if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null) {
- try {
- def userDto = new XmlSlurper().parseText(session['ch.adnovum.nevisidm.userDto'])
- def userState = userDto.state
- LOG.debug("Recovery: Dto is '${userDto}")
- LOG.debug("Recovery: state is '${userState}")
- def session = request.getAuthSession(true)
-
- if (userState == 'ACTIVE') {
-
- session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recovery')
-
- def maxLoiList = userDto.'**'.findAll { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-Loi' }.collect({ node -> node.name.text() })
- maxLoi = (maxLoiList == null || maxLoiList.isEmpty()) ? null : maxLoiList.sort().last()
-
- def idVerification = null
- def agovAqValidFrom = null
- if (maxLoi) {
- idVerification = userDto.'**'.find { node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + maxLoi}?.value?.text()
- idVerification = idVerification ?: 'None'
- agovAqValidFrom = userDto.'**'.find { node -> node.name() == 'authorizations' && node.role.name.text() == maxLoi}?.validFrom?.text()
- agovAqValidFrom = agovAqValidFrom?: userDto.'**'.find { node -> node.name() == 'authorizations' && node.role.name.text() == maxLoi}?.ctlCreDat?.text()
- }
-
- def mustRecover = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'mustRecover' }
-
- def hasRecoveryRole = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'recovery' }
-
-
- if (mustRecover) {
- // attributes are defined over the mustRecover authorization
- session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:mustRecover')
-
- idVerification = getUserIdVerificationForRecovery(maxLoi ?: 'level100') ?: idVerification
-
- agovAqValidFrom = getUserMustRecoverValidFrom()
-
- maxLoi = getAqLevelBasedOnIdVerificationForRecovery(idVerification, maxLoi)
- }
-
- LOG.debug("Recovery: MaxLoi is '${maxLoi}'")
- LOG.debug("Recovery: IdVerification is ${idVerification}")
- LOG.debug("Recovery: agovAqValidFrom is ${agovAqValidFrom}")
- LOG.debug("Recovery: mustRecover is '${mustRecover}'")
- LOG.debug("Recovery: hasRecoveryRole is '${hasRecoveryRole}'")
-
- if (maxLoi != null) {
- if (maxLoiRoleToCtxClssConvertorMap.containsKey(maxLoi)) {
- LOG.debug("Recovery: MaxLoiMapping is " + maxLoiRoleToCtxClssConvertorMap[maxLoi])
- response.setSessionAttribute('agov.recovery.currentAgovAq', '' + maxLoiRoleToCtxClssConvertorMap[maxLoi])
- response.setSessionAttribute('agov.recovery.currentIdVerification', '' + idVerification)
- response.setSessionAttribute('agov.recovery.currentAgovAqRoleValidFrom', '' + agovAqValidFrom)
-
- if ((maxLoi == 'level100') && (mustRecover == null)) {
- // mustRecover role not set, so code needs to be checked
- LOG.debug("Recovery: emailAndCode")
- response.setSessionAttribute('agov.recovery.authenticatedWith', 'urn:qa.agov.ch:names:tc:authfactor:emailAndCode')
- response.setResult('needCode')
- return
- } else {
- LOG.debug("Recovery: email")
- response.setSessionAttribute('agov.recovery.authenticatedWith', 'urn:qa.agov.ch:names:tc:authfactor:email')
- response.setResult('ok')
- return
- }
-
- } else {
- LOG.error("Recovery: Failed to convert '${maxLoi}' to AGOVaq")
- response.setResult('error')
- return
- }
- } else {
- // maxLoi is null
- LOG.debug("Recovery: no 'AGOV-Loi'-role assigned to user ${user}")
- if ((hasRecoveryRole != null) && (mustRecover == null)) {
- response.setResult('notFullyRegistered')
- return
- } else {
- LOG.error("Recovery: no 'AGOV-Loi'-role assigned to user ${user} and no recovery role ")
- response.setResult('error')
- return
- }
- }
- } else {
- // state != ACTIVE and no lasterror should not happen
- LOG.error("Recovery: state='${userState}' but not lasterror set")
- response.setNote('lasterror', '9909')
- response.setNote('lasterrorinfo', 'internal error')
- response.setResult('error')
- return
- }
- } catch (Exception e) {
- e = StackTraceUtils.sanitize(e)
- def affectedLines = e.stackTrace.findAll { it.className.startsWith('Script') }.collect { "${it.methodName}:${it.lineNumber}" }
- LOG.error("FATAL: Recovery processing failed (at lines: ${affectedLines})", e)
- response.setNote('lasterror', '9909')
- response.setNote('lasterrorinfo', 'internal error')
- response.setResult('error')
- return
- }
-}
-
-LOG.error("Recovery: userDto missing or failure before (lasterror='${notes.getProperty('lasterror', '-')}')")
-response.setNote('lasterror', '9909')
-response.setNote('lasterrorinfo', 'internal error')
-response.setResult('error')
-return
+import org.codehaus.groovy.runtime.StackTraceUtils
+import groovy.xml.XmlSlurper
+
+
+// AGOVaq conversion
+def maxLoiRoleToCtxClssConvertorMap = [
+ "level100": "urn:qa.agov.ch:names:tc:ac:classes:100",
+ "level200": "urn:qa.agov.ch:names:tc:ac:classes:200",
+ "level300": "urn:qa.agov.ch:names:tc:ac:classes:300",
+ "level400": "urn:qa.agov.ch:names:tc:ac:classes:400",
+ "level500": "urn:qa.agov.ch:names:tc:ac:classes:500"
+]
+
+def getUserIdVerificationForRecovery(currentLoaRole) {
+ // application is AGOV-AccountStatus
+ def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
+ def result = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-AccountStatus,mustRecover'}?.value?.text()
+
+ if (!result) {
+ // fallback if not explicitly set
+ def chDomicile = list.country.text() == 'ch'
+ def lastIdVerification = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + currentLoaRole}?.value?.text() ?: 'missing'
+ switch (currentLoaRole) {
+ case 'level100':
+ result = chDomicile ? 'SimpleLetter' : 'Video'
+ break
+ case 'level200':
+ result = chDomicile ? 'Bmid' : 'Video'
+ break
+ case 'level300':
+ case 'level400':
+ result = chDomicile ? lastIdVerification : 'Video'
+ break
+ default:
+ LOG.warn("unexpected loa on account: ${currentLoaRole}")
+ // safest default, should work in any case
+ result = 'Video'
+ }
+ LOG.warn("Recovery method not set, choosing ${result} (based on currentLoad: ${currentLoaRole}, CH-domicile: ${chDomicile}, last verification method: ${lastIdVerification})")
+ }
+ return result
+}
+
+def getAqLevelBasedOnIdVerificationForRecovery(idVerification, highestRoleLevel) {
+ def result = 'level'
+
+ switch (idVerification) {
+ case 'None':
+ result = result.concat('100')
+ break
+ case 'SimpleLetter':
+ result = result.concat('200')
+ break
+ case 'Video':
+ case 'VideoSelfPaid':
+ case 'Bmid':
+ case 'BmidSelfPaid':
+ case 'Counter':
+ result = result.concat((highestRoleLevel == 'level400') ? '400' : '300')
+ break
+ default:
+ LOG.warn("unexpected idVerification for recovery on account: ${idVerification}")
+ // safest default, should work in any case
+ result = highestRoleLevel
+ }
+
+ return result
+}
+
+def getUserMustRecoverValidFrom() {
+ // set attibutes from DTO: -> validFrom
+ def payload = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
+ def authzNode = payload.'**'.find {node -> node.name() == 'authorizations' && node.role.name.text() == 'mustRecover'}
+ return (authzNode) ? ((authzNode.validFrom && !authzNode.validFrom.text().isEmpty()) ? authzNode.validFrom?.text() : authzNode.ctlCreDat?.text()) : ''
+}
+
+
+// for autditing
+def user = session['ch.adnovum.nevisidm.user.extId'] ?: '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'
+def maxLoi = null
+
+
+// new
+if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null) {
+ try {
+ def userDto = new XmlSlurper().parseText(session['ch.adnovum.nevisidm.userDto'])
+ def userState = userDto.state
+ LOG.debug("Recovery: Dto is '${userDto}")
+ LOG.debug("Recovery: state is '${userState}")
+ def session = request.getAuthSession(true)
+
+ if (userState == 'ACTIVE') {
+
+ session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recovery')
+ session.setAttribute('agov.recovery.authenticatedWith', 'urn:qa.agov.ch:names:tc:authfactor:email')
+
+ def maxLoiList = userDto.'**'.findAll { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-Loi' }.collect({ node -> node.name.text() })
+ maxLoi = (maxLoiList == null || maxLoiList.isEmpty()) ? null : maxLoiList.sort().last()
+
+ def idVerification = null
+ def agovAqValidFrom = null
+ if (maxLoi) {
+ idVerification = userDto.'**'.find { node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + maxLoi}?.value?.text()
+ idVerification = idVerification ?: 'None'
+ agovAqValidFrom = userDto.'**'.find { node -> node.name() == 'authorizations' && node.role.name.text() == maxLoi}?.validFrom?.text()
+ agovAqValidFrom = agovAqValidFrom?: userDto.'**'.find { node -> node.name() == 'authorizations' && node.role.name.text() == maxLoi}?.ctlCreDat?.text()
+ }
+
+ def mustRecover = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'mustRecover' }
+
+ def hasRecoveryRole = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'recovery' }
+
+
+ if (mustRecover) {
+ // attributes are defined over the mustRecover authorization
+ session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:mustRecover')
+
+ idVerification = getUserIdVerificationForRecovery(maxLoi ?: 'level100') ?: idVerification
+
+ agovAqValidFrom = getUserMustRecoverValidFrom()
+
+ maxLoi = getAqLevelBasedOnIdVerificationForRecovery(idVerification, maxLoi)
+ }
+
+ LOG.debug("Recovery: MaxLoi is '${maxLoi}'")
+ LOG.debug("Recovery: IdVerification is ${idVerification}")
+ LOG.debug("Recovery: agovAqValidFrom is ${agovAqValidFrom}")
+ LOG.debug("Recovery: mustRecover is '${mustRecover}'")
+ LOG.debug("Recovery: hasRecoveryRole is '${hasRecoveryRole}'")
+
+ if (maxLoi != null) {
+ if (maxLoiRoleToCtxClssConvertorMap.containsKey(maxLoi)) {
+ LOG.debug("Recovery: MaxLoiMapping is " + maxLoiRoleToCtxClssConvertorMap[maxLoi])
+ response.setSessionAttribute('agov.recovery.currentAgovAq', '' + maxLoiRoleToCtxClssConvertorMap[maxLoi])
+ response.setSessionAttribute('agov.recovery.currentIdVerification', '' + idVerification)
+ response.setSessionAttribute('agov.recovery.currentAgovAqRoleValidFrom', '' + agovAqValidFrom)
+
+ if ((maxLoi == 'level100') && (mustRecover == null)) {
+ // mustRecover role not set, so code needs to be checked
+ LOG.debug("Recovery: emailAndCode")
+ response.setResult('needCode')
+ return
+ } else {
+ LOG.debug("Recovery: email")
+ response.setResult('ok')
+ return
+ }
+
+ } else {
+ LOG.error("Recovery: Failed to convert '${maxLoi}' to AGOVaq")
+ response.setResult('error')
+ return
+ }
+ } else {
+ // maxLoi is null
+ LOG.debug("Recovery: no 'AGOV-Loi'-role assigned to user ${user}")
+ if ((hasRecoveryRole != null) && (mustRecover == null)) {
+ response.setResult('notFullyRegistered')
+ return
+ } else {
+ LOG.error("Recovery: no 'AGOV-Loi'-role assigned to user ${user} and no recovery role ")
+ response.setResult('error')
+ return
+ }
+ }
+ } else {
+ // state != ACTIVE and no lasterror should not happen
+ LOG.error("Recovery: state='${userState}' but not lasterror set")
+ response.setNote('lasterror', '9909')
+ response.setNote('lasterrorinfo', 'internal error')
+ response.setResult('error')
+ return
+ }
+ } catch (Exception e) {
+ e = StackTraceUtils.sanitize(e)
+ def affectedLines = e.stackTrace.findAll { it.className.startsWith('Script') }.collect { "${it.methodName}:${it.lineNumber}" }
+ LOG.error("FATAL: Recovery processing failed (at lines: ${affectedLines})", e)
+ response.setNote('lasterror', '9909')
+ response.setNote('lasterrorinfo', 'internal error')
+ response.setResult('error')
+ return
+ }
+}
+
+LOG.error("Recovery: userDto missing or failure before (lasterror='${notes.getProperty('lasterror', '-')}')")
+response.setNote('lasterror', '9909')
+response.setNote('lasterrorinfo', 'internal error')
+response.setResult('error')
+return
diff --git a/patterns/9ff0369f3cf662f95d94ff09_resources/ensureRecoveryCode.groovy b/patterns/9ff0369f3cf662f95d94ff09_resources/ensureRecoveryCode.groovy
index 22f8a61..b147744 100644
--- a/patterns/9ff0369f3cf662f95d94ff09_resources/ensureRecoveryCode.groovy
+++ b/patterns/9ff0369f3cf662f95d94ff09_resources/ensureRecoveryCode.groovy
@@ -30,14 +30,22 @@ String endPoint = "${parameters.get('utility-service.baseUrl')}/api/v1/recovery/
def userDto = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
def recoveryCredential = userDto.'**'.find {node -> node.name() == 'credentials' && node.type.text() == 'CONTEXT_PASSWORD' && node.context.text() == 'RECOVERY'}
-// 1a) check if user has a credential
+// Only for aq 100, skip for the rest
+if (Arrays.stream(response.getActualRoles()).filter( r -> r.matches('^.*AGOV-Loi\\.level[2345]00.*$')).findAny().isPresent()) {
+ LOG.debug("Account '${user}' has a higher AQ-level than 100, no need to check code")
+ response.setResult('done')
+ return
+}
+
+
+// 1b) check if user has a credential
if ( recoveryCredential != null ) {
LOG.debug("Account '${user}' has an active recovery code, no need to create new code")
response.setResult('done')
return
}
-// 1b) check if a recovery is ongoing (nothing to do)
+// 1c) check if a recovery is ongoing (nothing to do)
if (Arrays.stream(response.getActualRoles()).filter( r -> r.contains('AGOV-AccountStatus.recovery')).findAny().isPresent()) {
LOG.debug("Account '${user}' is in recovery, no need to create new code")
response.setResult('done')
diff --git a/patterns/Fetch_Country_Name_594764b3b866d7855f6990a1.yml b/patterns/Fetch_Country_Name_594764b3b866d7855f6990a1.yml
index 46cfa5c..878a345 100644
--- a/patterns/Fetch_Country_Name_594764b3b866d7855f6990a1.yml
+++ b/patterns/Fetch_Country_Name_594764b3b866d7855f6990a1.yml
@@ -3,6 +3,7 @@ pattern:
id: "594764b3b866d7855f6990a1"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "Fetch_Country_Name"
+ notes: "TODO/haburger/2024-12-17: replace this with a call to http://utility-application-be.adn-agov-me-01-dev:8081/utility/api/v1/countries?lang=DE"
properties:
authStatesFile: "res://594764b3b866d7855f6990a1#authStatesFile"
onSuccess:
diff --git a/patterns/Utility_Resource_Service_Countries_Security_Filter_3a982aa242ff4f8ebd823693.yml b/patterns/Utility_Resource_Service_Countries_Security_Filter_3a982aa242ff4f8ebd823693.yml
new file mode 100644
index 0000000..31486b2
--- /dev/null
+++ b/patterns/Utility_Resource_Service_Countries_Security_Filter_3a982aa242ff4f8ebd823693.yml
@@ -0,0 +1,7 @@
+schemaVersion: "1.0"
+pattern:
+ id: "3a982aa242ff4f8ebd823693"
+ className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.LuaPattern"
+ name: "Utility_Resource_Service_Countries_Security_Filter"
+ properties:
+ script: "res://3a982aa242ff4f8ebd823693#script"
diff --git a/patterns/Utility_Resource_Service_eaa622e2a760704c1e0e22f2.yml b/patterns/Utility_Resource_Service_eaa622e2a760704c1e0e22f2.yml
new file mode 100644
index 0000000..0ecbc51
--- /dev/null
+++ b/patterns/Utility_Resource_Service_eaa622e2a760704c1e0e22f2.yml
@@ -0,0 +1,13 @@
+schemaVersion: "1.0"
+pattern:
+ id: "eaa622e2a760704c1e0e22f2"
+ className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.RESTServiceAccess"
+ name: "Utility_Resource_Service"
+ properties:
+ host:
+ - "pattern://1f0702aaabef60a615abf41f"
+ path: "/resource/utility/"
+ addons:
+ - "pattern://3a982aa242ff4f8ebd823693"
+ backends: "var://utility_resource_service-backend-address"
+ allowedMethods: "GET"
diff --git a/variables.yml b/variables.yml
index 9ad399f..48e3de7 100644
--- a/variables.yml
+++ b/variables.yml
@@ -965,6 +965,17 @@ variables:
minRequired: 0
value: null
requireOverloading: true
+ utility_resource_service-backend-address:
+ className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"
+ parameters:
+ minRequired: 1
+ schemeInputMode: "OPTIONAL"
+ allowedSchemes: "http,https"
+ hostNameInputMode: "REQUIRED"
+ portInputMode: "OPTIONAL"
+ pathInputMode: "OPTIONAL"
+ value: "http://utility-application-be.adn-agov-me-01-dev:8081/utility/"
+ requireOverloading: true
verify_shadow_user-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters: