new configuration version

This commit is contained in:
aca 2025-03-31 09:06:25 +00:00
parent b938bd429b
commit 6c3b7e672a
3 changed files with 108 additions and 98 deletions

View File

@ -45,7 +45,7 @@ spec:
podDisruptionBudget: podDisruptionBudget:
maxUnavailable: "50%" maxUnavailable: "50%"
git: git:
tag: "r-68680b2182672bd8a81d786c163e95b91fb89a64" tag: "r-1663a8d1d9ae71e0fb7c5af2e10bfc2536ee973b"
dir: "DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth" dir: "DEFAULT-ADN-AGOV-PROJECT/DEFAULT-ADN-AGOV-INV/auth"
credentials: "git-credentials" credentials: "git-credentials"
keystores: keystores:

View File

@ -10,6 +10,20 @@ def tAuth = System.currentTimeMillis() - (request.getSession(true).getCreationTi
LOG.info("Event='AUTHENTICATION', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', tAuth=${tAuth}ms, SourceIp=${sourceIp}, UserAgent='${userAgent}'") LOG.info("Event='AUTHENTICATION', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', tAuth=${tAuth}ms, SourceIp=${sourceIp}, UserAgent='${userAgent}'")
// BUNDBITBK-4824: Address was missing after bmid verification
def session = request.getAuthSession(true)
int loa = session.get('agov.actualRoleLevel') as int
// Best Token Available only if account's AQlevel is high enough
if ((session.getAttribute('agov.appAddressRequired') == 'true') && (loa < 200)) {
LOG.debug("Best Token: Address requested but account has to low AQ (${loa})")
session.setAttribute('agov.appAddressRequired', 'false')
}
if ((session.getAttribute('agov.appSvnrAllowed') == 'true') && (loa < 400)) {
LOG.debug("Best Token: SVNr requested but account has to low AQ (${loa})")
session.setAttribute('agov.appSvnrAllowed', 'false')
}
// BUNDBITBK-4824 END
// delete the login cookie // delete the login cookie
def agovLoginCookie = "agovLogin=deleted; Domain=${parameters.get('cookie.domain')}; Path=/; Max-Age=0; SameSite=Strict; Secure; HttpOnly" def agovLoginCookie = "agovLogin=deleted; Domain=${parameters.get('cookie.domain')}; Path=/; Max-Age=0; SameSite=Strict; Secure; HttpOnly"

View File

@ -1,26 +1,14 @@
import groovy.json.JsonSlurper
import ch.nevis.esauth.auth.engine.AuthResponse import ch.nevis.esauth.auth.engine.AuthResponse
import ch.nevis.esauth.util.httpclient.api.HttpClient import ch.nevis.esauth.util.httpclient.api.HttpClient
import groovy.json.JsonSlurper
import io.opentelemetry.api.trace.Span import io.opentelemetry.api.trace.Span
def getHeader(String name) { def getHeader(String name) {
def inctx = request.getLoginContext() def inctx = request.getLoginContext()
// case-insensitive lookup of HTTP headers // case-insensitive lookup of HTTP headers
def map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER) def map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER)
map.putAll(inctx) map.putAll(inctx)
return map['connection.HttpHeader.' + name] return map['connection.HttpHeader.' + name]
}
def clearIdmSessionAttributes() {
def s = request.getAuthSession(true)
def sessionKeySet = new HashSet(session.keySet())
sessionKeySet.each { key ->
if ( key ==~ /ch.nevis.idm.*/ || key ==~ /ch.adnovum.nevisidm.*/ ) {
s.removeAttribute(key)
}
}
} }
def verification_request_template = ''' def verification_request_template = '''
@ -129,47 +117,47 @@ def verification_request_template = '''
''' '''
def ERROR_CODE_TO_STATUS_MAPPER = [ def ERROR_CODE_TO_STATUS_MAPPER = [
'CREDENTIAL_INVALID': 'FAILED', 'CREDENTIAL_INVALID' : 'FAILED',
'JWT_EXPIRED': 'ERROR', 'JWT_EXPIRED' : 'ERROR',
'INVALID_FORMAT': 'ERROR', 'INVALID_FORMAT' : 'ERROR',
'CREDENTIAL_EXPIRED': 'FAILED', 'CREDENTIAL_EXPIRED' : 'FAILED',
'MISSING_NONCE': 'ERROR', 'MISSING_NONCE' : 'ERROR',
'UNSUPPORTED_FORMAT': 'ERROR', 'UNSUPPORTED_FORMAT' : 'ERROR',
'CREDENTIAL_REVOKED': 'FAILED', 'CREDENTIAL_REVOKED' : 'FAILED',
'CREDENTIAL_SUSPENDED': 'FAILED', 'CREDENTIAL_SUSPENDED' : 'FAILED',
'HOLDER_BINDING_MISMATCH': 'ERROR', 'HOLDER_BINDING_MISMATCH' : 'ERROR',
'CREDENTIAL_MISSING_DATA': 'FAILED', 'CREDENTIAL_MISSING_DATA' : 'FAILED',
'UNRESOLVABLE_STATUS_LIST': 'ERROR', 'UNRESOLVABLE_STATUS_LIST' : 'ERROR',
'PUBLIC_KEY_OF_ISSUER_UNRESOLVABLE': 'ERROR', 'PUBLIC_KEY_OF_ISSUER_UNRESOLVABLE': 'ERROR',
'CLIENT_REJECTED': 'CANCELED', 'CLIENT_REJECTED' : 'CANCELED',
'ISSUER_NOT_ACCEPTED' : 'ERROR' 'ISSUER_NOT_ACCEPTED' : 'ERROR'
] ]
// --------------- // ---------------
// check, whether we are still processing the correct AuthnRequest // check, whether we are still processing the correct AuthnRequest
if (inargs.containsKey('authRequestId') && (inargs['authRequestId'] != session['ch.nevis.auth.saml.request.id'])) { if (inargs.containsKey('authRequestId') && (inargs['authRequestId'] != session['ch.nevis.auth.saml.request.id'])) {
// wrong request, "force" a timeout // wrong request, "force" a timeout
LOG.debug('authentication timeout enforced, due to concurrent requests -> return a 408') LOG.debug('authentication timeout enforced, due to concurrent requests -> return a 408')
response.setIsDirectResponse(true) response.setIsDirectResponse(true)
response.setContentType('text/html; charset=UTF-8') response.setContentType('text/html; charset=UTF-8')
response.setContent('Timeout') response.setContent('Timeout')
response.setHttpStatusCode(205) response.setHttpStatusCode(205)
response.setHeader('IDP-AUTH', 'Timeout') response.setHeader('IDP-AUTH', 'Timeout')
// CONTINUE to keep the other request beeing processed // CONTINUE to keep the other request beeing processed
response.setStatus(AuthResponse.AUTH_CONTINUE) response.setStatus(AuthResponse.AUTH_CONTINUE)
return return
} }
if (inargs['oid4vp'] == 'ERROR') { if (inargs['oid4vp'] == 'ERROR') {
response.setResult('error') response.setResult('error')
return return
} }
if (inargs['oid4vp'] == 'SUCCEEDED') { if (inargs['oid4vp'] == 'SUCCEEDED') {
response.setResult('ok') response.setResult('ok')
return return
} }
@ -181,39 +169,40 @@ def traceparent = "00-${spanCtxt.getTraceId()}-${spanCtxt.getSpanId()}-${spanCtx
if (!session['agov.eid.verification']) { if (!session['agov.eid.verification']) {
// Initialize the verification session on the verifier // Initialize the verification session on the verifier
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications" def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications"
try { try {
def httpResponse = Http.post() def httpResponse = Http.post()
.url(endPoint) .url(endPoint)
.header("Accept", "application/json") .header("Accept", "application/json")
.header("traceparent", traceparent) .header("traceparent", traceparent)
.entity(Http.entity() .entity(Http.entity()
.content(verification_request_template.replaceAll("\\{\\{UUID\\}\\}", UUID.randomUUID().toString())) .content(verification_request_template.replaceAll("\\{\\{UUID}}", UUID.randomUUID().toString()))
.contentType("application/json") .contentType("application/json")
.build()) .build())
.build() .build()
.send(httpClient) .send(httpClient)
if (httpResponse.code() != 200) { if (httpResponse.code() != 200) {
LOG.debug("Result: ${httpResponse}") LOG.debug("Result: ${httpResponse}")
response.setResult('error') response.setResult('error')
return return
} }
def json = new JsonSlurper().parseText(httpResponse.bodyAsString()) def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
LOG.debug("Result: ${json}") LOG.debug("Result: ${json}")
sess.setAttribute('agov.eid.verification', 'true') sess.setAttribute('agov.eid.verification', 'true')
sess.setAttribute('agov.eid.verification.id', json.id) sess.setAttribute('agov.eid.verification.id', json.id)
sess.setAttribute('agov.eid.verification.link', json.verification_url) sess.setAttribute('agov.eid.verification.link', json.verification_url)
if (json.state != 'PENDING') { if (json.state != 'PENDING') {
response.setResult('error') response.setResult('error')
return return
} }
} catch(Exception e) { }
catch (Exception e) {
LOG.error("Eid verification failed: $e") LOG.error("Eid verification failed: $e")
response.setResult('error') response.setResult('error')
return return
@ -226,21 +215,21 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
// TODO/haburger/2025-03-24: we should make sure, that we have an actual session on the verifier with id.v // TODO/haburger/2025-03-24: we should make sure, that we have an actual session on the verifier with id.v
// and that authRequestId is correct // and that authRequestId is correct
def idvalue = ( !inargs['o.id.v'] || inargs['o.id.v'] == 'NEW' ) ? session['agov.eid.verification.id'] : inargs['o.id.v'] def idvalue = (!inargs['o.id.v'] || inargs['o.id.v'] == 'NEW') ? session['agov.eid.verification.id'] : inargs['o.id.v']
try { try {
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications/${idvalue}" def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications/${idvalue}"
def httpResponse = Http.get() def httpResponse = Http.get()
.url(endPoint) .url(endPoint)
.header("Accept", "application/json") .header("Accept", "application/json")
.header("traceparent", traceparent) .header("traceparent", traceparent)
.build() .build()
.send(httpClient) .send(httpClient)
if (httpResponse.code() != 200) { if (httpResponse.code() != 200) {
// TODO/haburger/2025-03-25: 404 we should create a new verification request // TODO/haburger/2025-03-25: 404 we should create a new verification request
LOG.debug("Result: ${httpResponse}") LOG.debug("Result: ${httpResponse}")
result = """{ result = """{
"oid4vp": { "oid4vp": {
"status": "ERROR", "status": "ERROR",
@ -251,44 +240,47 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
}}""" }}"""
LOG.warn("<== Response: ${responseCode}") LOG.warn("<== Response: ${responseCode}")
} }
else {
def json = new JsonSlurper().parseText(httpResponse.bodyAsString()) def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
if (json.state == 'SUCCESS') { if (json.state == 'SUCCESS') {
def claims = json.wallet_response.credential_subject_data def claims = json.wallet_response.credential_subject_data
// TODO/haburger/2025-03-25: format changes to align with IDM read data // TODO/haburger/2025-03-25: format changes to align with IDM read data
sess.setAttribute('ch.nevis.idm.User.firstName', claims.given_name) 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.lastName', claims.family_name)
sess.setAttribute('ch.nevis.idm.User.birthDate', claims.birth_date) 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.gender', claims.sex)
sess.setAttribute('ch.nevis.idm.User.prop.svnr', claims.personal_administrative_number) sess.setAttribute('ch.nevis.idm.User.prop.svnr', claims.personal_administrative_number)
sess.setAttribute('ch.nevis.idm.User.prop.placeOfBirth', claims.birth_place) sess.setAttribute('ch.nevis.idm.User.prop.placeOfBirth', claims.birth_place)
sess.setAttribute('ch.nevis.idm.User.prop.eIdNumber', claims.personal_administrative_number) sess.setAttribute('ch.nevis.idm.User.prop.eIdNumber', claims.personal_administrative_number)
sess.setAttribute('ch.nevis.idm.User.prop.nationality', claims.nationality.toString()) sess.setAttribute('ch.nevis.idm.User.prop.nationality', claims.nationality.toString())
sess.setAttribute('ValidFrom', claims.issuance_date) sess.setAttribute('ValidFrom', claims.issuance_date)
sess.setAttribute('ValidTo', claims.expiry_date) sess.setAttribute('ValidTo', claims.expiry_date)
sess.setAttribute('authenticatedWith', "urn:qa.agov.ch:names:tc:authfactor:eid") sess.setAttribute('authenticatedWith', "urn:qa.agov.ch:names:tc:authfactor:eid")
sess.setAttribute('idVerification', "Eid") sess.setAttribute('idVerification', "Eid")
sess.setAttribute('contextClassRefToSet', "urn:qa.agov.ch:names:tc:ac:classes:600") sess.setAttribute('contextClassRefToSet', "urn:qa.agov.ch:names:tc:ac:classes:600")
response.setUserId(claims.personal_administrative_number) response.setUserId(claims.personal_administrative_number)
response.setLoginId(claims.document_number) response.setLoginId(claims.document_number)
response.setAuthLevel("EID") response.setAuthLevel("EID")
result = """{ result = """{
"oid4vp": { "oid4vp": {
"status": "SUCCEEDED", "status": "SUCCEEDED",
"verification_url": "${session['agov.eid.verification.link']}", "verification_url": "${session['agov.eid.verification.link']}",
"id": "${idvalue}", "id": "${idvalue}",
"error_code": "NONE" "error_code": "NONE"
}}""" }}"""
} else if (json.state == 'FAILED') { }
// TODO/haburger/2025-03-25: ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] == 'FAILED' we should else if (json.state == 'FAILED') {
// initiate a new verification and return the new id, url together with the message // 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})") LOG
result = """{ .error("Eid verification failed: ${json.wallet_response.error_code} (${json.wallet_response.error_description})")
result = """{
"oid4vp": { "oid4vp": {
"status": "${ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] ?: 'ERROR'}", "status": "${ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] ?: 'ERROR'}",
"verification_url": "${session['agov.eid.verification.link']}", "verification_url": "${session['agov.eid.verification.link']}",
@ -296,16 +288,20 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
"error_code": "${json.wallet_response.error_code}", "error_code": "${json.wallet_response.error_code}",
"error_message": "${json.wallet_response.error_description}" "error_message": "${json.wallet_response.error_description}"
}}""" }}"""
} else { }
result = """{ else {
result = """{
"oid4vp": { "oid4vp": {
"status": "${inargs['o.id.v'] == 'NEW' ? 'INITIATED' : 'PENDING'}", "status": "${inargs['o.id.v'] == 'NEW' ? 'INITIATED' : 'PENDING'}",
"verification_url": "${session['agov.eid.verification.link']}", "verification_url": "${session['agov.eid.verification.link']}",
"id": "${idvalue}", "id": "${idvalue}",
"error_code": "NONE" "error_code": "NONE"
}}""" }}"""
}
} }
} catch(Exception e) {
}
catch (Exception e) {
LOG.error("Eid verification failed: ${e}") LOG.error("Eid verification failed: ${e}")
result = """{ result = """{
"oid4vp": { "oid4vp": {