1.8.x.2565

This commit is contained in:
haburger 2025-01-23 07:47:10 +00:00
parent ee73ecc9b9
commit e0fadab08b
13 changed files with 95 additions and 40 deletions

View File

@ -1,4 +1,22 @@
import ch.nevis.esauth.auth.engine.AuthResponse
if (inargs['recovery'] != null && inargs['recovery'] == 'recovery' ) {
response.setResult('ok')
return
// clean up SAML state, to make sure the redirect will really be processed
// IdentityProviderState sets session attributes as follows
// <IDP-State-Name>-session-participants.<SAML-RP-ISSUER> = <ACS-URL>
// State name contains the name of the pattern 'Recovery_redirectAgovMe'
def s = request.getAuthSession(true)
def sessionKeySet = new HashSet(session.keySet())
sessionKeySet.each { key ->
if ( key ==~ /.*Recovery_redirectAgovMe-session-participants\.*/ ) {
LOG.info("Deleted session attribute '${key}'")
s.removeAttribute(key)
}
}
response.setResult('ok')
return
}
// if we reach this, display the GUI again
response.setStatus(AuthResponse.AUTH_CONTINUE)
return

View File

@ -185,42 +185,46 @@ try {
}
// 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 recoveryRoleList = getUserAGOVRecoveryRoles()
if (recoveryRoleList.contains('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 origIdVerification = getUserAGOVLoiIdVerification(highestRoleLevelNumber.toString()) ?: 'None'
def idVerification = getUserIdVerificationForRecovery() ?: origIdVerification
session.setAttribute('agov.recovery.currentIdVerification', '' + idVerification )
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)
// 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 )
def validFrom = getUserMustRecoverValidFrom() ?: ''
session.setAttribute('agov.recovery.currentAgovAqRoleValidFrom', '' + validFrom )
LOG.debug("CheckLoa: mustRecover: origIdVerification=${origIdVerification}, idVerification=${idVerification}, currentAgovAqForRecovery=${currentAgovAqForRecovery}")
LOG.debug("CheckLoa: mustRecover: origIdVerification=${origIdVerification}, idVerification=${idVerification}, currentAgovAqForRecovery=${currentAgovAqForRecovery}")
response.setResult('exit.2')
return
response.setResult('exit.2')
return
} else if (role == 'recovery') {
} else if (recoveryRoleList.contains('recovery')) {
if (recoveryRoleList.contains('recoveryCascade')) {
session.setAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recoveryCascade')
} else {
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)
}
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
}
response.setResult('exit.2')
return
}
}
if (highestRoleLevelNumber>=requestedRoleLevelNumber) {

View File

@ -34,8 +34,8 @@
<property name="condition:invalidUrlTicket" value="${notes:invalidUrlTicket}"/>
<property name="condition:hasCaptchaInfos" value="#{sess.get('agov.recovery.captchaSettings.puzzleUrl')}"/>
</AuthState>
<AuthState name="${state.entry}_loginFactorQuestion" class="ch.nevis.esauth.auth.states.standard.ConditionalDispatcherState" final="true" resumeState="true">
<ResultCond name="cancel" next="${state.exit.2}"/>
<AuthState name="${state.entry}_loginFactorQuestion" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="true" resumeState="true">
<ResultCond name="doCancel" next="${state.exit.2}"/>
<ResultCond name="loginFactorYes" next="${state.entry}_reasonSelection"/>
<ResultCond name="loginFactorNo" next="${state.entry}_reasonSelection"/>
<Response value="AUTH_CONTINUE">
@ -46,12 +46,10 @@
<GuiElem name="submit" type="submit" label="submit.button.label" value="submit"/>
</Gui>
</Response>
<property name="condition:cancel" value="${inargs:cancel}==cancel"/>
<property name="condition:loginFactorYes" value="${inargs:continue}==yes"/>
<property name="condition:loginFactorNo" value="${inargs:continue}==no"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/questionnaireLfProcessing.groovy"/>
</AuthState>
<AuthState name="${state.entry}_reasonSelection" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="true" resumeState="true">
<ResultCond name="cancel" next="${state.entry}_loginFactorQuestion"/>
<ResultCond name="doCancel" next="${state.entry}_loginFactorQuestion"/>
<ResultCond name="validReasons" next="${state.entry}_instructions"/>
<ResultCond name="invalidReasons" next="${state.entry}_noRecovery"/>
<Response value="AUTH_CONTINUE">
@ -59,7 +57,7 @@
<GuiElem name="intro" type="info" label="recovery.intro.message"/>
<GuiElem name="authRequestId" type="hidden" value="${sess:ch.nevis.auth.saml.request.id}" optional="true"/>
<GuiElem name="reason" type="hidden" value="None" optional="true"/>
<GuiElem name="question" type="hidden" value="${inargs:continue}" optional="true"/>
<GuiElem name="question" type="hidden" value="${sess:agov.recovery.moreThanOneLf}" optional="true"/>
<GuiElem name="cancel" type="submit" label="cancel.button.label" value="cancel"/>
<GuiElem name="continue" type="submit" label="submit.button.label" value="submit"/>
</Gui>

View File

@ -0,0 +1,25 @@
import ch.nevis.esauth.auth.engine.AuthResponse
if (inargs['cancel'] && inargs['cancel'] == 'cancel') {
def s = request.getAuthSession(true)
s.removeAttribute('agov.recovery.moreThanOneLf')
response.setResult('doCancel')
return
}
if (inargs['continue'] && inargs['continue'] == 'yes') {
response.setSessionAttribute('agov.recovery.moreThanOneLf', 'yes')
response.setResult('loginFactorYes')
return
}
if (inargs['continue'] && inargs['continue'] == 'no') {
response.setSessionAttribute('agov.recovery.moreThanOneLf', 'no')
response.setResult('loginFactorNo')
return
}
// if we reach this, display the GUI again
response.setStatus(AuthResponse.AUTH_CONTINUE)
return

View File

@ -5,7 +5,11 @@ if (inargs['reason']) {
}
if (inargs['cancel'] && inargs['cancel'] == 'cancel') {
response.setResult('cancel')
def s = request.getAuthSession(true)
s.removeAttribute('agov.recovery.moreThanOneLf')
s.removeAttribute('agov.recovery.reason')
response.setResult('doCancel')
return
}

View File

@ -164,6 +164,8 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
def hasRecoveryRole = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'recovery' }
def hasRecoveryCascadeRole = userDto.'**'.find { node -> node.name() == 'roles' && node.applicationName.text() == 'AGOV-AccountStatus' && node.name.text() == 'recoveryCascade' }
def hasNewLoginFactor = hasRecoveryRole && userHasNewLoginFactor()
if (mustRecover) {
@ -176,6 +178,8 @@ if (session['ch.adnovum.nevisidm.userDto'] != null && notes['lasterror'] == null
agovAqValidFrom = getUserMustRecoverValidFrom()
maxLoi = getAqLevelBasedOnIdVerificationForRecovery(idVerification, maxLoi)
} else if (hasRecoveryCascadeRole && hasNewLoginFactor) {
response.setSessionAttribute('agov.recovery.authnContextClassRef', 'urn:qa.agov.ch:names:tc:ac:classes:recoveryCascade')
}
LOG.debug("Recovery: MaxLoi is '${maxLoi}'")

View File

@ -32,12 +32,12 @@ value="${sess:agov.recovery.currentAgovAqRoleValidFrom}"/>
<property name="out.audienceRestriction" value="${param.directAudience}"/>
</AuthState>
<AuthState name="${state.entry}_Handle_Redirect" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="true">
<AuthState name="${state.entry}_Handle_Redirect" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="false">
<ResultCond name="ok" next="${state.done}"/>
<Response value="AUTH_CONTINUE">
<Gui name="not_used"/>
</Response>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
<property name="parameter.agovmedirecturl" value="${param.agovmedirecturl}"/>
<property name="script" value="file:///var/opt/nevisauth/default/conf/handleRedirectRecovery.groovy"/>
</AuthState>

View File

@ -3,6 +3,8 @@ pattern:
id: "584964c837512845d7940809"
className: "ch.nevis.admin.v4.plugin.nevisauth.patterns2.GenericAuthenticationStep"
name: "Recovery_Auth"
notes: "TODO/haburger/2025-01-23: the transition exit.3 (alreadyInRecovery) is never\
\ used. We should clean this up here"
properties:
authStatesFile: "res://584964c837512845d7940809#authStatesFile"
parameters: "var://extid_user_verify-template-parameters"