diff --git a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/etc/nevis/k8s-nevisauth-7022472ae407577ae604bbb8.yaml b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/etc/nevis/k8s-nevisauth-7022472ae407577ae604bbb8.yaml index 1059835..9ba537d 100644 --- a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/etc/nevis/k8s-nevisauth-7022472ae407577ae604bbb8.yaml +++ b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/etc/nevis/k8s-nevisauth-7022472ae407577ae604bbb8.yaml @@ -45,7 +45,7 @@ spec: podDisruptionBudget: maxUnavailable: "50%" git: - tag: "r-7adaccc956f4499dc7e8f30195149151fda42e84" + tag: "r-7ea2bb552e56706a0514f07552905db7bb8ee0ad" dir: "DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth" credentials: "git-credentials" keystores: diff --git a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/idp_status_check.groovy b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/idp_status_check.groovy index dcc747d..28e2b29 100644 --- a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/idp_status_check.groovy +++ b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/idp_status_check.groovy @@ -11,6 +11,16 @@ def getHeader(String name) { return map['connection.HttpHeader.' + name] } +def getCookie(String name){ + cookies = getHeader('cookie') + if (cookies != null) { + if (cookies.matches('^.*'+"${name}"+'=([^;]+).*$')) { + return cookies.replaceAll('^.*'+"${name}"+'=([^;]+).*$', '$1') + } + } + return null +} + def sha256(String input) { // we do not catch NoSuchAlgorithmException, as every implementation of the Java platform is required to support SHA-256 def digestBytes = MessageDigest.getInstance('SHA-256').digest(input.getBytes()) @@ -36,8 +46,8 @@ def clearCurrentAuthenticationSession() { s.removeAttribute('saml.idp.result') s.removeAttribute('saml.inbound.issuer') - def sessionKeySet = new HashSet(session.keySet()) - sessionKeySet.each { key -> + def sessionKeySet = new HashSet(session.keySet()) + sessionKeySet.each { key -> if ( key ==~ /ch.nevis.auth.saml.request.*/ ) { s.removeAttribute(key) } @@ -70,7 +80,7 @@ if (inargs['SAMLRequest'] != null) { request.getInArgs().remove('SAMLRequest') request.getInArgs().remove('RelayState') - // restore the finisher again (was removed by resetAuthenticationCondition) + // restore the finisher again (was removed by resetAuthenticationCondition) def s = request.getAuthSession(true) s.setAttribute('ch.nevis.session.finishers', '' + session['agov.backup.finishers']) @@ -83,7 +93,8 @@ if (inargs['SAMLRequest'] != null) { LOG.error("Full?: " + parameters.get('eidFullEnabled')) LOG.error("Pass?: " + parameters.get('eidPassthroughEnabled')) def requestedLoa = s.getAttribute("agov.requestedRoleLevel") - if( eidEnabled && ( requestedLoa == "600" || session.get('ch.nevis.auth.saml.request.scoping.requesterId') == 'OidcPlaygroundWork' ) ){ + // 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") ){ // EID request -> goto correct state response.setResult('continueEidAfterRepost') }else{ @@ -104,6 +115,13 @@ if (inargs['SAMLRequest'] != null) { // we set/update a login Cookie def agovLoginCookie = "agovLogin=${System.currentTimeMillis()}; Domain=${parameters.get('cookie.domain')}; Path=/; SameSite=Strict; Secure; HttpOnly" response.setHeader('Set-Cookie', agovLoginCookie) + + // we check if a login method cookie has been set, if so save it to the session + def lastLoginMethod = getCookie('LOGINMETHOD') + if(lastLoginMethod != null){ + s.setAttribute('agov.lastLoginMethod', lastLoginMethod) + } + response.setResult('ok') return } @@ -130,17 +148,15 @@ if (inargs.containsKey('o.fidoUafSessionId.v')) { response.setStatus(AuthResponse.AUTH_CONTINUE) return } -else { +else { // authentication timeout reached, or SSO-Endpoint bookmarked -> return a 404 - def agovLoginCookie = 'missing' - if (getHeader('cookie') != null) { - def cookies = getHeader('cookie') - if (cookies.matches('^.*agovLogin=([^;]+).*$')) { - agovLoginCookie = cookies.replaceAll('^.*agovLogin=([^;]+).*$', '$1') - } + def agovLoginCookie = getCookie('agovLogin') + if (agovLoginCookie == null) { + agovLoginCookie = 'missing' } - LOG.debug("agovLoginCookie: ${agovLoginCookie}") + + LOG.debug("agovLoginCookie: ${agovLoginCookie}") if (agovLoginCookie == 'missing' || agovLoginCookie == 'deleted') { LOG.debug('SSO-Endpoint bookmarked -> return a 404') response.setHttpStatusCode(404) diff --git a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/requestedrolelevel.groovy b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/requestedrolelevel.groovy index cad5a2b..f6e4d8a 100644 --- a/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/requestedrolelevel.groovy +++ b/DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth/var/opt/nevisauth/default/conf/requestedrolelevel.groovy @@ -64,6 +64,25 @@ if (requestedRoleLevelNumber == 0 || session.get('ch.nevis.auth.saml.request.sco return } +def eidEnabled = parameters.get('eidPassthroughEnabled') == "true" || parameters.get('eidFullEnabled') == "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 +session.setAttribute('agov.eidAllowed', eidAllowed.toString()) + + +// if aq400 or less is requested then we need to decide which login method to show first +// The default login method is eid. If eid is not allowed we prefer fido uaf. +def ok_transition = eidAllowed ? 'exit.1' : 'ok' + +// if there is a login method cookie set form a previous login -> use that instead of the default +def lastLoginMethod = session.get('agov.lastLoginMethod') +if(lastLoginMethod != null || lastLoginMethod != ""){ + if(lastLoginMethod == "accessApp" || lastLoginMethod == "securityKey"){ + ok_transition = 'ok' + } +} +// NOTE: if the last login method was eid, but eid is not allowed, we will default to fido uaf try { def spanCtxt = Span.current().getSpanContext() @@ -85,38 +104,38 @@ try { session.setAttribute('agov.appDisplayNameIT', '' + json.displayNameIt) session.setAttribute('agov.appDisplayNameEN', '' + json.displayNameEn) - def eidEnabled = parameters.get('eidPassthroughEnabled') == "true" || parameters.get('eidFullEnabled') == "true" - // NOTE/aca/2024-04-07: Moved here to solve the issue of not getting display names - if (requestedRoleLevelNumber == 600 || session.get('ch.nevis.auth.saml.request.scoping.requesterId') == 'OidcPlaygroundWork') { + // if aq500 or 600 is requested -> the only available login method is eid -> continue directly there + // if eid is disabled -> show an error page + if (requestedRoleLevelNumber == 600 || requestedRoleLevelNumber == 500) { if(eidEnabled){ session.setAttribute('agov.appSvnrAllowed', 'true') response.setResult('exit.1') return }else{ response.setResult('error') - response.setError(9071, "LoA 600 not supported") + response.setError(9073, "LoA 600 not supported") return } - + } - + LOG.debug('AdressRequired: ' + json.addrRequired) LOG.debug('SvnrAllowed: ' + json.svnrAllowed) LOG.debug('appRequiresBestTokenWithAddress: ' + appRequiresBestTokenWithAddress) LOG.debug('appRequiresBestTokenWithSvnr: ' + appRequiresBestTokenWithSvnr) - // address will be returned to the application if allowed by connect (json.addrRequired) + // address will be returned to the application if allowed by connect (json.addrRequired) // and the authRequest was done with at least AGOVaq 200 // BUNDBITBK-4307: or best token for address is enabled session.setAttribute('agov.appAddressRequired', '' + (json.addrRequired && ((requestedRoleLevelNumber >= 200) || appRequiresBestTokenWithAddress))) - // address will be returned to the application if allowed by connect (json.svnrAllowed) + // address will be returned to the application if allowed by connect (json.svnrAllowed) // and the authRequest was done with at least AGOVaq 300 // BUNDBITBK-4307: or best token for svnr is enabled session.setAttribute('agov.appSvnrAllowed', '' + (json.svnrAllowed && ((requestedRoleLevelNumber >= 300) || appRequiresBestTokenWithSvnr))) - response.setResult('ok') + response.setResult(ok_transition) return } else { LOG.warn("Failed to fetch connect meta data for relying party '${session.get('ch.nevis.auth.saml.request.scoping.requesterId')}'") @@ -125,12 +144,12 @@ try { if ( requestedRoleLevelNumber == 100) { session.setAttribute('agov.appAddressRequired', '' + appRequiresBestTokenWithAddress) session.setAttribute('agov.appSvnrAllowed', 'false') - response.setResult('ok') + response.setResult(ok_transition) } else if ( requestedRoleLevelNumber == 200) { session.setAttribute('agov.appAddressRequired', 'true') session.setAttribute('agov.appSvnrAllowed', 'false') - response.setResult('ok') + response.setResult(ok_transition) } else { response.setResult('error') @@ -144,12 +163,12 @@ try { if ( requestedRoleLevelNumber == 100) { session.setAttribute('agov.appAddressRequired', '' + appRequiresBestTokenWithAddress) session.setAttribute('agov.appSvnrAllowed', 'false') - response.setResult('ok') + response.setResult(ok_transition) } else if ( requestedRoleLevelNumber == 200) { session.setAttribute('agov.appAddressRequired', 'true') session.setAttribute('agov.appSvnrAllowed', 'false') - response.setResult('ok') + response.setResult(ok_transition) } else { response.setResult('error')