12 files added, 25 files updated and 7 files deleted

This commit is contained in:
haburger 2025-06-30 15:28:13 +00:00
parent 81f13bf166
commit 991bfbd7c3
74 changed files with 1115 additions and 761 deletions

View File

@ -119,6 +119,7 @@ try {
if (adressVerificationList && !adressVerificationList.isEmpty()) {
adressVerification = adressVerificationList[0]
}
def authenticationMethod = session.get('authenticatedWith')
LOG.debug('CheckLoa: Requested role level '+ requestedRoleLevelNumber)
LOG.debug('CheckLoa: idVerification: ' + getUserAGOVLoiIdVerification())
@ -160,17 +161,17 @@ try {
session.setAttribute('ch.nevis.idm.User.gender', '3')
}
for (String role : getUserAGOVLoiRoles()) {
if (role.startsWith('level')) {
def roleLevel = role.substring(5)
int roleLevelNumber = Integer.parseInt(roleLevel)
if (role.startsWith('level')) {
def roleLevel = role.substring(5)
int roleLevelNumber = Integer.parseInt(roleLevel)
if (highestRoleLevelNumber< roleLevelNumber) {
highestRoleLevelNumber=roleLevelNumber
}
}
}
if (highestRoleLevelNumber< roleLevelNumber) {
highestRoleLevelNumber=roleLevelNumber
}
}
}
LOG.debug('CheckLoa: Highest role Level ' + highestRoleLevelNumber.toString() +' contextclassref ' + requestedRoleLevelNumber.toString())
LOG.debug('CheckLoa: Compare ' + (highestRoleLevelNumber>=requestedRoleLevelNumber))

View File

@ -0,0 +1,30 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="noChange" next="${state.entry}_UpdateLoginInfo"/>
<ResultCond name="audited" next="${state.entry}_NotifyUser"/>
<ResultCond name="error" next="${state.failed}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_compare_and_update_idm_attributes.groovy"/>
<property name="parameter.baseUrl" value="${var.eid.idm.rest.baseUrl}" />
<property name="parameter.clientExtId" value="${var.eid.idm.rest.clientExtId}" />
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
</AuthState>
<AuthState name="${state.entry}_NotifyUser" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="ok" next="${state.entry}_UpdateLoginInfo"/>
<ResultCond name="error" next="${state.failed}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_notify_user_idm_change.groovy"/>
<property name="parameter.baseUrl" value="${var.eid.idm.rest.baseUrl}" />
<property name="parameter.clientExtId" value="${var.eid.idm.rest.clientExtId}" />
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
</AuthState>
<AuthState name="${state.entry}_UpdateLoginInfo" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="error" next="${state.failed}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_update_login_info.groovy"/>
<property name="parameter.baseUrl" value="${var.eid.idm.rest.baseUrl}" />
<property name="parameter.clientExtId" value="${var.eid.idm.rest.clientExtId}" />
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
</AuthState>

View File

@ -0,0 +1,158 @@
import java.text.SimpleDateFormat
import groovy.text.SimpleTemplateEngine
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
def getDateWithoutTimestamp(String date){
def result = date
if(date.matches('^[0-9-]+[+]{1}.*')){
result = date.replaceAll('[+]{1}.*', "")
}
return result
}
// NOTE/aca/2025/06/19: We could also reload the data from idm after the update instead of updating the session variables manualy -> probably better and less error-prone
def compareAndUpdateSessionVariables(sess, keys, isProperty){
def updatedKeys = []
for(key in keys){
def idmkey = isProperty ? "ch.nevis.idm.User.prop.$key" : "ch.nevis.idm.User.$key"
def eidValue = session["agov.eid.User.$key"] ?: ""
def idmValue = session[idmkey] ?: ""
if(!idmValue || eidValue != idmValue){
sess.setAttribute(idmkey, eidValue)
updatedKeys.add(key)
}
}
return updatedKeys
}
String user_update_dto_template = '''
{
"name": {
"firstName": "$firstName",
"familyName": "$familyName"
},
"properties": {
"svnr": "$svnr",
"placeOfBirth": "$placeOfBirth",
"nationality": "$nationality",
"eIdNumber": "$eIdNumber"
},
"gender": "$gender",
"birthDate": "$birthDate",
"modificationComment": "updated user information with eid attributes during request $request"
}
'''
// 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['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'
def sess = request.getAuthSession(true)
// Convert EID gender format to IDM
if(sess.get('agov.eid.User.gender') == '1'){
sess.setAttribute('agov.eid.User.gender', 'MALE')
}
if(sess.get('agov.eid.User.gender') == '2'){
sess.setAttribute('agov.eid.User.gender', 'FEMALE')
}
if(sess.get('agov.eid.User.gender') == '3'){
sess.setAttribute('agov.eid.User.gender', 'OTHER')
}
// Compare eid and idm attributes + update idm session variables if they differ
def attributesToAudit = compareAndUpdateSessionVariables(sess, ["firstName", "lastName", "gender"], false)
// NOTE/aca/2025/06/14/: Potentally Throw a DATA ERROR if the properties are different? -> should the svnr number ever change?
def propertiesToAudit = compareAndUpdateSessionVariables(sess, ["svnr", "eIdNumber", "nationality", "placeOfBirth"], true)
// Handle birthdate seperately, since it can contain a timestamp -> we probably don't want to update if only the timestamp is wrong
String eidBirthdate = getDateWithoutTimestamp(session["agov.eid.User.birthDate"] ?: "")
String idmBirthdate = getDateWithoutTimestamp(session["ch.nevis.idm.User.birthDate"] ?: "")
LOG.debug("eidBirthdate: $eidBirthdate idmBirthdate: $idmBirthdate")
if(eidBirthdate != idmBirthdate){
sess.setAttribute("ch.nevis.idm.User.birthDate", eidBirthdate)
// For some reson IdmGetPropertyState uses a different date format than IdmSetPropertyState?
//def date = new SimpleDateFormat('yyyy-MM-dd').parse(eidBirthdate)
//def idmFromatedBirthDate = new SimpleDateFormat('dd.MM.yyyy').format(date)
//sess.setAttribute("ch.nevis.idm.User.birthDate.idmFormat", idmFromatedBirthDate)
attributesToAudit.add("birthDate")
}
// Check if we need to update IDM
def auditedRequired = attributesToAudit.size() > 0 || propertiesToAudit.size() > 0
if(auditedRequired){
// update attributes in idm & transition to User notification
IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)
String baseUrl = parameters.get("baseUrl")
String clientExtId = parameters.get("clientExtId")
String endPoint = "$baseUrl/api/core/v1"
String userExtId = sess.getAttribute("ch.nevis.idm.User.extId")
String requestUrl = "$endPoint/$clientExtId/users/$userExtId"
def binding = [
"firstName": sess.getAttribute('agov.eid.User.firstName'),
"familyName": sess.getAttribute('agov.eid.User.lastName'),
"svnr": sess.getAttribute('agov.eid.User.svnr'),
"placeOfBirth": sess.getAttribute('agov.eid.User.placeOfBirth'),
"nationality": sess.getAttribute('agov.eid.User.nationality'),
"eIdNumber": sess.getAttribute('agov.eid.User.eIdNumber'),
"gender": sess.getAttribute('agov.eid.User.gender').toLowerCase(),
"birthDate": sess.getAttribute('agov.eid.User.birthDate'),
"request": requestId
]
def templateEngine = new SimpleTemplateEngine()
def userUpdateDto = templateEngine.createTemplate(user_update_dto_template).make(binding).toString()
try {
idmRestClient.patch(requestUrl, userUpdateDto)
}catch(Exception e) {
LOG.error("Failed to update User data in IDM: ${e}")
LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Failed to update User data in IDM'")
response.setResult('error')
return
}
String printKeys = attributesToAudit.toListString()
LOG.debug("AuditedAttributes: $printKeys")
// Transform gender back to number
if(sess.get('ch.nevis.idm.User.gender') == 'MALE'){
sess.setAttribute('ch.nevis.idm.User.gender', '1')
}
if(sess.get('ch.nevis.idm.User.gender') == 'FEMALE'){
sess.setAttribute('ch.nevis.idm.User.gender', '2')
}
if(sess.get('ch.nevis.idm.User.gender') == 'OTHER'){
sess.setAttribute('ch.nevis.idm.User.gender', '3')
}
response.setResult('audited')
}else{
// Attributes match & no notification needed => continue by updating the linking credential and sending the saml assertion
// NOTE/aca/2025/06/19: We skip checking the account state, recovery code, mobile number and LoA
LOG.debug("No Audit Required: Logging user in")
response.setResult('noChange')
}

View File

@ -0,0 +1,38 @@
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
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

View File

@ -0,0 +1,36 @@
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
String login_info_update_dto = '''
{
"success": true,
"credentialExtId": "{{credentialExtId}}"
}
'''
IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)
def sess = request.getAuthSession(true)
String baseUrl = parameters.get("baseUrl")
String clientExtId = parameters.get("clientExtId")
String endPoint = "$baseUrl/api/core/v1"
String userExtId = sess.getAttribute("ch.nevis.idm.User.extId")
String linkingCredentialExtId = sess.getAttribute("agov.eid.linkingCredentialExtId")
String requestUrl = "$endPoint/$clientExtId/users/$userExtId/login-info"
String restRequest = login_info_update_dto.replaceAll("\\{\\{credentialExtId}}", linkingCredentialExtId)
try {
idmRestClient.post(requestUrl, restRequest)
}catch(Exception e) {
LOG.error("Failed to Update Linking Credential info: ${e}")
response.setResult('error')
return
}
response.setResult('ok')
return

View File

@ -0,0 +1,7 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.standard.AuthGeneric" final="false">
<Response value="AUTH_CONTINUE">
<Gui name="Eid_Placeholder" label="eID Placeholder">
<GuiElem name="infotext" type="info" label="${session:eid.placeholder.text}"/>
</Gui>
</Response>
</AuthState>

View File

@ -0,0 +1,39 @@
import groovy.json.JsonSlurper
import io.opentelemetry.api.trace.Span
def sess = request.getAuthSession(true)
def spanCtxt = Span.current().getSpanContext()
def traceparent = "00-${spanCtxt.getTraceId()}-${spanCtxt.getSpanId()}-${spanCtxt.getTraceFlags().asHex()}"
def jsonSlurper = new JsonSlurper()
def lang = (session['ch.nevis.idm.User.language']?:'DE').trim()
def endppoint = "${parameters.get('baseurl')}/api/v1/countries?lang=${lang.toUpperCase()}"
def countryCode = (session['ch.nevis.idm.User.country']?:'CH').trim().toLowerCase()
try {
LOG.debug("UTILITY: Countries: Request url: ${endppoint}")
def httpClient = HttpClients.create(parameters)
def httpResponse = Http.get().url(endppoint).header('traceparent', traceparent).build().send(httpClient)
LOG.debug('UTILITY: Countries: Response Message: ' + httpResponse.reasonPhrase())
LOG.debug('UTILITY: Countries: Response Status Code: ' + httpResponse.code())
LOG.debug('UTILITY: Countries: Response: ' + httpResponse.bodyAsString())
if (httpResponse.code() == 200) {
def json = jsonSlurper.parseText(httpResponse.bodyAsString())
// {"country.af":"Afghanistan","country.al":"Albanie"... }
def countryName = json["country.${countryCode}"]
LOG.debug("UTILITY: Countries: countryName for ${countryCode}: ${countryName}")
if (countryName) {
sess.setAttribute('agov.countryName', countryName)
}
} else {
LOG.warn("UTILITY: Countries: Failed to fetch country translations. (httpResponse.code: ${httpResponse.code()})")
}
} catch (Exception e) {
LOG.warn("UTILITY: Countries: Failed to fetch country translations. (${e})")
}
response.setResult('ok')

View File

@ -0,0 +1,31 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="noAccount" next="${state.exit.1}"/>
<ResultCond name="backToVerification" next="${state.exit.2}"/>
<ResultCond name="firstLogin" next="${state.entry}_NotifyUser"/>
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="error" next="${state.failed}"/>
<Response value="AUTH_CONTINUE">
<Gui name="eid_login_multiple_accounts">
<GuiElem name="accountEmail" type="hidden" value="UNKNOWN" optional="true"/>
<GuiElem name="login" type="submit" value="unknown" optional="true"/>
<GuiElem name="cancelEid" type="submit" value="unknown" optional="true"/>
</Gui>
</Response>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_fetch_linked_accounts.groovy"/>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="parameter.baseUrl" value="${var.eid.idm.rest.baseUrl}" />
<property name="parameter.clientExtId" value="${var.eid.idm.rest.clientExtId}" />
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
</AuthState>
<AuthState name="${state.entry}_NotifyUser" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="error" next="${state.failed}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_notify_user_first_login.groovy"/>
<property name="parameter.baseUrl" value="${var.eid.idm.rest.baseUrl}" />
<property name="parameter.clientExtId" value="${var.eid.idm.rest.clientExtId}" />
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
</AuthState>

View File

@ -0,0 +1,235 @@
import ch.nevis.esauth.auth.engine.AuthResponse
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
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
def map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER)
map.putAll(inctx)
return map['connection.HttpHeader.' + name]
}
def clearEidSession(){
def s = request.getAuthSession(true)
s.removeAttribute('agov.eid.verification')
s.removeAttribute('agov.eid.verification.id')
s.removeAttribute('agov.eid.verification.link')
s.removeAttribute('agov.eid.linkedAccountsDto')
s.removeAttribute('agov.eid.User.birthDate')
s.removeAttribute('agov.eid.User.eIdNumber')
s.removeAttribute('agov.eid.User.firstName')
s.removeAttribute('agov.eid.User.lastName')
s.removeAttribute('agov.eid.User.gender')
s.removeAttribute('agov.eid.User.nationality')
s.removeAttribute('agov.eid.User.placeOfBirth')
s.removeAttribute('agov.eid.User.svnr')
s.removeAttribute('agov.eid.User.origin')
}
def updateLoginHistory(idmRestClient, userExtId, credentialExtId) {
try {
def baseUrl = parameters.get("baseUrl")
def clientExtId = parameters.get("clientExtId")
def endpoint = "$baseUrl/api/core/v1/$clientExtId/users/$userExtId/login-info"
def dto = "{\"success\": true,\"credentialExtId\": \"${credentialExtId}\"}"
def postRequest = new HTTPRequestWrapper()
postRequest.addToHeaders('Content-Type', ['application/json'])
postRequest.setPayLoad(dto.getBytes('UTF-8'))
postRequest.setPayLoad(dto.getBytes('UTF-8'))
def result = idmRestClient.postWithResponse(endpoint, postRequest)
if (result.getStatusCode() != 200) {
// best effort, we log only
// TODO/haburger/2025-06-24: context parameters are missing here (also in getAccounts)
LOG.warn("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${userExtId}, CredentialType='E-ID Link', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='failed to update login history for credential ${credentialExtId} (http status: ${result.getStatusCode()})'")
}
} catch (Exception e) {
// best effort, we log only
// TODO/haburger/2025-06-24: context parameters are missing here (also in getAccounts)
LOG.warn("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${userExtId}, CredentialType='E-ID Link', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='failed to update login history for credential ${credentialExtId} (${e})'")
}
}
def getAccounts(json, String svnr) {
def idm_users_dto = json["Resources"]
def accounts = [:]
def frontend_dto = []
for(user in idm_users_dto){
def credentials_dto = user["urn:nevis:idm:scim:schemas:v1:extension:User"]["credentials"]
if(!credentials_dto){
LOG.warn("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${extId}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='AGOV account has no credentials'")
}
for(cred in credentials_dto){
def foundCredential = false
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(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]
}
// extract login info
def firstLogin = true
if(cred["credentialLoginInfo"]){
if(cred["credentialLoginInfo"]["lastLogin"] && cred["credentialLoginInfo"]["lastLogin"] != ""){
firstLogin = false
}
}
//NOTE/aca/2025/06/11: Assume that this is sanitized when registered.
def accountName = cred['subjectNameId']
def credentialExtId = cred['extId']
accounts.put(email, [ "extId": extId, "credentialExtId": cred['extId'], "firstLogin": firstLogin ] )
frontend_dto.add(["email": email, "description": accountName])
foundCredential=true
}
}
}
return [ accounts, [ "accounts": frontend_dto ] ]
}
def sess = request.getAuthSession(true)
IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)
// 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['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'
if(inargs['submit'] && inargs['login'] && inargs['login'] != ''){
LOG.debug("Account with email: ${inargs['login']} was selceted -> Continuing")
def accounts = new JsonSlurper().parseText(session['agov.eid.linkedAccountsDto'])
def account = accounts.get( inargs['login'].trim() )
sess.setAttribute('agov.eid.linkingCredentialExtId', account["credentialExtId"])
sess.setAttribute('agov.eid.linkedAccountExtId', account["extId"])
// update login history
updateLoginHistory(idmRestClient, account["extId"], account["credentialExtId"])
if(account["firstLogin"]){
response.setResult('firstLogin')
return
}
response.setResult('ok')
return
}
if(inargs['cancelEid'] && inargs['cancelEid'] == 'cancel'){
LOG.debug("Account selection was canceled: back to initial login screen")
clearEidSession()
response.setResult('backToVerification')
return
}
if(getHeader('Content-Type') == 'application/json'){
String account_selection_dto = session['agov.eid.linkedAccountsFrontendDto']
response.setContent(account_selection_dto.toString())
response.setContentType('application/json')
response.setHttpStatusCode(200)
response.setIsDirectResponse(true)
response.setStatus(AuthResponse.AUTH_CONTINUE)
return
}
String baseUrl = parameters.get("baseUrl")
String clientExtId = parameters.get("clientExtId")
String endPoint = "$baseUrl/api/scim/v1/$clientExtId/Users"
// Fetch account identifier
String svnr = sess.getAttribute("agov.eid.User.svnr")
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 requestUrl = "$endPoint?count=20&attributes=$attributes&filter=$filter"
String scimResponse
try {
scimResponse = idmRestClient.get(requestUrl)
//TODO/aca/2025/06/11: Fetch more pages if more than 20 entries have been found
LOG.debug("SCIM Response: $scimResponse")
def json = new JsonSlurper().parseText(scimResponse)
def (accounts, frontend_dto) = getAccounts(json, svnr)
// unrecoverable DATA ERROR happend
if(!accounts){
response.setResult('error')
return
}
def numAccounts = accounts.size()
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")
response.setResult('noAccount')
return
}else if(numAccounts == 1){
// One account found -> continue with loading attributes from idm (+ notification if it is the first login)
def account = accounts.values().first()
sess.setAttribute('agov.eid.linkingCredentialExtId', account["credentialExtId"])
sess.setAttribute('agov.eid.linkedAccountExtId', account["extId"])
// update login history
updateLoginHistory(idmRestClient, account["extId"], account["credentialExtId"])
if(account["firstLogin"]){
response.setResult('firstLogin')
return
}
response.setResult('ok')
return
}else{
// Multiple accounts found -> Dispatch the account selection screen
sess.setAttribute('agov.eid.linkedAccountsDto', new JsonBuilder(accounts).toString())
sess.setAttribute('agov.eid.linkedAccountsFrontendDto', new JsonBuilder(frontend_dto).toString())
LOG.debug("Show GUI")
response.setStatus(AuthResponse.AUTH_CONTINUE)
return
}
} catch(Exception e) {
LOG.error("Fetching Agov Accounts Failed: ${e}")
sess.setAttribute("eid.placeholder.text", "EId: An exception occured while fetching the AGOV accounts\n: ${e}")
response.setResult('error')
return
}

View File

@ -0,0 +1,38 @@
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
String user_notification_dto = '''
{
"clientExtId": "{{clientExtId}}",
"userExtId": "{{userExtId}}",
"notificationType": "userNotification4",
"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("agov.eid.linkedAccountExtId")
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: First Login: ${e}")
response.setResult('error')
return
}
response.setResult('ok')
return

View File

@ -197,7 +197,7 @@
<GuiElem name="submit" type="button" label="continue.button.label" value="go"/>
</Gui>
</Response>
<property name="parameter.baseUrl" value="${param.url:https://idm:8989/nevisidm}"/>
<property name="parameter.baseUrl" value="${var.idm-connection-fqdn}"/>
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="Recovery_Auth"/>
<property name="scriptTraceGroup" value="Recovery"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/recovery-processing.groovy"/>

View File

@ -1,20 +0,0 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.xml.DocumentProcessor" final="false" resumeState="false">
<ResultCond name="ok" next="${state.done}"/>
<!-- errors ignored, we transition anyway to done -->
<ResultCond name="nomatch" next="${state.done}"/>
<ResultCond name="validation-failed" next="${state.done}"/>
<ResultCond name="default" next="${state.done}"/>
<Response value="AUTH_ERROR"/>
<property name="sess:agov.countryName" value="xpath:/country-names/country[@code='${sess:ch.nevis.idm.User.country}']/@${sess:ch.nevis.idm.User.language}"/>
<property name="optional" value="sess:agov.countryName"/>
<property name="documentSourceType" value="RESOURCE"/>
<property name="documentSource" value="file:/var/opt/nevisauth/default/conf/countries.xml"/>
<!-- scheduler interval: only load it once, then we use it -->
<property name="scheduler.interval" value="-1"/>
<property name="maxAge" value="-1"/>
</AuthState>

View File

@ -1,250 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<country-names>
<country code="af" en="Afghanistan" de="Afghanistan" fr="Afghanistan" it="Afghanistan"/>
<country code="al" en="Albania" de="Albanien" fr="Albanie" it="Albania"/>
<country code="dz" en="Algeria" de="Algerien" fr="Algérie" it="Algeria"/>
<country code="as" en="American Samoa" de="Amerikanisch-Samoa" fr="Samoa américaines" it="Samoa Americane"/>
<country code="ad" en="Andorra" de="Andorra" fr="Andorre" it="Andorra"/>
<country code="ao" en="Angola" de="Angola" fr="Angola" it="Angola"/>
<country code="ai" en="Anguilla" de="Anguilla" fr="Anguilla" it="Anguilla"/>
<country code="aq" en="Antarctica" de="Antarktis" fr="Antarctique" it="Antartide"/>
<country code="ag" en="Antigua and Barbuda" de="Antigua und Barbuda" fr="Antigua-et-Barbuda" it="Antigua e Barbuda"/>
<country code="ar" en="Argentina" de="Argentinien" fr="Argentine" it="Argentina"/>
<country code="am" en="Armenia" de="Armenien" fr="Arménie" it="Armenia"/>
<country code="aw" en="Aruba" de="Aruba" fr="Aruba" it="Aruba"/>
<country code="au" en="Australia" de="Australien" fr="Australie" it="Australia"/>
<country code="at" en="Austria" de="Österreich" fr="Autriche" it="Austria"/>
<country code="az" en="Azerbaijan" de="Aserbaidschan" fr="Azerbaïdjan" it="Azerbaigian"/>
<country code="bs" en="Bahamas" de="Bahamas" fr="Bahamas" it="Bahamas"/>
<country code="bh" en="Bahrain" de="Bahrain" fr="Bahreïn" it="Bahrein"/>
<country code="bd" en="Bangladesh" de="Bangladesch" fr="Bangladesh" it="Bangladesh"/>
<country code="bb" en="Barbados" de="Barbados" fr="Barbade" it="Barbados"/>
<country code="by" en="Belarus" de="Belarus" fr="Bélarus" it="Bielorussia"/>
<country code="be" en="Belgium" de="Belgien" fr="Belgique" it="Belgio"/>
<country code="bz" en="Belize" de="Belize" fr="Belize" it="Belize"/>
<country code="bj" en="Benin" de="Benin" fr="Bénin" it="Benin"/>
<country code="bm" en="Bermuda" de="Bermudas" fr="Bermudes" it="Bermuda"/>
<country code="bt" en="Bhutan" de="Bhutan" fr="Bhoutan" it="Bhutan"/>
<country code="bo" en="Bolivia" de="Bolivien" fr="Bolivie" it="Bolivia"/>
<country code="ba" en="Bosnia-Herzegovina" de="Bosnien-Herzegowina" fr="Bosnie et Herzégovine" it="Bosnia ed Erzegovina"/>
<country code="bw" en="Botswana" de="Botsuana" fr="Botswana" it="Botswana"/>
<country code="bv" en="Bouvet Island" de="Bouvetinsel" fr="Île Bouvet" it="Isola Bouvet"/>
<country code="br" en="Brazil" de="Brasilien" fr="Brésil" it="Brasile"/>
<country code="io" en="British Indian Ocean Territory" de="Britisches Territorium im Indischen Ozean" fr="Territoire britannique de locéan Indien" it="Territorio Britannico dellOceano Indiano"/>
<country code="bn" en="Brunei" de="Brunei" fr="Brunei" it="Brunei"/>
<country code="bg" en="Bulgaria" de="Bulgarien" fr="Bulgarie" it="Bulgaria"/>
<country code="bf" en="Burkina Faso" de="Burkina Faso" fr="Burkina Faso " it="Burkina Faso"/>
<country code="bi" en="Burundi" de="Burundi" fr="Burundi" it="Burundi"/>
<country code="kh" en="Cambodia" de="Kambodscha" fr="Cambodge" it="Cambogia"/>
<country code="cm" en="Cameroon" de="Kamerun" fr="Cameroun" it="Camerun"/>
<country code="ca" en="Canada" de="Kanada" fr="Canada" it="Canada"/>
<country code="cv" en="Cape Verde" de="Cabo Verde" fr="Cabo Verde" it="Capo Verde"/>
<country code="ky" en="Cayman Islands" de="Kaiman-Inseln" fr="Îles Caïmans" it="Isole Cayman"/>
<country code="cf" en="Central African Republic" de="Zentralafrikanische Republik" fr="République centrafricaine" it="Repubblica Centrafricana"/>
<country code="td" en="Chad" de="Tschad" fr="Tchad" it="Ciad"/>
<country code="cl" en="Chile" de="Chile" fr="Chili" it="Cile"/>
<country code="cn" en="China (People's Republic OF)" de="China (Volksrepublik)" fr="Chine (République populaire de Chine)" it="Cina, Repubblica popolare cinese"/>
<country code="cx" en="Christmas Island (Indian Ocean)" de="Weihnachtsinsel (Indischer Ozean)" fr="Île Christmas (océan Indien)" it="Isola di Natale"/>
<country code="cc" en="Cocos (Keeling) Island" de="Kokosinseln (Keeling)" fr="Îles Cocos" it="Isole Cocos (Keeling)"/>
<country code="co" en="Colombia" de="Kolumbien" fr="Colombie" it="Colombia"/>
<country code="km" en="Comoros" de="Komoren" fr="Comores" it="Comore"/>
<country code="cg" en="Congo (Republic)" de="Kongo (Republik)" fr="République du Congo" it="Repubblica del Congo"/>
<country code="cd" en="Congo, Democratic Republic" de="Kongo, Demokratische Republik" fr="République démocratique du Congo" it="Repubblica democratica del Congo"/>
<country code="ck" en="Cook Islands" de="Cookinseln" fr="Îles Cook" it="Isole Cook"/>
<country code="cr" en="Costa Rica" de="Costa Rica" fr="Costa Rica" it="Costa Rica"/>
<country code="hr" en="Croatia" de="Kroatien" fr="Croatie" it="Croazia"/>
<country code="cu" en="Cuba" de="Kuba" fr="Cuba" it="Cuba"/>
<country code="cw" en="Curaçao" de="Curaçao" fr="Curaçao" it="Curaçao"/>
<country code="cy" en="Cyprus" de="Zypern" fr="Chypre" it="Cipro"/>
<country code="cz" en="Czech Republic" de="Tschechische Republik" fr="Tchéquie" it="Repubblica Ceca"/>
<country code="dk" en="Denmark" de="Dänemark" fr="Danemark" it="Danimarca"/>
<country code="dj" en="Djibouti" de="Dschibuti" fr="Djibouti" it="Gibuti"/>
<country code="dm" en="Dominica" de="Dominica" fr="Dominique" it="Dominica"/>
<country code="do" en="Dominican Republic" de="Dominikanische Republik" fr="République dominicaine" it="Repubblica Dominicana"/>
<country code="ec" en="Ecuador" de="Ecuador" fr="Équateur" it="Ecuador"/>
<country code="eg" en="Egypt" de="Ägypten" fr="Égypte" it="Egitto"/>
<country code="sv" en="El Salvador" de="El Salvador" fr="El Salvador" it="El Salvador"/>
<country code="gq" en="Equatorial Guinea" de="Äquatorialguinea" fr="Guinée équatoriale" it="Guinea equatoriale"/>
<country code="er" en="Eritrea" de="Eritrea" fr="Érythrée" it="Eritrea"/>
<country code="ee" en="Estonia" de="Estland" fr="Estonie" it="Estonia"/>
<country code="et" en="Ethiopia" de="Äthiopien" fr="Éthiopie" it="Etiopia"/>
<country code="fk" en="Falkland Islands" de="Falklandinseln" fr="Îles Falkland" it="Isole Falkland"/>
<country code="fo" en="Faroe Islands" de="Färöerinseln" fr="Îles Féroé" it="Isole Faroe"/>
<country code="fj" en="Fiji" de="Fidschi" fr="Fidji" it="Figi"/>
<country code="fi" en="Finland" de="Finnland" fr="Finlande" it="Finlandia"/>
<country code="fr" en="France" de="Frankreich" fr="France" it="Francia"/>
<country code="gf" en="French Guiana" de="Französisch-Guayana" fr="Guyane française" it="Guyana francese"/>
<country code="pf" en="French Polynesia" de="Französisch-Polynesien" fr="Polynésie française" it="Polinesia francese"/>
<country code="ga" en="Gabon" de="Gabun" fr="Gabon" it="Gabon"/>
<country code="gm" en="Gambia" de="Gambia" fr="Gambie" it="Gambia"/>
<country code="ge" en="Georgia" de="Georgien" fr="Géorgie" it="Georgia"/>
<country code="de" en="Germany" de="Deutschland" fr="Allemagne" it="Germania"/>
<country code="gh" en="Ghana" de="Ghana" fr="Ghana" it="Ghana"/>
<country code="gi" en="Gibraltar" de="Gibraltar" fr="Gibraltar" it="Gibilterra"/>
<country code="gb" en="Great Britain and Northern Ireland" de="Grossbritannien und Nordirland" fr="Royaume-Uni" it="Regno Unito"/>
<country code="gr" en="Greece" de="Griechenland" fr="Grèce" it="Grecia"/>
<country code="gl" en="Greenland" de="Grönland" fr="Groenland" it="Groenlandia"/>
<country code="gd" en="Grenada" de="Grenada" fr="Grenade" it="Grenada"/>
<country code="gp" en="Guadeloupe" de="Guadeloupe" fr="Guadeloupe" it="Guadalupa"/>
<country code="gu" en="Guam" de="Guam" fr="Guam" it="Guam"/>
<country code="gt" en="Guatemala" de="Guatemala" fr="Guatemala" it="Guatemala"/>
<country code="gg" en="Guernsey" de="Guernsey" fr="Guernesey" it="Guernsey"/>
<country code="gn" en="Guinea (Republic)" de="Guinea (Republik)" fr="République de Guinée" it="Guinea"/>
<country code="gw" en="Guinea-Bissau" de="Guinea-Bissau" fr="Guinée-Bissau" it="Guinea-Bissau"/>
<country code="gy" en="Guyana" de="Guyana" fr="Guyana" it="Guyana"/>
<country code="ht" en="Haiti" de="Haiti" fr="Haïti" it="Haiti"/>
<country code="hm" en="Heard AND McDonald Islands" de="Heard- und McDonald-Inseln" fr="Îles Heard et McDonald" it="Isola Heard e Isole McDonald"/>
<country code="hn" en="Honduras" de="Honduras" fr="Honduras" it="Honduras"/>
<country code="hk" en="Hong Kong" de="Hongkong" fr="Hong Kong" it="Hong Kong"/>
<country code="hu" en="Hungary" de="Ungarn" fr="Hongrie" it="Ungheria"/>
<country code="is" en="Iceland" de="Island" fr="Islande" it="Islanda"/>
<country code="in" en="India" de="Indien" fr="Inde" it="India"/>
<country code="id" en="Indonesia" de="Indonesien" fr="Indonésie" it="Indonesia"/>
<country code="ir" en="Iran" de="Iran" fr="Iran" it="Iran"/>
<country code="iq" en="Iraq" de="Irak" fr="Irak" it="Iraq"/>
<country code="ie" en="Ireland" de="Irland" fr="Irlande" it="Irlanda"/>
<country code="im" en="Island OF Man" de="Isle of Man" fr="Île de Man" it="Isola di Man"/>
<country code="il" en="Israel" de="Israel" fr="Israël" it="Israele"/>
<country code="it" en="Italy" de="Italien" fr="Italie" it="Italia"/>
<country code="ci" en="Ivory Coast" de="Côte d'Ivoire" fr="Côte dIvoire" it="Costa dAvorio"/>
<country code="jm" en="Jamaica" de="Jamaika" fr="Jamaïque" it="Giamaica"/>
<country code="jp" en="Japan" de="Japan" fr="Japon" it="Giappone"/>
<country code="je" en="Jersey" de="Jersey" fr="Jersey" it="Jersey"/>
<country code="jo" en="Jordan" de="Jordanien" fr="Jordanie" it="Giordania"/>
<country code="kz" en="Kazakhstan" de="Kasachstan" fr="Kazakhstan" it="Kazakstan"/>
<country code="ke" en="Kenya" de="Kenia" fr="Kenya" it="Kenya"/>
<country code="ki" en="Kiribati" de="Kiribati" fr="Kiribati" it="Kiribati"/>
<country code="kp" en="Korea, Democratic People's Republic of (North Korea)" de="Korea, Demokratische Volksrepublik (Nordkorea)" fr="République populaire démocratique de Corée (Corée du Nord)" it="Repubblica popolare democratica di Corea (Corea del Nord)"/>
<country code="kr" en="Korea, Republic of (South Korea)" de="Korea, Republik (Südkorea)" fr="République de Corée (Corée du Sud)" it="Repubblica di Corea (Corea del Sud)"/>
<country code="xk" en="Kosovo / Unmik" de="Kosovo / UNMIK" fr="Kosovo" it="Kosovo / UNMIK"/>
<country code="kw" en="Kuwait" de="Kuwait" fr="Koweït" it="Kuwait"/>
<country code="kg" en="Kyrgyzstan" de="Kirgisistan" fr="Kirghizistan" it="Kirghizistan"/>
<country code="la" en="Laos" de="Laos" fr="Laos" it="Laos"/>
<country code="lv" en="Latvia" de="Lettland" fr="Lettonie" it="Lettonia"/>
<country code="lb" en="Lebanon" de="Libanon" fr="Liban" it="Libano"/>
<country code="ls" en="Lesotho" de="Lesotho" fr="Lesotho" it="Lesotho"/>
<country code="lr" en="Liberia" de="Liberia" fr="Libéria" it="Liberia"/>
<country code="ly" en="Libya" de="Libyen" fr="Libye" it="Libia"/>
<country code="li" en="Liechtenstein" de="Liechtenstein" fr="Liechtenstein" it="Liechtenstein"/>
<country code="lt" en="Lithuania" de="Litauen" fr="Lituanie" it="Lituania"/>
<country code="lu" en="Luxembourg" de="Luxemburg" fr="Luxembourg" it="Lussemburgo"/>
<country code="mo" en="Macao" de="Macao" fr="Macao" it="Macao"/>
<country code="mk" en="Macedonia, the Former Yugoslav Republic of" de="Mazedonien, ehemalige jugoslawische Republik" fr="Macédoine du Nord" it="Macedonia del Nord"/>
<country code="mg" en="Madagascar" de="Madagaskar" fr="Madagascar" it="Madagascar"/>
<country code="mw" en="Malawi" de="Malawi" fr="Malawi" it="Malawi"/>
<country code="my" en="Malaysia" de="Malaysia" fr="Malaisie" it="Malaysia"/>
<country code="mv" en="Maldives" de="Malediven" fr="Maldives" it="Maldive"/>
<country code="ml" en="Mali" de="Mali" fr="Mali" it="Mali"/>
<country code="mt" en="Malta" de="Malta" fr="Malte" it="Malta"/>
<country code="mp" en="Mariana Islands" de="Marianen" fr="Îles Mariannes" it="Isole Marianne"/>
<country code="mh" en="Marshall Islands" de="Marshallinseln" fr="Îles Marshall" it="Isole Marshall"/>
<country code="mq" en="Martinique" de="Martinique" fr="Martinique" it="Martinica"/>
<country code="mr" en="Mauritania" de="Mauretanien" fr="Mauritanie" it="Mauritania"/>
<country code="mu" en="Mauritius Island" de="Mauritius" fr="Île Maurice" it="Maurizio"/>
<country code="yt" en="Mayotte" de="Mayotte" fr="Mayotte" it="Mayotte"/>
<country code="mx" en="Mexico" de="Mexiko" fr="Mexique" it="Messico"/>
<country code="fm" en="Micronesia (Federated States OF)" de="Mikronesien (Föderierte Staaten von)" fr="États fédérés de Micronésie" it="Stati Federati di Micronesia"/>
<country code="md" en="Moldova" de="Moldau" fr="Moldavie" it="Moldova"/>
<country code="mc" en="Monaco" de="Monaco" fr="Monaco" it="Monaco"/>
<country code="mn" en="Mongolia" de="Mongolei" fr="Mongolie" it="Mongolia"/>
<country code="me" en="Montenegro, Republic" de="Montenegro, Republik" fr="Monténégro" it="Montenegro"/>
<country code="ms" en="Montserrat" de="Montserrat" fr="Montserrat" it="Montserrat"/>
<country code="ma" en="Morocco" de="Marokko" fr="Maroc" it="Marocco"/>
<country code="mz" en="Mozambique" de="Mosambik" fr="Mozambique" it="Mozambico"/>
<country code="mm" en="Myanmar (Union of)" de="Myanmar (Union)" fr="Myanmar" it="Myanmar"/>
<country code="na" en="Namibia" de="Namibia" fr="Namibie" it="Namibia"/>
<country code="nr" en="Nauru" de="Nauru" fr="Nauru" it="Nauru"/>
<country code="np" en="Nepal" de="Nepal" fr="Népal" it="Nepal"/>
<country code="nl" en="Netherlands" de="Niederlande" fr="Pays-Bas" it="Paesi Bassi"/>
<country code="nc" en="New Caledonia" de="Neukaledonien" fr="Nouvelle-Calédonie" it="Nuova Caledonia"/>
<country code="nz" en="New Zealand" de="Neuseeland" fr="Nouvelle-Zélande" it="Nuova Zelanda"/>
<country code="ni" en="Nicaragua" de="Nicaragua" fr="Nicaragua" it="Nicaragua"/>
<country code="ne" en="Niger" de="Niger" fr="Niger" it="Niger"/>
<country code="ng" en="Nigeria" de="Nigeria" fr="Nigéria" it="Nigeria"/>
<country code="nu" en="Niua" de="Niue" fr="Nioué" it="Isole Niua"/>
<country code="nf" en="Norfolk Island" de="Norfolkinsel" fr="Île Norfolk" it="Isola Norfolk"/>
<country code="no" en="Norway" de="Norwegen" fr="Norvège" it="Norvegia"/>
<country code="om" en="Oman" de="Oman" fr="Oman" it="Oman"/>
<country code="pk" en="Pakistan" de="Pakistan" fr="Pakistan" it="Pakistan"/>
<country code="pw" en="Palau" de="Palau" fr="Palaos" it="Palau"/>
<country code="ps" en="Palestine" de="Palästina" fr="Palestine" it="Palestina"/>
<country code="pa" en="Panama" de="Panama" fr="Panama" it="Panama"/>
<country code="pg" en="Papua New Guinea" de="Papua-Neuguinea" fr="Papouasie-Nouvelle-Guinée" it="Papua Nuova Guinea"/>
<country code="py" en="Paraguay" de="Paraguay" fr="Paraguay" it="Paraguay"/>
<country code="pe" en="Peru" de="Peru" fr="Pérou" it="Perù"/>
<country code="ph" en="Philippines" de="Philippinen" fr="Philippines" it="Filippine"/>
<country code="pn" en="Pitcairn" de="Pitcairn" fr="Îles Pitcairn" it="Isole Pitcairn"/>
<country code="pl" en="Poland" de="Polen" fr="Pologne" it="Polonia"/>
<country code="pt" en="Portugal" de="Portugal" fr="Portugal" it="Portogallo"/>
<country code="pr" en="Puerto Rico" de="Puerto Rico" fr="Porto Rico" it="Porto Rico"/>
<country code="qa" en="Qatar" de="Katar" fr="Qatar" it="Qatar"/>
<country code="re" en="Réunion" de="Réunion" fr="La Réunion" it="Isola della Riunione"/>
<country code="ro" en="Romania" de="Rumänien" fr="Roumanie" it="Romania"/>
<country code="ru" en="Russian Federation" de="Russische Föderation" fr="Russie" it="Russia"/>
<country code="rw" en="Rwanda" de="Ruanda" fr="Rwanda" it="Ruanda"/>
<country code="sb" en="Salomon Islands" de="Salomoninseln" fr="Îles Salomon" it="Isole Salomone"/>
<country code="sm" en="San Marino" de="San Marino" fr="Saint-Marin" it="San Marino"/>
<country code="sa" en="Saudi Arabia" de="Saudi-Arabien" fr="Arabie saoudite" it="Arabia Saudita"/>
<country code="sn" en="Senegal" de="Senegal" fr="Sénégal" it="Senegal"/>
<country code="rs" en="Serbia, Republic" de="Serbien, Republik" fr="Serbie" it="Serbia"/>
<country code="sc" en="Seychelles" de="Seychellen" fr="Seychelles" it="Seychelles"/>
<country code="sl" en="Sierra Leone" de="Sierra Leone" fr="Sierra Leone" it="Sierra Leone"/>
<country code="sg" en="Singapore" de="Singapur" fr="Singapour" it="Singapore"/>
<country code="sk" en="Slovak Republic" de="Slowakei" fr="Slovaquie" it="Slovacchia"/>
<country code="si" en="Slovenia" de="Slowenien" fr="Slovénie" it="Slovenia"/>
<country code="so" en="Somalia" de="Somalia" fr="Somalie" it="Somalia"/>
<country code="za" en="South Africa" de="Südafrika" fr="Afrique du Sud" it="Sudafrica"/>
<country code="gs" en="South Georgia AND the south Sandwich Islands" de="Südgeorgien und die Südlichen Sandwichinseln" fr="Îles Géorgie du Sud et Sandwich du Sud" it="Georgia del Sud e Sandwich Australi"/>
<country code="ss" en="South Sudan" de="Südsudan" fr="Soudan du Sud" it="Sudan del Sud"/>
<country code="es" en="Spain" de="Spanien" fr="Espagne" it="Spagna"/>
<country code="lk" en="Sri Lanka" de="Sri Lanka" fr="Sri Lanka" it="Sri Lanka"/>
<country code="bl" en="St. Barthélemy" de="St. Barthélemy" fr="Saint-Barthélemy" it="Saint Barthélemy"/>
<country code="kn" en="St. Christopher (St. Kitts) and Nevis" de="St. Kitts und Nevis" fr="Saint-Christophe-et-Niévès" it="Saint Kitts e Nevis"/>
<country code="sh" en="St. Helena, Ascension and Tristan da Cunha" de="St. Helena, Ascension und Tristan da Cunha" fr="Sainte-Hélène, Ascension et Tristan da Cunha" it="SantElena, Ascensione e Tristan da Cunha"/>
<country code="lc" en="St. Lucia" de="St. Lucia" fr="Sainte-Lucie" it="Santa Lucia"/>
<country code="sx" en="St. Maarten" de="Sint Maarten" fr="Sint-Maarten" it="Sint Maarten"/>
<country code="mf" en="St. Martin" de="St. Martin" fr="Saint-Martin" it="Saint Martin"/>
<country code="pm" en="St. Pierre and Miquelon" de="St. Pierre und Miquelon" fr="Saint-Pierre-et-Miquelon" it="Saint-Pierre e Miquelon"/>
<country code="st" en="St. Tome and Principe" de="São Tomé und Príncipe" fr="Sao Tomé-et-Principe" it="São Tomé e Príncipe"/>
<country code="vc" en="St. Vincent and the Grenadines" de="St. Vincent und die Grenadinen" fr="Saint-Vincent-et-les-Grenadines" it="Saint Vincent e Grenadine"/>
<country code="sd" en="Sudan" de="Sudan" fr="Soudan" it="Sudan"/>
<country code="sr" en="Suriname" de="Suriname" fr="Suriname" it="Suriname"/>
<country code="sj" en="Svalbard and Jan Mayen Island" de="Svalbard und Jan Mayen-Insel" fr="Svalbard et Jan Mayen" it="Svalbard e Jan Mayen"/>
<country code="sz" en="Swaziland" de="Eswatini" fr="Swaziland" it="Eswatini"/>
<country code="se" en="Sweden" de="Schweden" fr="Suède" it="Svezia"/>
<country code="ch" en="Switzerland" de="Schweiz" fr="Suisse" it="Svizzera"/>
<country code="sy" en="Syria" de="Syrien" fr="Syrie" it="Siria"/>
<country code="tw" en="Taiwan (Chinese Taipei)" de="Taiwan (Chinesisches Taipei)" fr="Taïwan (Taipei chinois)" it="Taiwan (Taipei cinese)"/>
<country code="tj" en="Tajikistan" de="Tadschikistan" fr="Tadjikistan" it="Tagikistan"/>
<country code="tz" en="Tanzania" de="Tansania" fr="Tanzanie" it="Tanzania"/>
<country code="th" en="Thailand" de="Thailand" fr="Thaïlande" it="Thailandia"/>
<country code="tl" en="Timor-Leste" de="Timor-Leste" fr="Timor-Leste" it="Timor-Leste"/>
<country code="tg" en="Togo" de="Togo" fr="Togo" it="Togo"/>
<country code="tk" en="Tokelau" de="Tokelau" fr="Tokélaou" it="Tokelau"/>
<country code="to" en="Tonga" de="Tonga" fr="Tonga" it="Tonga"/>
<country code="tt" en="Trinidad and Tobago" de="Trinidad und Tobago" fr="Trinité-et-Tobago" it="Trinidad e Tobago"/>
<country code="tn" en="Tunisia" de="Tunesien" fr="Tunisie" it="Tunisia"/>
<country code="tr" en="Turkey" de="Türkiye" fr="Turquie" it="Turchia"/>
<country code="tm" en="Turkmenistan" de="Turkmenistan" fr="Turkménistan" it="Turkmenistan"/>
<country code="tc" en="Turks and Caicos" de="Turks- und Caicosinseln" fr="Turks-et-Caïcos" it="Isole Turks e Caicos"/>
<country code="tv" en="Tuvalu" de="Tuvalu" fr="Tuvalu" it="Tuvalu"/>
<country code="ug" en="Uganda" de="Uganda" fr="Ouganda" it="Uganda"/>
<country code="ua" en="Ukraine" de="Ukraine" fr="Ukraine" it="Ucraina"/>
<country code="ae" en="United Arab Emirates" de="Vereinigte Arabische Emirate" fr="Émirats arabes unis" it="Emirati Arabi Uniti"/>
<country code="um" en="United States Minor Outlying Islands" de="United States Minor Outlying Islands" fr="Îles mineures éloignées des États-Unis" it="Isole Minori Esterne degli Stati Uniti"/>
<country code="us" en="United States of America" de="Vereinigte Staaten von Amerika" fr="États-Unis dAmérique" it="Stati Uniti"/>
<country code="uy" en="Uruguay" de="Uruguay" fr="Uruguay" it="Uruguay"/>
<country code="uz" en="Uzbekistan" de="Usbekistan" fr="Ouzbékistan" it="Uzbekistan"/>
<country code="vu" en="Vanuatu" de="Vanuatu" fr="Vanuatu" it="Vanuatu"/>
<country code="va" en="Vatican City State" de="Vatikanstadt" fr="Saint-Siège (Cité du Vatican)" it="Città del Vaticano"/>
<country code="ve" en="Venezuela" de="Venezuela" fr="Venezuela" it="Venezuela"/>
<country code="vn" en="Vietnam" de="Vietnam" fr="Vietnam" it="Vietnam"/>
<country code="vi" en="Virgin Islands (USA)" de="Jungferninseln (USA)" fr="Îles Vierges américaines" it="Isole Vergini"/>
<country code="vg" en="Virgin Islands, British (Tortola)" de="British Virgin Islands (Tortola)" fr="Îles Vierges britanniques (Tortola)" it="Isole Vergini britanniche"/>
<country code="wf" en="Wallis and Futuna Islands" de="Wallis und Futuna" fr="Îles Wallis-et-Futuna" it="Wallis e Futuna"/>
<country code="eh" en="Western Sahara" de="Westsahara" fr="Sahara occidental" it="Sahara occidentale"/>
<country code="ws" en="Western Samoa" de="Samoa" fr="Samoa" it="Samoa occidentale"/>
<country code="ye" en="Yemen" de="Jemen" fr="Yémen" it="Yemen"/>
<country code="zm" en="Zambia" de="Sambia" fr="Zambie" it="Zambia"/>
<country code="zw" en="Zimbabwe" de="Simbabwe" fr="Zimbabwe" it="Zimbabwe" />
</country-names>

View File

@ -64,7 +64,7 @@ if (requestedRoleLevelNumber == 0 || session.get('ch.nevis.auth.saml.request.sco
return
}
def eidEnabled = parameters.get('eidPassthroughEnabled') == "true" || parameters.get('eidFullEnabled') == "true"
def eidEnabled = parameters.get('eidEnabled') == "true"
// TODO/aca/2025-06-05: add a condition to check if the client actually allows eid
def eidAllowed = eidEnabled
// set session variable to later decide to which loginmethods we can switch
@ -81,6 +81,8 @@ if(lastLoginMethod != null || lastLoginMethod != ""){
if(lastLoginMethod == "accessApp" || lastLoginMethod == "securityKey"){
ok_transition = 'ok'
}
}else{
session.setAttribute('agov.lastLoginMethod', eidAllowed ? "accessApp" : "eid")
}
// NOTE: if the last login method was eid, but eid is not allowed, we will default to fido uaf
@ -103,7 +105,7 @@ 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))
// if aq500 or 600 is requested -> the only available login method is eid -> continue directly there
// if eid is disabled -> show an error page
@ -160,6 +162,7 @@ try {
} catch (Exception e) {
LOG.error("Failed to fetch connect meta data for relying party '${session.get('ch.nevis.auth.saml.request.scoping.requesterId')}'", e)
session.setAttribute('agov.eidAllowed', 'false')
if ( requestedRoleLevelNumber == 100) {
session.setAttribute('agov.appAddressRequired', '' + appRequiresBestTokenWithAddress)
session.setAttribute('agov.appSvnrAllowed', 'false')

View File

@ -15,4 +15,5 @@
<property name="parameter.idm.httpclient.tls.keyObjectRef" value="DefaultKeyStore"/>
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="${keystore}"/>
<property name="parameter.cookie.domain" value="${var.idp-fqdn}"/>
<property name="parameter.ask_mobile_number_enabled" value="${var.idp.ask_mobile_number_enabled}"/>
</AuthState>

View File

@ -32,6 +32,12 @@ String baseUrl = parameters.get('baseUrl')
String endPoint = "${baseUrl}/core/v1/${clientExtId}/users/${userExtId}"
if (!(parameters.get('ask_mobile_number_enabled')?.toLowerCase()?.trim() == "true")) {
LOG.debug("Feature 'ask mobile number' is disabled")
response.setResult('done')
return
}
if (mobile) {
LOG.debug("User '${user}' has already registered a mobile number")
response.setResult('done')

View File

@ -6,7 +6,6 @@
</Response>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="parameter.cookie.domain" value="${var.idp-fqdn}"/>
<property name="parameter.eidPassthroughEnabled" value="${var.eid.passthrough.enabled}"/>
<property name="parameter.eidFullEnabled" value="${var.eid.full.enabled}"/>
<property name="parameter.eidEnabled" value="${var.eid.enabled}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/idp_status_check.groovy"/>
</AuthState>

View File

@ -87,14 +87,11 @@ if (inargs['SAMLRequest'] != null) {
// process it the same way, as if frontend triggered a reload
request.getInArgs().setProperty('onReload', 'now')
def eidEnabled = parameters.get('eidPassthroughEnabled') == "true" || parameters.get('eidFullEnabled') == "true"
eidEnabled
LOG.error("EID?: " + eidEnabled)
LOG.error("Full?: " + parameters.get('eidFullEnabled'))
LOG.error("Pass?: " + parameters.get('eidPassthroughEnabled'))
def eidEnabled = parameters.get('eidEnabled') == "true"
def requestedLoa = s.getAttribute("agov.requestedRoleLevel")
// TODO: use a different flag to check if this is a eid request since eid can now also be used for lower aq
if( eidEnabled && ( requestedLoa == "600" || requestedLoa == "500") ){
if( eidEnabled && ( requestedLoa == "600" || requestedLoa == "500" || s.getAttribute('agov.lastLoginMethod') == 'eid' ) ){
// EID request -> goto correct state
response.setResult('continueEidAfterRepost')
}else{

View File

@ -0,0 +1,13 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="register" next="${state.done}"/>
<ResultCond name="back" next="${state.exit.1}"/>
<Response value="AUTH_CONTINUE">
<Gui name="eid_registration">
<GuiElem name="register" type="hidden" value="UNKNOWN" optional="true"/>
<GuiElem name="authRequestId" type="hidden" value="${sess:ch.nevis.auth.saml.request.id}" optional="true"/>
</Gui>
</Response>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_registration.groovy"/>
</AuthState>

View File

@ -0,0 +1,17 @@
import ch.nevis.esauth.auth.engine.AuthResponse
if(inargs['cancel']){
LOG.debug("Account registration canceled: Send response with error")
response.setResult('back')
return
}
if(inargs['register'] == "agov"){
LOG.debug("AGOV account registration was selected")
response.setResult('register')
return
}
LOG.debug("Show GUI")
response.setStatus(AuthResponse.AUTH_CONTINUE)
return

View File

@ -5,7 +5,6 @@ pattern:
name: "Ask_Mobile_Number"
properties:
authStatesFile: "res://6d83506dfcc430c12d81dfa3#authStatesFile"
parameters: "var://ask_mobile_number-template-parameters"
onSuccess:
- "pattern://2cdd910036aa06b102863a4f"
onFailure:

View File

@ -22,6 +22,7 @@ pattern:
- "pattern://097929211988398a87bcbb0c"
template: "res://4fcfadb4a5c946ead7e6e995#template"
labels: "res://4fcfadb4a5c946ead7e6e995#labels"
defaultProperties: "var://nevislogrend-configuration-logrendproperties"
sessionTracking: "COOKIE"
cookieName: "agov"
initialSessionTimeout: "var://idp-authentication-session-timeout"

View File

@ -15,6 +15,7 @@ pattern:
- "pattern://097929211988398a87bcbb0c"
template: "res://204c22beaccdfd22727af378#template"
labels: "res://204c22beaccdfd22727af378#labels"
defaultProperties: "var://nevislogrend-configuration-logrendproperties"
cookieName: "agovRecovery"
cookieSameSite: "Lax"
langCookieDomain: "var://agov-language-cookie-domain"

View File

@ -7,7 +7,7 @@ pattern:
properties:
scriptFile: "res://2cdd910036aa06b102863a4f#scriptFile"
onSuccess:
- "pattern://594764b3b866d7855f6990a1"
- "pattern://4c7ad5e93c0ed94844e6bbfe"
onFailure:
- "pattern://50b861438e79c2332862d3ca"
customSteps:

View File

@ -1,24 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "ecf4381f4653b0aa9a69b417"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.GenericHostContextSettings"
name: "DefaulErrorPages"
label: "UTILS"
properties:
filters: "<filter>\n <filter-name>DefaultErrorFilter</filter-name>\n <filter-class>ch::nevis::isiweb4::filter::error::ErrorFilter</filter-class>\n\
\ <init-param>\n <param-name>StatusCode</param-name>\n <param-value>\n\
\ 400:file:/resources/errorPages/404.html:reset-header:reset-status-code\n\
\ 403:file:/resources/errorPages/403.html:reset-header:reset-status-code\n\
\t 404:file:/resources/errorPages/404.html:reset-header:reset-status-code\n\
\ 408:file:/resources/errorPages/timeout.html:reset-header:reset-status-code\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\
\ </param-value>\n </init-param>\n <init-param>\n <param-name>CheckAcceptHeader</param-name>\n\
\ <param-value>true</param-value>\n </init-param>\n <init-param>\n\
\ <param-name>PlaceHolders</param-name>\n <param-value>\n \
\ TransferIdHolder:TRANSFER_ID\n TimestampHolder:TIMESTAMP\n\
\ </param-value>\n </init-param>\n</filter>\n\n<filter-mapping>\n\
\ <filter-name>DefaultErrorFilter</filter-name>\n <url-pattern>/*</url-pattern>\n\
\ <exclude-url-regex>^/resource/utility/.*$</exclude-url-regex>\n</filter-mapping>\n"
filterMappings: "manual"
phase: "START"

View File

@ -0,0 +1,38 @@
schemaVersion: "1.0"
pattern:
id: "ecf4381f4653b0aa9a69b417"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.GenericHostContextSettings"
name: "DefaultErrorPages"
label: "UTILS"
properties:
filters: "<filter>\n <filter-name>DefaultErrorFilter</filter-name>\n <filter-class>ch::nevis::isiweb4::filter::error::ErrorFilter</filter-class>\n\
\ <init-param>\n <param-name>StatusCode</param-name>\n <param-value>\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\
\ </param-value>\n </init-param>\n <init-param>\n <param-name>CheckAcceptHeader</param-name>\n\
\ <param-value>true</param-value>\n </init-param>\n <init-param>\n\
\ <param-name>PlaceHolders</param-name>\n <param-value>\n \
\ TransferIdHolder:TRANSFER_ID\n TimestampHolder:TIMESTAMP\n\
\ </param-value>\n </init-param>\n</filter>\n<filter>\n <filter-name>FallbackErrorFilter</filter-name>\n\
\ <filter-class>ch::nevis::isiweb4::filter::error::ErrorFilter</filter-class>\n\
\ <init-param>\n <param-name>StatusCode</param-name>\n <param-value>\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\
\ </param-value>\n </init-param>\n <init-param>\n <param-name>CheckAcceptHeader</param-name>\n\
\ <param-value>true</param-value>\n </init-param>\n <init-param>\n\
\ <param-name>PlaceHolders</param-name>\n <param-value>\n \
\ TransferIdHolder:TRANSFER_ID\n TimestampHolder:TIMESTAMP\n\
\ </param-value>\n </init-param>\n</filter>\n<filter-mapping>\n\
\ <filter-name>DefaultErrorFilter</filter-name>\n <url-pattern>/*</url-pattern>\n\
</filter-mapping>\n<filter-mapping>\n <filter-name>FallbackErrorFilter</filter-name>\n\
\ <servlet-name>NevisLogrendConnector_${param.logrendInstancePatternName}</servlet-name>\n\
</filter-mapping>"
filterMappings: "manual"
phase: "START"
parameters: "logrendInstancePatternName: nevisLogrend"

View File

@ -0,0 +1,18 @@
schemaVersion: "1.0"
pattern:
id: "306ce091fd87bad6174d9e8b"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "EId_Compare_And_Update_IDM_Attributes"
label: "EID"
notes: "We return to the regular login flow after this State"
properties:
authStatesFile: "res://306ce091fd87bad6174d9e8b#authStatesFile"
onSuccess:
- "pattern://b87d0d2b640e8e545ad70234"
onFailure:
- "pattern://4c65de021d362462324a3a5f"
nextSteps:
- "pattern://47f8f6ef24f62431fbe1b530"
resources: "res://306ce091fd87bad6174d9e8b#resources"
keyObjects:
- "pattern://947daa1313709b0f26a64432"

View File

@ -0,0 +1,12 @@
schemaVersion: "1.0"
pattern:
id: "b8bdab6e4634a1d81f20e5bb"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "EId_Fetch_IDM_Attributes"
label: "EID"
properties:
authStatesFile: "res://b8bdab6e4634a1d81f20e5bb#authStatesFile"
onSuccess:
- "pattern://306ce091fd87bad6174d9e8b"
keyObjects:
- "pattern://947daa1313709b0f26a64432"

View File

@ -0,0 +1,18 @@
schemaVersion: "1.0"
pattern:
id: "6244fcef0dce49e7b09012de"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.TransformVariablesStep"
name: "EId_Passthrough_Prepare_Assertion"
label: "EID"
properties:
variables:
- sess:ch.nevis.idm.User.firstName: "${sess:agov.eid.User.firstName}"
- sess:ch.nevis.idm.User.lastName: "${sess:agov.eid.User.lastName}"
- sess:ch.nevis.idm.User.birthDate: "${sess:agov.eid.User.birthDate}"
- sess:ch.nevis.idm.User.gender: "${sess:agov.eid.User.gender}"
- sess:ch.nevis.idm.User.prop.svnr: "${sess:agov.eid.User.svnr}"
- sess:ch.nevis.idm.User.prop.placeOfBirth: "${sess:agov.eid.User.placeOfBirth}"
- sess:ch.nevis.idm.User.prop.eIdNumber: "${sess:agov.eid.User.eIdNumber}"
- sess:ch.nevis.idm.User.prop.nationality: "${sess:agov.eid.User.nationality}"
onSuccess:
- "pattern://b87d0d2b640e8e545ad70234"

View File

@ -0,0 +1,18 @@
schemaVersion: "1.0"
pattern:
id: "3c1d57471850dccab77fd257"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.Dispatcher"
name: "EId_Passthrough_Switch"
label: "EID"
properties:
conditions:
- passthrough: "${session:agov.requestedRoleLevel:600:true}"
- augmentation: "${session:agov.requestedRoleLevel:^[12345]00$:true}"
transitions:
- passthrough: "1"
- augmentation: "2"
steps:
- "pattern://6244fcef0dce49e7b09012de"
- "pattern://4f15bae09cbda04a7a515158"
defaultStep:
- "pattern://4c65de021d362462324a3a5f"

View File

@ -0,0 +1,13 @@
schemaVersion: "1.0"
pattern:
id: "9e0cb3f3fd05315512afd46c"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "EId_Registration_Page"
label: "EID"
properties:
authStatesFile: "res://9e0cb3f3fd05315512afd46c#authStatesFile"
onSuccess:
- "pattern://d76231eaa88cb1645ce44cf3"
nextSteps:
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://9e0cb3f3fd05315512afd46c#resources"

View File

@ -0,0 +1,9 @@
schemaVersion: "1.0"
pattern:
id: "947daa1313709b0f26a64432"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns.KeyObject"
name: "EId_Rest_Client_Trust_Store"
label: "EID"
properties:
trustStore:
- "pattern://ff188ae9f50527ef19eccd2c"

View File

@ -0,0 +1,18 @@
schemaVersion: "1.0"
pattern:
id: "4f15bae09cbda04a7a515158"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "EId_Select_AGOV_Account"
label: "EID"
properties:
authStatesFile: "res://4f15bae09cbda04a7a515158#authStatesFile"
onSuccess:
- "pattern://b8bdab6e4634a1d81f20e5bb"
onFailure:
- "pattern://4c65de021d362462324a3a5f"
nextSteps:
- "pattern://47f8f6ef24f62431fbe1b530"
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://4f15bae09cbda04a7a515158#resources"
keyObjects:
- "pattern://947daa1313709b0f26a64432"

View File

@ -7,7 +7,10 @@ pattern:
properties:
authStatesFile: "res://e335f57d4c64dfc97223697a#authStatesFile"
onSuccess:
- "pattern://b87d0d2b640e8e545ad70234"
- "pattern://3c1d57471850dccab77fd257"
onFailure:
- "pattern://4c65de021d362462324a3a5f"
nextSteps:
- "pattern://f63c475c35b616b7c6c1901c"
- "pattern://9e0cb3f3fd05315512afd46c"
resources: "res://e335f57d4c64dfc97223697a#resources"

View File

@ -0,0 +1,9 @@
schemaVersion: "1.0"
pattern:
id: "47f8f6ef24f62431fbe1b530"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "Eid_Placeholder"
label: "EID"
notes: "Test Pattern to display messages/errors"
properties:
authStatesFile: "res://47f8f6ef24f62431fbe1b530#authStatesFile"

View File

@ -28,8 +28,10 @@ pattern:
link: "Custom URI"
customURILink: "var://fido_uaf_instance-custom-uri-link"
nevisidm:
- "pattern://b8a36646f81c3247cdb5d90b"
client: "var://fido_uaf_instance-client-id"
- "pattern://f1e0b2a7bc849ffc63a612e6"
client: "var://idm-agov-client-extid"
backendTrustStore:
- "pattern://7076f2654dd4efa1675afc72"
registrationTokenTimeout: "var://fido-uaf-generic-token-timeout"
authenticationTokenTimeout: "var://fido-uaf-generic-token-timeout"
deviceServiceTimeout: "var://fido-uaf-device-service-timeout"

View File

@ -4,7 +4,7 @@ pattern:
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.AutomaticTrustStoreProvider"
name: "FIDO_UAF_extended_Frontent_Truststore"
label: "UAF"
notes: "Used to also as trusstore for the firebase outgoing connection (i.e. trust\
notes: "Used to also as truststore for the firebase outgoing connection (i.e. trust\
\ forward proxy CA if necessary)"
properties:
truststoreFile: "var://fido_uaf_extended_frontent_truststore-fw_proxy_ca_cert"

View File

@ -0,0 +1,17 @@
schemaVersion: "1.0"
pattern:
id: "4c7ad5e93c0ed94844e6bbfe"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GroovyScriptStep"
name: "Fetch_Country_Name"
label: "LOA"
properties:
scriptFile: "res://4c7ad5e93c0ed94844e6bbfe#scriptFile"
parameters:
- baseurl: "${var.utility_resource_service-backend-address}"
validation: "parse-only"
onSuccess:
- "pattern://b87d0d2b640e8e545ad70234"
onFailure:
- "pattern://b87d0d2b640e8e545ad70234"
scriptTraceGroup: "AGOV-ACCT"
responseType: "AUTH_CONTINUE"

View File

@ -1,11 +0,0 @@
schemaVersion: "1.0"
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:
- "pattern://b87d0d2b640e8e545ad70234"
resources: "res://594764b3b866d7855f6990a1#resources"

View File

@ -1,21 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "2951ead44a7a9362a4545094"
className: "ch.nevis.admin.v4.plugin.nevisidm.patterns.NevisIDMDatabase"
name: "IDM_DB"
label: "IDM"
properties:
type: "var://idm_db-database-type"
hosts: "var://idm_db-database-host"
database: "var://idm_db-database-name"
rootCredential: "var://idm_db-root-credential"
rootCredentialNamespace: "var://idm_db-root-credential-namespace"
user: "var://idm_db-database-user"
password: "var://idm_db-database-password"
encryption: "var://idm_db-tls-encryption"
trustStore:
- "pattern://326adce95ad1a0761f2259b7"
jdbcDriver: "var://idm_db-database-jdbc-driver"
oracleVolumeClaimName: "var://idm_db-database-volume-claim"
databaseManagement: "var://agov_dev_idm-db-management"
connectionUrl: "var://idm_db-database-connection-url"

View File

@ -1,8 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "326adce95ad1a0761f2259b7"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.PemTrustStoreProvider"
name: "IDM_DB_TLS_TrustStore"
label: "IDM"
properties:
truststoreFile: "var://idm_db_tls_truststore-trusted-certificates"

View File

@ -6,4 +6,4 @@ pattern:
label: "IDM"
properties:
nevisIDM:
- "pattern://b8a36646f81c3247cdb5d90b"
- "pattern://f1e0b2a7bc849ffc63a612e6"

View File

@ -1,15 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "71411a755a625f9b850c6cf5"
className: "ch.nevis.admin.v4.plugin.nevisidm.patterns.NevisIDMAdvancedSettings"
name: "IDM_Settings"
label: "IDM"
notes: "used for SAMP IDP\n---\nbatch, event, audit processing disabled on that\
\ instance"
link:
sourceProjectKey: "DEFAULT-IAM-JAKOB"
sourcePatternId: "71411a755a625f9b850c6cf5"
author: "florip"
lastCopied: "2023-03-30T08:57:06Z"
properties:
properties: "var://idm-standard-settings"

View File

@ -0,0 +1,8 @@
schemaVersion: "1.0"
pattern:
id: "7076f2654dd4efa1675afc72"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.AutomaticTrustStoreProvider"
name: "IDP_Extended_Truststore"
notes: "Trusts the own CA and additionally the one needed for out-going calls.\n\
Currently those to nevisidm running in another admin administrated namespace."
properties: {}

View File

@ -0,0 +1,10 @@
schemaVersion: "1.0"
pattern:
id: "450d8070d6c0b395c98a013f"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.RESTServiceAccess"
name: "IDP_OIDC4VP_Service"
properties:
host:
- "pattern://1f0702aaabef60a615abf41f"
path: "/oidc4vp/"
backends: "var://eid-oidc4vp-service-url"

View File

@ -1,10 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "2d8151249e6734ccc072422b"
className: "ch.nevis.admin.v4.plugin.nevisproxy.patterns.AutomaticTrustStoreProvider"
name: "IdP-Idm-SecToken-Signer-Trust"
label: "STORE"
properties:
keystore:
- "pattern://aeb2fed9962dcd5f7893db51"
truststoreFile: "var://idp-idm-sectoken-signer-trust-additional-trusted-certificates"

View File

@ -1,9 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "a4c7f77128ea9a990291fe64"
className: "ch.nevis.admin.v4.plugin.nevisidm.patterns.CustomNevisIDMLogFile"
name: "Log_IDM"
label: "LOGS"
properties:
logLevel: "var://log_idm-default-log-level"
levels: "var://log_idm-log-levels"

View File

@ -11,6 +11,7 @@ pattern:
nextSteps:
- "pattern://f39352769cb2a1c88e1a176d"
- "pattern://d76231eaa88cb1645ce44cf3"
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://f63c475c35b616b7c6c1901c#resources"
keyObjects:
- "pattern://95220b3005deb118adeb01aa"

View File

@ -19,5 +19,6 @@ pattern:
- "pattern://7022472ae407577ae604bbb8"
logrend:
- "pattern://097929211988398a87bcbb0c"
defaultProperties: "var://nevislogrend-configuration-logrendproperties"
initialSessionTimeout: "var://idp-authentication-session-timeout"
langCookieDomain: "var://agov-language-cookie-domain"

View File

@ -12,4 +12,4 @@ pattern:
lastCopied: "2023-04-27T13:03:12Z"
properties:
nevisIDM:
- "pattern://b8a36646f81c3247cdb5d90b"
- "pattern://f1e0b2a7bc849ffc63a612e6"

View File

@ -10,6 +10,8 @@ pattern:
- "pattern://6061abea33a234fad73897b7"
onFailure:
- "pattern://473f9d6b4ab9d61c1eb8c689"
nextSteps:
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://4bc453bf68139ee87966b0c7#resources"
keyObjects:
- "pattern://95220b3005deb118adeb01aa"

View File

@ -8,4 +8,6 @@ pattern:
parameters: "var://service_provider_state-registration-template-parameters"
onSuccess:
- "pattern://f63c475c35b616b7c6c1901c"
nextSteps:
- "pattern://e335f57d4c64dfc97223697a"
resources: "res://bfd395eb0dab50aff2f2c01b#resources"

View File

@ -10,8 +10,7 @@ pattern:
- url: "${var.connect.metadataservice.url}"
- bestTokenAddressWhitelist: "${var.bestToken.address.whitelist}"
- bestTokenSvnrWhitelist: "${var.bestToken.svnr.whitelist}"
- eidPassthroughEnabled: "${var.eid.passthrough.enabled}"
- eidFullEnabled: "${var.eid.full.enabled}"
- eidEnabled: "${var.eid.enabled}"
onSuccess:
- "pattern://f63c475c35b616b7c6c1901c"
onFailure:

View File

@ -6,6 +6,6 @@ pattern:
label: "STS"
properties:
nevisIDM:
- "pattern://b8a36646f81c3247cdb5d90b"
- "pattern://f1e0b2a7bc849ffc63a612e6"
genericAuthPatterns:
- "pattern://5d7dc3d51416356293a239f7"

View File

@ -47,4 +47,4 @@ def agovLoginCookie = "agovLogin=deleted; Domain=${parameters.get('cookie.domain
response.setHeader('Set-Cookie', agovLoginCookie)
response.setResult('ok')
return
return

View File

@ -0,0 +1,56 @@
<AuthState name="${state.entry}" class="ch.nevis.idm.authstate.IdmUserVerifyState" final="false" resumeState="false">
<ResultCond name="prospect" next="${state.entry}_getProperties"/>
<ResultCond name="default" next="${state.failed}"/>
<ResultCond name="failed" next="${state.failed}"/>
<ResultCond name="clientNotFound" next="${state.failed}"/>
<Response value="AUTH_CONTINUE">
<Gui name="internal_error">
<GuiElem name="transferId" type="hidden" value="${request:traceId}" optional="true"/>
</Gui>
</Response>
<propertyRef name="nevisIDM_Connector"/>
<property name="userExtId" value="${session:agov.eid.linkedAccountExtId}"/>
<property name="clientExtId" value="${var.eid.idm.rest.clientExtId}"/>
<property name="presetNoteValues" value="false"/>
<property name="detaillevel.user" value="HIGH"/>
<property name="detaillevel.profile" value="HIGH"/>
<property name="detaillevel.role" value="MEDIUM"/>
<property name="detaillevel.authorization" value="HIGH"/>
<property name="detaillevel.dataroom" value="LOW"/>
<property name="detaillevel.credential" value="HIGH"/>
<property name="detaillevel.property" value="HIGH"/>
<property name="detaillevel.unit" value="LOW"/>
<property name="detaillevel.default" value="EXCLUDE"/>
</AuthState>
<!-- NOTE/aca/2025/06/15 Use the same detail levels as the agov login, so that we can switch to EnsureAccountState afterwards -->
<!-- We could potentially also just reuse the States form the regular login for this with some switches -->
<AuthState name="${state.entry}_getProperties" final="false" class="ch.nevis.idm.authstate.IdmGetPropertiesState" resumeState="false">
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="default" next="${state.failed}"/>
<ResultCond name="clientNotFound" next="${state.failed}"/>
<Response value="AUTH_CONTINUE">
<Gui name="internal_error">
<GuiElem name="transferId" type="hidden" value="${request:traceId}" optional="true"/>
</Gui>
</Response>
<propertyRef name="nevisIDM_Connector"/>
<property name="clientExtId" value="${var.eid.idm.rest.clientExtId}"/>
<property name="user.attributes" value="loginId,extId,firstName,name,email,mobile,birthDate, gender, language, street, houseNumber, postalCode, city, country"/>
<property name="user.properties" value="eIdNumber,nationality,placeOfBirth,svnr"/>
<property name="chooseDefaultProfile" value="true"/>
<property name="forceDataReload" value="false"/>
<property name="userExtId" value="${session:agov.eid.linkedAccountExtId}"/>
<property name="detaillevel.user" value="HIGH"/>
<property name="detaillevel.profile" value="HIGH"/>
<property name="detaillevel.role" value="HIGH"/>
<property name="detaillevel.authorization" value="HIGH"/>
<property name="detaillevel.dataroom" value="HIGH"/>
<property name="detaillevel.credential" value="HIGH"/>
<property name="detaillevel.property" value="HIGH"/>
<property name="detaillevel.unit" value="LOW"/>
<property name="detaillevel.default" value="EXCLUDE"/>
</AuthState>

View File

@ -35,7 +35,8 @@
</AuthState>
<AuthState name="${state.entry}_Handle_Redirect" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="agovLogin" next="${state.done}"/>
<ResultCond name="eidLogin" next="${state.exit.1}"/>
<Response value="AUTH_CONTINUE">
<Gui name="not_used"/>
</Response>

View File

@ -19,7 +19,15 @@ if(outargs.containsKey('saml.SAMLResponse')) {
response.removeOutArg('saml.SAMLResponse')
}
else {
response.setResult('ok')
if (session['agov.eidAllowed'] && session['agov.eidAllowed'] == 'true') {
if (session['agov.lastLoginMethod'] && !(session['agov.lastLoginMethod'] == 'eid')) {
response.setResult('agovLogin')
} else {
response.setResult('eidLogin')
}
} else {
response.setResult('agovLogin')
}
}

View File

@ -1,20 +1,24 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="error" next="${state.failed}"/>
<ResultCond name="error" next="${state.failed}"/>
<ResultCond name="ok" next="${state.done}"/>
<ResultCond name="agovLogin" next="${state.exit.1}"/>
<ResultCond name="register" next="${state.exit.2}"/>
<ResultCond name="default" next="${state.entry}"/>
<Response value="AUTH_CONTINUE">
<Gui name="eid_verification">
<GuiElem name="agov.appDisplayNameDE" type="hidden" value="${sess:agov.appDisplayNameDE}" optional="true"/>
<GuiElem name="agov.appDisplayNameFR" type="hidden" value="${sess:agov.appDisplayNameFR}" optional="true"/>
<GuiElem name="agov.appDisplayNameIT" type="hidden" value="${sess:agov.appDisplayNameIT}" optional="true"/>
<GuiElem name="agov.appDisplayNameEN" type="hidden" value="${sess:agov.appDisplayNameEN}" optional="true"/>
<GuiElem name="agov.appSamlRpEntityId" type="hidden" value="${var.appIconUrl}${sess:ch.nevis.auth.saml.request.scoping.requesterId}" optional="true"/>
<GuiElem name="agov.appDisplayNameDE" type="hidden" value="${sess:agov.appDisplayNameDE}" optional="true"/>
<GuiElem name="agov.appDisplayNameFR" type="hidden" value="${sess:agov.appDisplayNameFR}" optional="true"/>
<GuiElem name="agov.appDisplayNameIT" type="hidden" value="${sess:agov.appDisplayNameIT}" optional="true"/>
<GuiElem name="agov.appDisplayNameEN" type="hidden" value="${sess:agov.appDisplayNameEN}" optional="true"/>
<GuiElem name="agov.appDisplayNameRM" type="hidden" value="${sess:agov.appDisplayNameRM}" optional="true"/>
<GuiElem name="agov.appSamlRpEntityId" type="hidden" value="${var.appIconUrl}${sess:ch.nevis.auth.saml.request.scoping.requesterId}" optional="true"/>
<GuiElem name="authRequestId" type="hidden" value="${sess:ch.nevis.auth.saml.request.id}" optional="true"/>
<GuiElem name="oid4vp" type="hidden" value="UNKNOWN" optional="true"/>
<GuiElem name="eidOnly" type="hidden" value="${sess:agov.requestedRoleLevel:^[56]00$:true}" optional="true"/>
</Gui>
</Response>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_verification_auth.groovy"/>
<property name="parameter.eidVerifierBaseUrl" value="${var.eidVerifierBaseUrl}"/>
<property name="parameter.eidUUIDNamespace" value="${var.eidUUIDNamespace}"/>
<property name="parameter.eidUUIDNamespace" value="${var.eidUUIDNamespace}"/>
</AuthState>

View File

@ -4,6 +4,10 @@ import ch.nevis.esauth.util.httpclient.api.HttpClient
import groovy.json.JsonSlurper
import io.opentelemetry.api.trace.Span
import java.time.LocalDate
import java.time.ZoneId
import java.time.ZoneOffset
import com.fasterxml.uuid.Generators
def getHeader(String name) {
@ -57,6 +61,13 @@ def getNewVerification(Session sess, HttpClient httpClient, String verification_
return true
}
def clearEidSession(){
def s = request.getAuthSession(true)
s.removeAttribute('agov.eid.verification')
s.removeAttribute('agov.eid.verification.id')
s.removeAttribute('agov.eid.verification.link')
}
def verification_request_template = '''
{ "presentation_definition": {
"id": "{{UUID}}",
@ -211,29 +222,39 @@ if (inargs['oid4vp'] == 'SUCCEEDED') {
return
}
/*
// Temporary for CANCELED
if (inargs['oid4vp'] == 'CANCELED') {
LOG.debug("oid4vp canceled")
response.setResult('error')
// switch to access App
if (inargs['accessApp'] == 'accessApp') {
//TODO/aca/2025/06/19: In theory we could also land here when we send 'SUCCESS' to the frontend -> would be better to clear all session vaiables that can be set in this Authstate
//TODO/aca/2025/06/19: Should we here rather set the LOGINMETHOD cookie and send an error assertion, since otherwise we might swich states too often and Nevis will kill the session?
clearEidSession()
LOG.debug("Switch to Access App")
sess.setAttribute('agov.lastLoginMethod', 'accessApp')
response.setResult('agovLogin')
return
}
// switch to fido2
if (inargs['securityKey'] == 'securityKey') {
clearEidSession()
LOG.debug("Switch to Security Key")
sess.setAttribute('agov.lastLoginMethod', 'securityKey')
response.setResult('agovLogin')
return
}
// switch to registration
if (inargs['fallback'] == 'register') {
clearEidSession()
LOG.debug("Switch to registration")
response.setResult('register')
return
}
*/
HttpClient httpClient = HttpClients.create(parameters)
def spanCtxt = Span.current().getSpanContext()
def traceparent = "00-${spanCtxt.getTraceId()}-${spanCtxt.getSpanId()}-${spanCtxt.getTraceFlags().asHex()}"
/*
if (!session['agov.eid.verification']) {
LOG.debug("Initializing verification")
if(!getNewVerification(sess, httpClient, verification_request_template, traceparent)){
response.setResult('error')
return
}
}
*/
if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.v')) {
LOG.debug("Request Status Update")
@ -300,7 +321,7 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
"error_code": "HTTP-ERROR",
"error_message": "Faild to verify status of verification, http status: ${httpResponse.code()}"
}}"""
LOG.warn("<== Response: ${responseCode}")
LOG.warn("<== Response: ${httpResponse.code()}")
}
else if (httpResponse.code() != 200) {
LOG.debug("Result: ${httpResponse}")
@ -315,7 +336,7 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
"error_code": "HTTP-ERROR",
"error_message": "failed to verify status of verification ${idvalue}, http status: ${httpResponse.code()}"
}}"""
LOG.warn("<== Response: ${responseCode}")
LOG.warn("<== Response: ${httpResponse.code()}")
}
else {
@ -324,25 +345,37 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
if (json.state == 'SUCCESS') {
def claims = json.wallet_response.credential_subject_data
LOG.debug("Store user data in session")
// TODO/haburger/2025-03-25: format changes to align with IDM read data => No changes needed(?)
sess.setAttribute('ch.nevis.idm.User.firstName', claims.given_name)
sess.setAttribute('ch.nevis.idm.User.lastName', claims.family_name)
sess.setAttribute('ch.nevis.idm.User.birthDate', claims.birth_date)
sess.setAttribute('ch.nevis.idm.User.gender', claims.sex)
sess.setAttribute('ch.nevis.idm.User.prop.svnr', claims.personal_administrative_number.replace('.',''))
sess.setAttribute('ch.nevis.idm.User.prop.placeOfBirth', claims.birth_place)
sess.setAttribute('ch.nevis.idm.User.prop.eIdNumber', claims.document_number)
sess.setAttribute('ch.nevis.idm.User.prop.nationality', claims.nationality.toString())
sess.setAttribute('ValidFrom', claims.issuance_date)
sess.setAttribute('ValidTo', claims.expiry_date)
def validFrom = LocalDate.parse(claims.issuance_date, DateTimeFormatter.ISO_LOCAL_DATE).atStartOfDay(ZoneId.systemDefault()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
def validTo = LocalDate.parse(claims.expiry_date, DateTimeFormatter.ISO_LOCAL_DATE).atTime(23,59,59).atOffset(ZoneOffset.systemDefault()).format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
sess.setAttribute('agov.eid.User.firstName', claims.given_name)
sess.setAttribute('agov.eid.User.lastName', claims.family_name)
sess.setAttribute('agov.eid.User.birthDate', claims.birth_date)
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.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())
sess.setAttribute('ValidFrom', validFrom)
sess.setAttribute('ValidTo', validTo)
sess.setAttribute('authenticatedWith', "urn:qa.agov.ch:names:tc:authfactor:eid")
sess.setAttribute('idVerification', "Eid")
sess.setAttribute('contextClassRefToSet', "urn:qa.agov.ch:names:tc:ac:classes:600")
// BUNDBITBK-5203 Dynamic aq levels
def requestedRoleLevel = session['agov.requestedRoleLevel']
if(requestedRoleLevel == "600"){
sess.setAttribute('contextClassRefToSet', "urn:qa.agov.ch:names:tc:ac:classes:600")
}else{
sess.setAttribute('contextClassRefToSet', "urn:qa.agov.ch:names:tc:ac:classes:500")
}
// subjectUUID v5
def namespace = UUID.fromString(parameters.get('eidUUIDNamespace'))
def uuid = Generators.nameBasedGenerator(namespace).generate(claims.personal_administrative_number)
LOG.debug("UUID: ${uuid}")
LOG.debug("UUID derived from svnr: ${uuid}")
String uuidString = uuid.toString()
sess.setAttribute('agov.subjectUUID', '' + uuidString)
@ -360,9 +393,6 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
}}"""
}
else if (json.state == 'FAILED') {
// TODO/haburger/2025-03-25: ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] == 'FAILED' we should
// initiate a new verification and return the new id, url together with the message
LOG
.error("Eid verification failed: ${json.wallet_response.error_code} (${json.wallet_response.error_description})")
@ -410,14 +440,11 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
}}"""
}
response.setContent(result.toString())
response.setContentType('application/json')
response.setHttpStatusCode(200)
response.setIsDirectResponse(true)
response.setStatus(AuthResponse.AUTH_CONTINUE)
LOG.debug("Recieved json: End")
return
}

View File

@ -5,7 +5,7 @@
<Response value="AUTH_CONTINUE"/>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/ensureAccountState.groovy"/>
<property name="parameter.idm.baseUrl" value="https://${param.idm-service}:8989/nevisidm/api"/>
<property name="parameter.idm.baseUrl" value="https://${var.idm-connection-fqdn}:8989/nevisidm/api"/>
<property name="parameter.unitExtid" value="${param.agov.unitExtId}"/>
<property name="parameter.level100.roleExtid" value="${param.agov.level100.roleExtid}"/>
<property name="parameter.idm.httpclient.tls.trustStoreRef" value="Ensure_Account_State"/>

View File

@ -1,6 +1,7 @@
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<ResultCond name="registration" next="${state.exit.2}"/>
<ResultCond name="fido2" next="${state.exit.1}"/>
<ResultCond name="fido2" next="${state.exit.1}"/>
<ResultCond name="eidLogin" next="${state.exit.3}"/>
<ResultCond name="ok" next="${state.entry}_Processing"/>
<ResultCond name="default" next="${state.entry}"/>
<Response value="AUTH_CONTINUE">
@ -11,7 +12,7 @@
<GuiElem name="agov.appDisplayNameEN" type="hidden" value="${sess:agov.appDisplayNameEN}" optional="true"/>
<GuiElem name="agov.appSamlRpEntityId" type="hidden" value="${var.appIconUrl}${sess:ch.nevis.auth.saml.request.scoping.requesterId}" optional="true"/>
<GuiElem name="authRequestId" type="hidden" value="${sess:ch.nevis.auth.saml.request.id}" optional="true"/>
<GuiElem name="lastLoginMethod" type="hidden" value="${cookie:LOGINMETHOD}" optional="true"/>
<GuiElem name="lastLoginMethod" type="hidden" value="${sess:agov.lastLoginMethod}" optional="true"/>
<GuiElem name="fallback" type="button" label="mobile_auth.cancel.button.label" value="true" optional="true"/>
</Gui>
</Response>

View File

@ -103,4 +103,11 @@ if (inargs.containsKey('onReload')) {
// dispatch form post with fallback input field : go to registration with right loa
if (inargs['fallback'] == 'register') {
response.setResult('registration')
}
// change to eid
// temporary for demo
if (inargs.containsKey('swiyu')) {
clearFidoUAFSession()
response.setResult('eidLogin')
}

View File

@ -12,6 +12,8 @@ pattern:
- "pattern://b7b59e97b3fd18bb60178573"
frontendTrustStore:
- "pattern://c0722fc79e7314c9cdcd20ff"
backendTrustStore:
- "pattern://7076f2654dd4efa1675afc72"
signerKeyStore:
- "pattern://aeb2fed9962dcd5f7893db51"
signerTrustStore:

View File

@ -10,6 +10,8 @@ pattern:
- "pattern://aec56cb572434a42d55de30c"
frontendTrustStore:
- "pattern://c0722fc79e7314c9cdcd20ff"
backendTrustStore:
- "pattern://7076f2654dd4efa1675afc72"
signerKeyStore:
- "pattern://aeb2fed9962dcd5f7893db51"
idPregenerate: "enabled"

View File

@ -16,7 +16,9 @@ pattern:
relyingPartyId: "var://nevisfido2-relying-party-id"
relyingPartyOrigins: "var://nevisfido2-relying-party-origins"
idm:
- "pattern://b8a36646f81c3247cdb5d90b"
client: "cfa9c9b9-119f-4dff-9bb8-86d7c0cf2720"
- "pattern://f1e0b2a7bc849ffc63a612e6"
client: "var://idm-agov-client-extid"
serverTrustStore:
- "pattern://7076f2654dd4efa1675afc72"
addons:
- "pattern://90af8358cc587f5c5aa79fec"

View File

@ -0,0 +1,10 @@
schemaVersion: "1.0"
pattern:
id: "f1e0b2a7bc849ffc63a612e6"
className: "ch.nevis.admin.v4.plugin.nevisidm.patterns.NevisIDMConnector"
name: "nevisIDM_Connector"
label: "UTILS"
properties:
url: "var://idm-connection-url"
kubernetes: "other_namespace"
kubernetesNamespace: "var://idm-connection-namespace"

View File

@ -1,26 +0,0 @@
schemaVersion: "1.0"
pattern:
id: "b8a36646f81c3247cdb5d90b"
className: "ch.nevis.admin.v4.plugin.nevisidm.patterns.NevisIDMDeployable"
name: "nevisIDM"
deploymentHosts: "idm"
label: "IDM"
properties:
encryptionKey: "var://nevisidm-encryption-key"
frontendTrustStore:
- "pattern://c0722fc79e7314c9cdcd20ff"
authSignerTrustStore:
- "pattern://2d8151249e6734ccc072422b"
database:
- "pattern://2951ead44a7a9362a4545094"
logging:
- "pattern://a4c7f77128ea9a990291fe64"
mailSMTPHost: "var://nevisidm-smtp-host"
mailSMTPPort: "var://nevisidm-smtp-port"
smtpTLSMode: "var://nevisidm-smtp-ssltls-mode"
mailSMTPUser: "var://nevisidm-smtp-user"
mailSMTPPass: "var://nevisidm-smtp-password"
mailSenderAddress: "var://nevisidm-mail-sender"
addons:
- "pattern://71411a755a625f9b850c6cf5"
- "pattern://90af8358cc587f5c5aa79fec"

View File

@ -7,35 +7,6 @@ variables:
maxAllowed: 1
value: ".agov-d.azure.adnovum.net"
requireOverloading: true
agov_dev_idm-db-management:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 1
maxAllowed: 1
options:
- "complete"
- "schema"
- "disabled"
value: "complete"
requireOverloading: true
agov_dev_idm_db-db-management:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 1
maxAllowed: 1
options:
- "complete"
- "schema"
- "disabled"
value: "disabled"
requireOverloading: true
ask_mobile_number-template-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters:
required: false
syntax: "YAML"
value: "idm-service: idm\n"
requireOverloading: true
auth-session-store-database-host:
className: "ch.nevis.admin.v4.plugin.base.generation.property.HostPortProperty"
parameters:
@ -181,6 +152,17 @@ variables:
\ font-src 'self';"
- param_report_only_csp: "none"
requireOverloading: true
eid-oidc4vp-service-url:
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://eid-verifier-oid4vp.adn-agov-eid-01-dev:8081/api"
requireOverloading: true
ensure_recovery_code-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters:
@ -235,10 +217,10 @@ variables:
parameters:
required: false
syntax: "YAML"
value: "url: \"https://idm:8989/nevisidm\"\nclient.name: agov\nattributes: loginId,extId,firstName,name,email,mobile\n\
properties: eIdNumber,gender,placeOfBirth,svnr\nidm-service: idm\nagov.unitExtId:\
\ 1000\nagov.level100.roleExtid: aee52e9f-7084-4e55-9aea-9383ac7757f7"
requireOverloading: true
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"
requireOverloading: false
fido-session-store-database-host:
className: "ch.nevis.admin.v4.plugin.base.generation.property.HostPortProperty"
parameters:
@ -339,13 +321,6 @@ variables:
minRequired: 0
value: null
requireOverloading: true
fido_uaf_instance-client-id:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 1
maxAllowed: 1
value: "agov"
requireOverloading: true
fido_uaf_instance-custom-uri-link:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
@ -381,147 +356,39 @@ variables:
pathInputMode: "NONE"
value: null
requireOverloading: true
idm-standard-settings:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
idm-agov-client-extid:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
separators:
- "="
switchedSeparators: []
valueFormat: ".*"
minRequired: 1
maxAllowed: 1
value: "cfa9c9b9-119f-4dff-9bb8-86d7c0cf2720"
requireOverloading: false
idm-agov-client-name:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 1
maxAllowed: 1
value:
- application.feature.multiclientmode.enabled: "true"
- application.modules.auditing.enabled: "true"
- application.feature.email.validation.enabled: "false"
- application.generators.extid.client: "uuid"
- application.generators.extid.user: "uuid"
- application.generators.extid.profile: "uuid"
- application.generators.extid.unit: "uuid"
- application.generators.extid.credential: "uuid"
- application.generators.extid.application: "uuid"
- application.generators.extid.role: "uuid"
- application.generators.extid.policyconfig: "uuid"
- application.generators.extid.template: "uuid"
- application.generators.extid.enterpriserole: "uuid"
- application.generators.extid.authorization: "uuid"
- application.modules.event.repeat.count: "0"
- application.modules.event.autostartup.enabled: "false"
- application.modules.auditing.autostartup.enabled: "false"
- application.modules.auditing.repeat.count: "0"
- application.modules.provisioning.enabled: "false"
- database.connection.xa.enabled: "false"
- database.connection.pool.size.min: "5"
- database.connection.pool.size.max: "10"
requireOverloading: true
idm_db-database-connection-url:
- "agov"
requireOverloading: false
idm-connection-namespace:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: null
requireOverloading: true
idm_db-database-host:
className: "ch.nevis.admin.v4.plugin.base.generation.property.HostPortProperty"
parameters:
minRequired: 0
maxAllowed: 2
portRequired: false
value: "mariadb-agov-dev.mariadb.database.azure.com:3306"
requireOverloading: true
idm_db-database-jdbc-driver:
className: "ch.nevis.admin.v4.plugin.base.generation.property.AttachmentProperty"
parameters:
minRequired: 0
maxAllowed: 1
allowedFileName: ".*\\.jar"
value: null
requireOverloading: true
idm_db-database-name:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
value: "agov-nevisidm-admin-01-prod-p"
requireOverloading: false
idm-connection-url:
className: "ch.nevis.admin.v4.plugin.base.generation.property.URLProperty"
parameters:
minRequired: 1
maxAllowed: 1
value: "nevisidm_dev"
requireOverloading: true
idm_db-database-password:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
secret: true
value: "sample password"
requireOverloading: true
idm_db-database-type:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 1
maxAllowed: 1
options:
- "MariaDB"
- "Oracle"
- "PostgreSQL"
value: "Oracle"
requireOverloading: true
idm_db-database-user:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "adndbadmin"
requireOverloading: true
idm_db-database-volume-claim:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: null
requireOverloading: true
idm_db-root-credential:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "root-adn-agov-nevisidm-01-dev-idm"
requireOverloading: true
idm_db-root-credential-namespace:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "adn-agov-nevisidm-01-dev-idm"
requireOverloading: true
idm_db-tls-encryption:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 1
maxAllowed: 1
options:
- "disabled"
- "trust"
- "verify-ca"
- "verify-full"
value: "trust"
requireOverloading: true
idm_db_tls_truststore-trusted-certificates:
className: "ch.nevis.admin.v4.plugin.base.generation.property.AttachmentProperty"
parameters:
minRequired: 0
secretPreserving: true
value: null
requireOverloading: true
idm_post_processing-template-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters:
required: false
syntax: "YAML"
value: "attributes: loginId,extId,firstName,name,email"
requireOverloading: true
idm_x509_state-template-parameters:
className: "ch.nevis.admin.v4.plugin.base.generation.property.TextProperty"
parameters:
required: false
syntax: "YAML"
value: "client.name: Default"
requireOverloading: true
schemeInputMode: "OPTIONAL"
allowedSchemes: "https"
hostNameInputMode: "REQUIRED"
portInputMode: "REQUIRED"
pathInputMode: "NONE"
value: "idm:8989"
requireOverloading: false
idp-authentication-session-timeout:
className: "ch.nevis.admin.v4.plugin.base.generation.property.DurationProperty"
parameters:
@ -538,12 +405,6 @@ variables:
value: "cors.allowed.fqdns: '{\"trustbroker.agov-d.azure.adnovum.net\", \"auth.agov-d.azure.adnovum.net\"\
}'"
requireOverloading: true
idp-idm-sectoken-signer-trust-additional-trusted-certificates:
className: "ch.nevis.admin.v4.plugin.base.generation.property.AttachmentProperty"
parameters:
minRequired: 0
value: null
requireOverloading: true
idp-sp-connector-properties:
className: "ch.nevis.admin.v4.plugin.base.generation.property.AuthStateProperty"
parameters:
@ -644,16 +505,21 @@ variables:
- "INFO"
- "DEBUG"
- "TRACE"
value: "INFO"
requireOverloading: true
value: "WARN"
requireOverloading: false
log_auth-log-levels:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters:
separators:
- "="
switchedSeparators: []
value: []
requireOverloading: true
value:
- AuthPerf: "INFO"
- AGOV-ACCT: "INFO"
- AgovCaptcha: "INFO"
- IdmAuth: "ERROR"
- OpTrace: "INFO"
requireOverloading: false
log_fido2-default-log-level:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
@ -665,16 +531,17 @@ variables:
- "INFO"
- "DEBUG"
- "TRACE"
value: "DEBUG"
requireOverloading: true
value: "WARN"
requireOverloading: false
log_fido2-log-levels:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters:
separators:
- "="
switchedSeparators: []
value: null
requireOverloading: true
value:
- OpTrace: "INFO"
requireOverloading: false
log_fido_uaf-default-log-level:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
@ -686,8 +553,8 @@ variables:
- "INFO"
- "DEBUG"
- "TRACE"
value: "INFO"
requireOverloading: true
value: "WARN"
requireOverloading: false
log_fido_uaf-log-levels:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters:
@ -695,29 +562,8 @@ variables:
- "="
switchedSeparators: []
value:
- OpTrace: "DEBUG"
requireOverloading: true
log_idm-default-log-level:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 0
maxAllowed: 1
options:
- "ERROR"
- "WARN"
- "INFO"
- "DEBUG"
- "TRACE"
value: "INFO"
requireOverloading: true
log_idm-log-levels:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters:
separators:
- "="
switchedSeparators: []
value: null
requireOverloading: true
- OpTrace: "INFO"
requireOverloading: false
log_proxy-default-log-level:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
@ -730,8 +576,8 @@ variables:
- "DEBUG"
- "DEBUG_HIGH"
- "TRACE"
value: "DEBUG"
requireOverloading: true
value: "NOTICE"
requireOverloading: false
log_proxy-log-levels:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters:
@ -739,8 +585,10 @@ variables:
- "="
- ":"
switchedSeparators: []
value: null
requireOverloading: true
value:
- IsiwebOp: "INFO"
- NavajoOp: "INFO"
requireOverloading: false
nevisfido2-relying-party-id:
className: "ch.nevis.admin.v4.plugin.base.generation.property.HostProperty"
parameters:
@ -772,74 +620,6 @@ variables:
minRequired: 0
value: null
requireOverloading: true
nevisidm-custom-property-svnr-client-external-id:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "cfa9c9b9-119f-4dff-9bb8-86d7c0cf2720"
requireOverloading: true
nevisidm-database-root-credential:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "username: <root-user> password: <root-password>"
requireOverloading: true
nevisidm-encryption-key:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 1
maxAllowed: 1
secret: true
value: "this a sample password"
requireOverloading: true
nevisidm-mail-sender:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
format: "^\\S+@\\S+$"
value: "noreply-agov-dev@adnovum.ch"
requireOverloading: true
nevisidm-smtp-host:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "greenmail.adn-agov-mail-01-dev.svc"
requireOverloading: true
nevisidm-smtp-password:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: null
requireOverloading: true
nevisidm-smtp-port:
className: "ch.nevis.admin.v4.plugin.base.generation.property.PortProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: "3025"
requireOverloading: true
nevisidm-smtp-ssltls-mode:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SelectionProperty"
parameters:
minRequired: 0
maxAllowed: 1
options:
- "disabled"
- "STARTTLS"
value: "disabled"
requireOverloading: true
nevisidm-smtp-user:
className: "ch.nevis.admin.v4.plugin.base.generation.property.SimpleTextProperty"
parameters:
minRequired: 0
maxAllowed: 1
value: null
requireOverloading: true
nevislogrend-configuration-logrendproperties:
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
parameters: {}