BUNDBITBK-4105

This commit is contained in:
haburger 2025-01-09 14:38:45 +00:00
parent e7d921f415
commit 83f8f527e7
3 changed files with 33 additions and 13 deletions

View File

@ -201,16 +201,16 @@
<property name="script" value="file:///var/opt/nevisauth/default/conf/recovery-processing.groovy"/>
</AuthState>
<AuthState name="${state.entry}_IdmUserIdPasswordLogin" final="true" resumeState="true" class="ch.nevis.idm.authstate.IdmPasswordVerifyState">
<ResultCond name="no_code-true" next="${state.exit.1}"/>
<ResultCond name="no_code-true" next="${state.entry}_codeSkipped"/>
<ResultCond name="ok" next="${state.entry}_codeVerified"/>
<ResultCond name="pwChange" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="lockWarn" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="nowLocked" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="locked" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="tmpLocked" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="failed" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="pwChange" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="lockWarn" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="nowLocked" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="locked" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="tmpLocked" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="failed" next="${state.entry}_saveDetailStatus"/>
<ResultCond name="clientNotFound" next="${state.failed}"/>
<ResultCond name="disabled" next="${state.entry}_IdmUserIdPasswordLogin"/>
<ResultCond name="disabled" next="${state.entry}_saveDetailStatus"/>
<Response value="AUTH_CONTINUE">
<Gui name="recovery_check_code">
<GuiElem name="lasterror" type="error" label="${notes:lasterrorinfo}" value="#{ notes.containsKey('lasterror') ? ((notes.getProperty('lasterror') == '1' or notes.getProperty('lasterror') == '3') ? 'check' : 'locked' ): '' }"/>
@ -231,4 +231,16 @@
<ResultCond name="default" next="${state.exit.1}"/>
<Response value="AUTH_CONTINUE"/>
<property name="sess:agov.recovery.authenticatedWith" value="urn:qa.agov.ch:names:tc:authfactor:emailAndCode"/>
<property name="sess:agov.recovery.codeStatus" value="verified"/>
</AuthState>
<AuthState name="${state.entry}_codeSkipped" class="ch.nevis.esauth.auth.states.standard.TransformAttributes" final="false" resumeState="false">
<ResultCond name="default" next="${state.exit.1}"/>
<Response value="AUTH_CONTINUE"/>
<property name="sess:agov.recovery.codeStatus" value="skipped"/>
<property name="${sess:agov.recovery.codeDetailStatus}==n/a?sess:agov.recovery.codeDetailStatus" value="directly skipped by user"/>
</AuthState>
<AuthState name="${state.entry}_saveDetailStatus" class="ch.nevis.esauth.auth.states.standard.TransformAttributes" final="false" resumeState="false">
<ResultCond name="default" next="${state.entry}_IdmUserIdPasswordLogin"/>
<Response value="AUTH_CONTINUE"/>
<property name="sess:agov.recovery.codeDetailStatus" value="${notes:lasterrorinfo} (${notes:lasterror})"/>
</AuthState>

View File

@ -101,6 +101,8 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recovery')
session.setAttribute('agov.recovery.authenticatedWith', 'urn:qa.agov.ch:names:tc:authfactor:email')
session.setAttribute('agov.recovery.codeStatus', 'notNeeded')
session.setAttribute('agov.recovery.codeDetailStatus', 'n/a')
def maxLoiList = userDto.'**'.findAll { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-Loi' }.collect({ node -> node.name.text() })
maxLoi = (maxLoiList == null || maxLoiList.isEmpty()) ? null : maxLoiList.sort().last()
@ -108,6 +110,10 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
def idVerification = null
def agovAqValidFrom = null
if (maxLoi) {
if (maxLoi != 'level100') {
session.setAttribute('agov.recovery.codeDetailStatus', '' + maxLoi)
}
idVerification = userDto.'**'.find { node -> node.name() == 'properties' && node.name.text() == 'idVerification' && node.scopeName.text() == 'AGOV-Loi,' + maxLoi}?.value?.text()
idVerification = idVerification ?: 'None'
agovAqValidFrom = userDto.'**'.find { node -> node.name() == 'authorizations' && node.role.name.text() == maxLoi}?.validFrom?.text()
@ -122,6 +128,7 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
if (mustRecover) {
// attributes are defined over the mustRecover authorization
session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:mustRecover')
session.setAttribute('agov.recovery.codeDetailStatus', 'mustRecover')
idVerification = getUserIdVerificationForRecovery(maxLoi ?: 'level100') ?: idVerification
@ -144,7 +151,7 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
response.setSessionAttribute('agov.recovery.currentAgovAqRoleValidFrom', '' + agovAqValidFrom)
if ((maxLoi == 'level100') && (mustRecover == null)) {
// AQ100 accounts need to used the recovery code, if they can
// AQ100 accounts need to use the recovery code, if they can
// check the status of recoveryCode credential
if (recoveryCode && !blockingCredentialStates.contains(recoveryCode.state.text())) {
LOG.debug("Recovery: emailAndCode")
@ -152,11 +159,12 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
return
} else {
LOG.warn("AGOVaq100 recovery: skipped Recovery-Code check '${recoveryCode ? recoveryCode.state.text() : 'MISSING'}'")
session.setAttribute('agov.recovery.codeStatus', 'skipped')
session.setAttribute('agov.recovery.codeDetailStatus', "unusable (state: ${recoveryCode ? recoveryCode.state.text() : 'MISSING'})")
response.setResult('ok')
return
}
// mustRecover role not set, so code needs to be checked
} else {
LOG.debug("Recovery: email")
response.setResult('ok')

View File

@ -8,7 +8,7 @@ if(outargs.containsKey('saml.SAMLResponse')) {
def sourceIp = request.getLoginContext()['connection.HttpHeader.X-Real-IP'] ?: 'unknown'
def userAgent = request.getLoginContext()['connection.HttpHeader.user-agent'] ?: request.getLoginContext()['connection.HttpHeader.User-Agent'] ?: 'unknown'
LOG.info("Event='GOTORECOVERY', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', RecoveryInfo={ ctxClass: ${session['agov.recovery.authnContextClassRef']}, acctAq: ${session['agov.recovery.currentAgovAq']}}")
LOG.info("Event='GOTORECOVERY', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', AccountAq='${session['agov.recovery.currentAgovAq']}', AuthCtxClass='${session['agov.recovery.authnContextClassRef']}', RecoveryCodeStatus='${session['agov.recovery.codeStatus']}', RecoveryCodeDetailStatus='${session['agov.recovery.codeDetailStatus']}'")
// Redirect
response.addOutArg('nevis.transfer.destination', parameters.get('agovmedirecturl'))