import org.codehaus.groovy.runtime.StackTraceUtils import groovy.xml.XmlSlurper def getUserAGOVLoiRoles() { // set attibutes from DTO: -> AGOVaq def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return list.'**'.findAll { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-Loi' }.collect({ node -> node.name.text() }) } def getUserAGOVRecoveryRoles() { // set attibutes from DTO: -> AGOV def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return list.'**'.findAll { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' }.collect({ node -> node.name.text() }) } def getUserAGOVLoiIdVerification() { // set attibutes from DTO: -> idVerification def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return list.'**'.findAll {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text().contains('AGOV-Loi,')}.collect({ node -> node.value.text()}) } def getUserAGOVLoiIdVerification(level) { // set attibutes from DTO: -> idVerification def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return list.'**'.findAll {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,level' + level}.collect({ node -> node.value.text()}) } def getUserAGOVLoiValidFrom(level) { // set attibutes from DTO: -> validFrom def payload = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return payload.'**'.find {node -> node.name() == 'authorizations' && node.role.name.text() == level}?.validFrom?.text() } def getUserAGOVLoiValidTo(level) { // set attibutes from DTO: -> validTo def payload = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) return payload.'**'.find {node -> node.name() == 'authorizations' && node.role.name.text() == level}?.validTo?.text() } def getUserIdVerificationForRecovery() { // application is AGOV-AccountStatus def list = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) def result = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-AccountStatus,mustRecover'}?.value?.text() if (!result) { // fallback if not explicitly set def currentLoaRole = getUserAGOVLoiRoles()?.sort()?.last() ?: 'level100' def chDomicile = list.country.text() == 'ch' def lastIdVerification = list.'**'.find {node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + currentLoaRole}?.value?.text() switch (currentLoaRole) { case 'level100': result = chDomicile ? 'SimpleLetter' : 'Video' break case 'level200': result = chDomicile ? 'Bmid' : 'Video' break case 'level300': case 'level400': result = chDomicile ? lastIdVerification : 'Video' break default: LOG.warn("unexpected loa on account: ${currentLoaRole}") // safest default, should work in any case result = 'Video' } LOG.warn("Recovery method not set, choosing ${result} (based on currentLoad: ${currentLoaRole}, CH-domicile: ${chDomicile}, last verification method: ${lastIdVerification})") } return result } def getAqLevelBasedOnIdVerificationForRecovery(idVerification, highestRoleLevelNumber) { def result = 'urn:qa.agov.ch:names:tc:ac:classes:' switch (idVerification) { case 'None': result = result.concat('100') break case 'SimpleLetter': result = result.concat('200') break case 'Video': case 'VideoSelfPaid': case 'Bmid': case 'BmidSelfPaid': case 'Counter': result = result.concat((highestRoleLevelNumber == 400) ? '400' : '300') break default: LOG.warn("unexpected idVerification for recovery on account: ${idVerification}") // safest default, should work in any case result = result.concat('' + highestRoleLevelNumber) } return result } def getUserMustRecoverValidFrom() { // set attibutes from DTO: -> validFrom def payload = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto')) def authzNode = payload.'**'.find {node -> node.name() == 'authorizations' && node.role.name.text() == 'mustRecover'} return (authzNode) ? ((authzNode.validFrom && !authzNode.validFrom.text().isEmpty()) ? authzNode.validFrom?.text() : authzNode.ctlCreDat?.text()) : '' } // 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' try { // beef def session = request.getAuthSession(true) def highestRoleLevelNumber = 0 def requestedRoleLevelNumber = session.get('agov.requestedRoleLevel').toInteger() def adressVerificationList = getUserAGOVLoiIdVerification('200') def adressVerification = 'None' if (adressVerificationList && !adressVerificationList.isEmpty()) { adressVerification = adressVerificationList[0] } LOG.debug('CheckLoa: Requested role level '+ requestedRoleLevelNumber) LOG.debug('CheckLoa: idVerification: ' + getUserAGOVLoiIdVerification()) LOG.debug('CheckLoa: adressVerification : ' + adressVerification) def idVerificationMethodList = getUserAGOVLoiIdVerification() session.setAttribute('idVerification', idVerificationMethodList.isEmpty() ? 'None' : idVerificationMethodList.last()) session.setAttribute('agov.adressVerification', '' + adressVerification) if (requestedRoleLevelNumber == 0) { // AuthnFailed_Zero_RoleLvl response.setResult('error'); return } if (session.get('ch.adnovum.nevisidm.profileExtId') == '') { LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', errorMessage='Account without Profile', SourceIp=${sourceIp}, UserAgent='${userAgent}'") session.setAttribute('contextClassRefToSet', 'urn:qa.agov.ch:names:tc:ac:classes:100') response.setResult('ok') return } // Transform sex to number if(session.get('ch.nevis.idm.User.gender') == 'MALE'){ session.setAttribute('ch.nevis.idm.User.gender', '1') } if(session.get('ch.nevis.idm.User.gender') == 'FEMALE'){ session.setAttribute('ch.nevis.idm.User.gender', '2') } if(session.get('ch.nevis.idm.User.gender') == 'OTHER'){ 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 (highestRoleLevelNumber == 0) { highestRoleLevelNumber = roleLevelNumber } if (highestRoleLevelNumber< roleLevelNumber) { highestRoleLevelNumber=roleLevelNumber } } } LOG.debug('CheckLoa: Highest role Level' + highestRoleLevelNumber.toString() +' contextclassref' + requestedRoleLevelNumber.toString()) LOG.debug('CheckLoa: Compare' + (highestRoleLevelNumber>=requestedRoleLevelNumber)) //set attribute Actual Role Level session.setAttribute('agov.actualRoleLevel', '' + highestRoleLevelNumber) LOG.debug('CheckLoa: actual role level (agov) '+ highestRoleLevelNumber) if (highestRoleLevelNumber > 0) { // set attribute contextClassRefToSet session.setAttribute('contextClassRefToSet','urn:qa.agov.ch:names:tc:ac:classes:' .concat(highestRoleLevelNumber.toString())) } else { // by default 100 session.setAttribute('contextClassRefToSet','urn:qa.agov.ch:names:tc:ac:classes:100' ) } // no login for users with a recovery role for (String role : getUserAGOVRecoveryRoles()) { if (role == 'mustRecover') { session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:mustRecover') session.setAttribute('agov.recovery.authenticatedWith', session.getAttribute('authenticatedWith') ?: 'unknown' ) def origIdVerification = getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString()) ?: 'None' def idVerification = getUserIdVerificationForRecovery() ?: origIdVerification session.setAttribute('agov.recovery.currentIdVerification', '' + idVerification ) // align currentAgovAq with the method selected for idVerification def currentAgovAqForRecovery = getAqLevelBasedOnIdVerificationForRecovery(idVerification, highestRoleLevelNumber) session.setAttribute('agov.recovery.currentAgovAq', '' + currentAgovAqForRecovery) def validFrom = getUserMustRecoverValidFrom() ?: '' session.setAttribute('agov.recovery.currentAgovAqRoleValidFrom', '' + validFrom ) LOG.debug("CheckLoa: mustRecover: origIdVerification=${origIdVerification}, idVerification=${idVerification}, currentAgovAqForRecovery=${currentAgovAqForRecovery}") response.setResult('exit.2') return } else if (role == 'recovery') { session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recovery') session.setAttribute('agov.recovery.authenticatedWith', session.getAttribute('authenticatedWith') ?: 'unknown') session.setAttribute('agov.recovery.currentAgovAq', session.getAttribute('contextClassRefToSet') ?: 'urn:qa.agov.ch:names:tc:ac:classes:100' ) LOG.debug('CheckLoa: idVerification2= '+ getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString())) def idVerification = getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString()) session.setAttribute('agov.recovery.currentIdVerification', (idVerification.isEmpty() ? 'None' : idVerification.first())) def validFrom = getUserAGOVLoiValidFrom('level'.concat(highestRoleLevelNumber.toString())) ?: '' session.setAttribute('agov.recovery.currentAgovAqRoleValidFrom', validFrom) response.setResult('exit.2') return } } if (highestRoleLevelNumber>=requestedRoleLevelNumber) { // set attribute ValidFrom and ValidTo (only for higher than 100) if (highestRoleLevelNumber > 100) { def validFrom = getUserAGOVLoiValidFrom('level'.concat(highestRoleLevelNumber.toString())) def validTo = getUserAGOVLoiValidTo('level'.concat(highestRoleLevelNumber.toString())) LOG.debug('CheckLoa: ValidFrom :' + validFrom) LOG.debug('CheckLoa: ValidTo :' + validTo) if(validFrom != '') { session.setAttribute('ValidFrom', '' + validFrom) } if(validTo != '') { session.setAttribute('ValidTo', '' + validTo) } } response.setResult('ok') return; } else { // Insufficient_LoaInfo response.setResult('exit.1'); return; } } catch (Exception ex) { LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', errorMessage='exception occured: ${ex}', SourceIp=${sourceIp}, UserAgent='${userAgent}'") ex = StackTraceUtils.sanitize(ex) def affectedLines = ex.stackTrace.findAll { it.className.startsWith('Script') }.collect { "${it.methodName}:${it.lineNumber}" } LOG.error("FATAL: Script failure (at lines: ${affectedLines})", ex) // AuthnFailed_Zero_RoleLvl response.setResult('error'); return; }