eid switch + new frontend resources
This commit is contained in:
parent
20b0cc663b
commit
2e0e3a1cca
22
bundles.yml
22
bundles.yml
|
@ -1,13 +1,13 @@
|
||||||
schemaVersion: "1.0"
|
schemaVersion: "1.0"
|
||||||
bundles:
|
bundles:
|
||||||
- "nevisadmin-plugin-base-generation:8.2411.2.rc2"
|
- "nevisadmin-plugin-authcloud:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisproxy:8.2411.2.rc2"
|
- "nevisadmin-plugin-base-generation:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisauth:8.2411.2.rc2"
|
- "nevisadmin-plugin-fido2:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisidm:8.2411.2.rc2"
|
- "nevisadmin-plugin-mobile-auth:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-mobile-auth:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisadapt:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-fido2:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisauth:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisadapt:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisdetect:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisdetect:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisdp:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-oauth:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisidm:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-authcloud:8.2411.2.rc2"
|
- "nevisadmin-plugin-nevisproxy:8.2411.2.4"
|
||||||
- "nevisadmin-plugin-nevisdp:8.2411.2.rc2"
|
- "nevisadmin-plugin-oauth:8.2411.2.4"
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -58,12 +58,6 @@ if (requestedRoleLevelNumber == 0 || session.get('ch.nevis.auth.saml.request.sco
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO/haburger/2024-03-21: move this later, now here for a simple start
|
|
||||||
if (requestedRoleLevelNumber == 600 || session.get('ch.nevis.auth.saml.request.scoping.requesterId') == 'OidcPlaygroundWork') {
|
|
||||||
session.setAttribute('agov.appSvnrAllowed', 'true')
|
|
||||||
response.setResult('exit.1');
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
def spanCtxt = Span.current().getSpanContext()
|
def spanCtxt = Span.current().getSpanContext()
|
||||||
|
@ -79,6 +73,28 @@ try {
|
||||||
|
|
||||||
if (httpResponse.code() == 200) {
|
if (httpResponse.code() == 200) {
|
||||||
def json = jsonSlurper.parseText(httpResponse.bodyAsString())
|
def json = jsonSlurper.parseText(httpResponse.bodyAsString())
|
||||||
|
|
||||||
|
session.setAttribute('agov.appDisplayNameDE', '' + json.displayNameDe)
|
||||||
|
session.setAttribute('agov.appDisplayNameFR', '' + json.displayNameFr)
|
||||||
|
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(eidEnabled){
|
||||||
|
session.setAttribute('agov.appSvnrAllowed', 'true')
|
||||||
|
response.setResult('exit.1')
|
||||||
|
return
|
||||||
|
}else{
|
||||||
|
response.setResult('error')
|
||||||
|
response.setError(9071, "LoA 600 not supported")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
LOG.debug('AdressRequired: ' + json.addrRequired)
|
LOG.debug('AdressRequired: ' + json.addrRequired)
|
||||||
LOG.debug('SvnrAllowed: ' + json.svnrAllowed)
|
LOG.debug('SvnrAllowed: ' + json.svnrAllowed)
|
||||||
LOG.debug('appRequiresBestTokenWithAddress: ' + appRequiresBestTokenWithAddress)
|
LOG.debug('appRequiresBestTokenWithAddress: ' + appRequiresBestTokenWithAddress)
|
||||||
|
@ -94,10 +110,6 @@ try {
|
||||||
// BUNDBITBK-4307: or best token for svnr is enabled
|
// BUNDBITBK-4307: or best token for svnr is enabled
|
||||||
session.setAttribute('agov.appSvnrAllowed', '' + (json.svnrAllowed && ((requestedRoleLevelNumber >= 300) || appRequiresBestTokenWithSvnr)))
|
session.setAttribute('agov.appSvnrAllowed', '' + (json.svnrAllowed && ((requestedRoleLevelNumber >= 300) || appRequiresBestTokenWithSvnr)))
|
||||||
|
|
||||||
session.setAttribute('agov.appDisplayNameDE', '' + json.displayNameDe)
|
|
||||||
session.setAttribute('agov.appDisplayNameFR', '' + json.displayNameFr)
|
|
||||||
session.setAttribute('agov.appDisplayNameIT', '' + json.displayNameIt)
|
|
||||||
session.setAttribute('agov.appDisplayNameEN', '' + json.displayNameEn)
|
|
||||||
response.setResult('ok')
|
response.setResult('ok')
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1,9 +1,12 @@
|
||||||
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="false">
|
<AuthState name="${state.entry}" class="ch.nevis.esauth.auth.states.scripting.ScriptState" final="false" resumeState="false">
|
||||||
<ResultCond name="ok" next="${state.done}"/>
|
<ResultCond name="ok" next="${state.done}"/>
|
||||||
<ResultCond name="continueAfterRepost" next="${state.exit.1}"/>
|
<ResultCond name="continueAfterRepost" next="${state.exit.1}"/>
|
||||||
|
<ResultCond name="continueEidAfterRepost" next="${state.exit.2}"/>
|
||||||
<Response value="AUTH_ERROR">
|
<Response value="AUTH_ERROR">
|
||||||
</Response>
|
</Response>
|
||||||
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
|
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
|
||||||
<property name="parameter.cookie.domain" value="${var.idp-fqdn}"/>
|
<property name="parameter.cookie.domain" value="${var.idp-fqdn}"/>
|
||||||
|
<property name="eidPassthroughEnabled" value="${vareid.passthrough.enabled}"/>
|
||||||
|
<property name="eidFullEnabled" value="${vareid.full.enabled}"/>
|
||||||
<property name="script" value="file:///var/opt/nevisauth/default/conf/idp_status_check.groovy"/>
|
<property name="script" value="file:///var/opt/nevisauth/default/conf/idp_status_check.groovy"/>
|
||||||
</AuthState>
|
</AuthState>
|
||||||
|
|
|
@ -77,7 +77,15 @@ if (inargs['SAMLRequest'] != null) {
|
||||||
// process it the same way, as if frontend triggered a reload
|
// process it the same way, as if frontend triggered a reload
|
||||||
request.getInArgs().setProperty('onReload', 'now')
|
request.getInArgs().setProperty('onReload', 'now')
|
||||||
|
|
||||||
response.setResult('continueAfterRepost')
|
def eidEnabled = parameters.get('eidPassthroughEnabled') == "true" || parameters.get('eidFullEnabled') == "true"
|
||||||
|
def requestedLoa = s.getAttribute("agov.requestedRoleLevel")
|
||||||
|
if( eidEnabled && ( requestedLoa == "600" || session.get('ch.nevis.auth.saml.request.scoping.requesterId') == 'OidcPlaygroundWork' ) ){
|
||||||
|
// EID request -> goto correct state
|
||||||
|
response.setResult('continueEidAfterRepost')
|
||||||
|
}else{
|
||||||
|
response.setResult('continueAfterRepost')
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// else, the new replaces the on-going one
|
// else, the new replaces the on-going one
|
||||||
|
|
|
@ -22,6 +22,7 @@ pattern:
|
||||||
database:
|
database:
|
||||||
- "pattern://9385d1b33aefe975fb1c5914"
|
- "pattern://9385d1b33aefe975fb1c5914"
|
||||||
facets: "var://fido_uaf_instance-facets"
|
facets: "var://fido_uaf_instance-facets"
|
||||||
|
basicFullAttestation: "strict"
|
||||||
firebaseServiceAccount: "var://fido_uaf_instance-firebase-configuration"
|
firebaseServiceAccount: "var://fido_uaf_instance-firebase-configuration"
|
||||||
firebaseProxyAddress: "var://fido_uaf_instance-firebase-proxy-url"
|
firebaseProxyAddress: "var://fido_uaf_instance-firebase-proxy-url"
|
||||||
link: "Custom URI"
|
link: "Custom URI"
|
||||||
|
|
|
@ -10,4 +10,5 @@ pattern:
|
||||||
- "pattern://03326b180687860ffe06a58c"
|
- "pattern://03326b180687860ffe06a58c"
|
||||||
nextSteps:
|
nextSteps:
|
||||||
- "pattern://f63c475c35b616b7c6c1901c"
|
- "pattern://f63c475c35b616b7c6c1901c"
|
||||||
|
- "pattern://e335f57d4c64dfc97223697a"
|
||||||
resources: "res://7a913eec7f78ce674cd87854#resources"
|
resources: "res://7a913eec7f78ce674cd87854#resources"
|
||||||
|
|
|
@ -10,6 +10,8 @@ pattern:
|
||||||
- url: "${var.connect.metadataservice.url}"
|
- url: "${var.connect.metadataservice.url}"
|
||||||
- bestTokenAddressWhitelist: "${var.bestToken.address.whitelist}"
|
- bestTokenAddressWhitelist: "${var.bestToken.address.whitelist}"
|
||||||
- bestTokenSvnrWhitelist: "${var.bestToken.svnr.whitelist}"
|
- bestTokenSvnrWhitelist: "${var.bestToken.svnr.whitelist}"
|
||||||
|
- eidPassthroughEnabled: "${var.eid.passthrough.enabled}"
|
||||||
|
- eidFullEnabled: "${var.eid.full.enabled}"
|
||||||
onSuccess:
|
onSuccess:
|
||||||
- "pattern://f63c475c35b616b7c6c1901c"
|
- "pattern://f63c475c35b616b7c6c1901c"
|
||||||
onFailure:
|
onFailure:
|
||||||
|
|
|
@ -11,18 +11,25 @@ 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
|
// 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)) {
|
def session = request.getAuthSession(true)
|
||||||
LOG.debug("Best Token: Address requested but account has to low AQ (${loa})")
|
def loa_str = session.get('agov.actualRoleLevel')
|
||||||
session.setAttribute('agov.appAddressRequired', 'false')
|
|
||||||
}
|
if(loa_str){
|
||||||
if ((session.getAttribute('agov.appSvnrAllowed') == 'true') && (loa < 400)) {
|
int loa = loa_str as int
|
||||||
LOG.debug("Best Token: SVNr requested but account has to low AQ (${loa})")
|
|
||||||
session.setAttribute('agov.appSvnrAllowed', 'false')
|
// 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
|
// BUNDBITBK-4824 END
|
||||||
|
|
||||||
// delete the login cookie
|
// delete the login cookie
|
||||||
|
|
|
@ -16,4 +16,5 @@
|
||||||
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
|
<property name="scriptTraceGroup" value="AGOV-ACCT"/>
|
||||||
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_verification_auth.groovy"/>
|
<property name="script" value="file:///var/opt/nevisauth/default/conf/eid_verification_auth.groovy"/>
|
||||||
<property name="parameter.eidVerifierBaseUrl" value="${var.eidVerifierBaseUrl}"/>
|
<property name="parameter.eidVerifierBaseUrl" value="${var.eidVerifierBaseUrl}"/>
|
||||||
|
<property name="parameter.eidUUIDNamespace" value="${var.eidUUIDNamespace}"/>
|
||||||
</AuthState>
|
</AuthState>
|
|
@ -1,8 +1,11 @@
|
||||||
import ch.nevis.esauth.auth.engine.AuthResponse
|
import ch.nevis.esauth.auth.engine.AuthResponse
|
||||||
|
import ch.nevis.esauth.sess.Session
|
||||||
import ch.nevis.esauth.util.httpclient.api.HttpClient
|
import ch.nevis.esauth.util.httpclient.api.HttpClient
|
||||||
import groovy.json.JsonSlurper
|
import groovy.json.JsonSlurper
|
||||||
import io.opentelemetry.api.trace.Span
|
import io.opentelemetry.api.trace.Span
|
||||||
|
|
||||||
|
import com.fasterxml.uuid.Generators
|
||||||
|
|
||||||
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
|
||||||
|
@ -11,6 +14,49 @@ def getHeader(String name) {
|
||||||
return map['connection.HttpHeader.' + name]
|
return map['connection.HttpHeader.' + name]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns true on success and false on failure
|
||||||
|
def getNewVerification(Session sess, HttpClient httpClient, String verification_request_template, String traceparent){
|
||||||
|
// Initialize the verification session on the verifier
|
||||||
|
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications"
|
||||||
|
|
||||||
|
try {
|
||||||
|
def httpResponse = Http.post()
|
||||||
|
.url(endPoint)
|
||||||
|
.header("Accept", "application/json")
|
||||||
|
.header("traceparent", traceparent)
|
||||||
|
.entity(Http.entity()
|
||||||
|
.content(verification_request_template.replaceAll("\\{\\{UUID}}", UUID.randomUUID().toString()))
|
||||||
|
.contentType("application/json")
|
||||||
|
.build())
|
||||||
|
.build()
|
||||||
|
.send(httpClient)
|
||||||
|
|
||||||
|
|
||||||
|
if (httpResponse.code() != 200) {
|
||||||
|
LOG.debug("Result: ${httpResponse}")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
|
||||||
|
LOG.debug("Result: ${json}")
|
||||||
|
|
||||||
|
sess.setAttribute('agov.eid.verification', 'true')
|
||||||
|
sess.setAttribute('agov.eid.verification.id', json.id)
|
||||||
|
sess.setAttribute('agov.eid.verification.link', json.verification_url)
|
||||||
|
|
||||||
|
|
||||||
|
// TODO/aca/2025-04-04:This could probably also be INITIATED, once the verifier supports this status
|
||||||
|
if (json.state != 'PENDING') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
LOG.error("Eid verification failed: $e")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
def verification_request_template = '''
|
def verification_request_template = '''
|
||||||
{ "presentation_definition": {
|
{ "presentation_definition": {
|
||||||
"id": "{{UUID}}",
|
"id": "{{UUID}}",
|
||||||
|
@ -135,9 +181,10 @@ def ERROR_CODE_TO_STATUS_MAPPER = [
|
||||||
|
|
||||||
// ---------------
|
// ---------------
|
||||||
// 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'])) {
|
// or if the frontend requested a timeout
|
||||||
|
if ( (inargs.containsKey('authRequestId') && (inargs['authRequestId'] != session['ch.nevis.auth.saml.request.id'])) || inargs['oid4vp'] == 'TIMEOUT') {
|
||||||
// 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 (authRequestId missmatch) -> return a 408')
|
||||||
|
|
||||||
response.setIsDirectResponse(true)
|
response.setIsDirectResponse(true)
|
||||||
response.setContentType('text/html; charset=UTF-8')
|
response.setContentType('text/html; charset=UTF-8')
|
||||||
|
@ -150,66 +197,44 @@ if (inargs.containsKey('authRequestId') && (inargs['authRequestId'] != session['
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def sess = request.getAuthSession(true)
|
||||||
|
|
||||||
if (inargs['oid4vp'] == 'ERROR') {
|
if (inargs['oid4vp'] == 'ERROR') {
|
||||||
|
LOG.debug("oid4vp error")
|
||||||
response.setResult('error')
|
response.setResult('error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inargs['oid4vp'] == 'SUCCEEDED') {
|
if (inargs['oid4vp'] == 'SUCCEEDED') {
|
||||||
|
LOG.debug("oid4vp succeeded")
|
||||||
response.setResult('ok')
|
response.setResult('ok')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Temporary for CANCELED
|
||||||
|
if (inargs['oid4vp'] == 'CANCELED') {
|
||||||
|
LOG.debug("oid4vp canceled")
|
||||||
|
response.setResult('error')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
def sess = request.getAuthSession(true)
|
|
||||||
|
|
||||||
HttpClient httpClient = HttpClients.create(parameters)
|
HttpClient httpClient = HttpClients.create(parameters)
|
||||||
def spanCtxt = Span.current().getSpanContext()
|
def spanCtxt = Span.current().getSpanContext()
|
||||||
def traceparent = "00-${spanCtxt.getTraceId()}-${spanCtxt.getSpanId()}-${spanCtxt.getTraceFlags().asHex()}"
|
def traceparent = "00-${spanCtxt.getTraceId()}-${spanCtxt.getSpanId()}-${spanCtxt.getTraceFlags().asHex()}"
|
||||||
|
|
||||||
if (!session['agov.eid.verification']) {
|
if (!session['agov.eid.verification']) {
|
||||||
// Initialize the verification session on the verifier
|
LOG.debug("Initializing verification")
|
||||||
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications"
|
if(!getNewVerification(sess, httpClient, verification_request_template, traceparent)){
|
||||||
|
response.setResult('error')
|
||||||
try {
|
return
|
||||||
def httpResponse = Http.post()
|
}
|
||||||
.url(endPoint)
|
|
||||||
.header("Accept", "application/json")
|
|
||||||
.header("traceparent", traceparent)
|
|
||||||
.entity(Http.entity()
|
|
||||||
.content(verification_request_template.replaceAll("\\{\\{UUID}}", UUID.randomUUID().toString()))
|
|
||||||
.contentType("application/json")
|
|
||||||
.build())
|
|
||||||
.build()
|
|
||||||
.send(httpClient)
|
|
||||||
|
|
||||||
|
|
||||||
if (httpResponse.code() != 200) {
|
|
||||||
LOG.debug("Result: ${httpResponse}")
|
|
||||||
response.setResult('error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
|
|
||||||
LOG.debug("Result: ${json}")
|
|
||||||
|
|
||||||
sess.setAttribute('agov.eid.verification', 'true')
|
|
||||||
sess.setAttribute('agov.eid.verification.id', json.id)
|
|
||||||
sess.setAttribute('agov.eid.verification.link', json.verification_url)
|
|
||||||
|
|
||||||
if (json.state != 'PENDING') {
|
|
||||||
response.setResult('error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e) {
|
|
||||||
LOG.error("Eid verification failed: $e")
|
|
||||||
response.setResult('error')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.v')) {
|
if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.v')) {
|
||||||
|
LOG.debug("Request Status Update")
|
||||||
// request for a status update from the verifier
|
// request for a status update from the verifier
|
||||||
def result
|
def result
|
||||||
|
|
||||||
|
@ -217,6 +242,29 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
// 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']
|
||||||
|
|
||||||
|
// check, whether we are still processing the correct verification request
|
||||||
|
//
|
||||||
|
if(inargs.containsKey('authRequestId') && (inargs['authRequestId'] != session['ch.nevis.auth.saml.request.id'])){
|
||||||
|
//if(inargs['o.id.v'] && inargs['o.id.v'] != 'NEW' && inargs['o.id.v'] != session['agov.eid.verification.id']){
|
||||||
|
// wrong request, tell fe to stop polling and request a timeout
|
||||||
|
LOG.debug('authentication timeout enforced, due to concurrent requests (verificationRequest missmatch) -> Notify FE & then return a 408')
|
||||||
|
result = """{
|
||||||
|
"oid4vp": {
|
||||||
|
"status": "TIMEOUT",
|
||||||
|
"verification_url": "${session['agov.eid.verification.link']}",
|
||||||
|
"id": "${idvalue}",
|
||||||
|
"error_code": "REQUEST-MISMATCH",
|
||||||
|
"error_message": "Request Mismatch Detected: Forcing Timeout"
|
||||||
|
}}"""
|
||||||
|
|
||||||
|
response.setContent(result.toString())
|
||||||
|
response.setContentType('application/json')
|
||||||
|
response.setHttpStatusCode(200)
|
||||||
|
response.setIsDirectResponse(true)
|
||||||
|
response.setStatus(AuthResponse.AUTH_CONTINUE)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications/${idvalue}"
|
def endPoint = "${parameters.get('eidVerifierBaseUrl')}/api/v1/verifications/${idvalue}"
|
||||||
|
|
||||||
|
@ -227,12 +275,32 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
.build()
|
.build()
|
||||||
.send(httpClient)
|
.send(httpClient)
|
||||||
|
|
||||||
if (httpResponse.code() != 200) {
|
|
||||||
// TODO/haburger/2025-03-25: 404 we should create a new verification request
|
// 404 -> request a new verification
|
||||||
|
if(httpResponse.code() == 404){
|
||||||
|
// Frontend should know that we are starting a new request and not recieve an error
|
||||||
|
def status = "FAILED"
|
||||||
|
// Delete session variable to start a new verification
|
||||||
|
sess.removeAttribute('agov.eid.verification')
|
||||||
|
|
||||||
|
result = """{
|
||||||
|
"oid4vp": {
|
||||||
|
"status": "${status}",
|
||||||
|
"verification_url": "",
|
||||||
|
"id": "",
|
||||||
|
"error_code": "HTTP-ERROR",
|
||||||
|
"error_message": "Faild to verify status of verification, http status: ${httpResponse.code()}"
|
||||||
|
}}"""
|
||||||
|
LOG.warn("<== Response: ${responseCode}")
|
||||||
|
}
|
||||||
|
else if (httpResponse.code() != 200) {
|
||||||
LOG.debug("Result: ${httpResponse}")
|
LOG.debug("Result: ${httpResponse}")
|
||||||
|
|
||||||
|
def status = "ERROR"
|
||||||
|
|
||||||
result = """{
|
result = """{
|
||||||
"oid4vp": {
|
"oid4vp": {
|
||||||
"status": "ERROR",
|
"status": "${status}",
|
||||||
"verification_url": "${session['agov.eid.verification.link']}",
|
"verification_url": "${session['agov.eid.verification.link']}",
|
||||||
"id": "${idvalue}",
|
"id": "${idvalue}",
|
||||||
"error_code": "HTTP-ERROR",
|
"error_code": "HTTP-ERROR",
|
||||||
|
@ -243,18 +311,18 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
else {
|
else {
|
||||||
|
|
||||||
def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
|
def json = new JsonSlurper().parseText(httpResponse.bodyAsString())
|
||||||
|
LOG.debug(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
|
||||||
|
LOG.debug("Store user data in session")
|
||||||
// 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 => No changes needed(?)
|
||||||
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.replace('.',''))
|
||||||
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.document_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)
|
||||||
|
@ -262,7 +330,15 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
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)
|
// subjectUUID v5
|
||||||
|
def namespace = UUID.fromString(parameters.get('eidUUIDNamespace'))
|
||||||
|
def uuid = Generators.nameBasedGenerator(namespace).generate(claims.personal_administrative_number)
|
||||||
|
LOG.debug("UUID: ${uuid}")
|
||||||
|
String uuidString = uuid.toString()
|
||||||
|
sess.setAttribute('agov.subjectUUID', '' + uuidString)
|
||||||
|
|
||||||
|
response.setUserId(uuidString)
|
||||||
|
sess.setAttribute('ch.adnovum.nevisidm.user.extId', uuidString)
|
||||||
response.setLoginId(claims.document_number)
|
response.setLoginId(claims.document_number)
|
||||||
response.setAuthLevel("EID")
|
response.setAuthLevel("EID")
|
||||||
|
|
||||||
|
@ -280,9 +356,20 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
|
|
||||||
LOG
|
LOG
|
||||||
.error("Eid verification failed: ${json.wallet_response.error_code} (${json.wallet_response.error_description})")
|
.error("Eid verification failed: ${json.wallet_response.error_code} (${json.wallet_response.error_description})")
|
||||||
|
def status = ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] ?: 'ERROR'
|
||||||
|
|
||||||
|
// Send new request & return variables with new id and url
|
||||||
|
if(status == 'FAILED' || status == 'CANCELED'){
|
||||||
|
// Delete session variable to start a new verification
|
||||||
|
sess.removeAttribute('agov.eid.verification')
|
||||||
|
|
||||||
|
// Clear variables for for a cleaner result
|
||||||
|
sess.removeAttribute('agov.eid.verification.link')
|
||||||
|
}
|
||||||
|
|
||||||
result = """{
|
result = """{
|
||||||
"oid4vp": {
|
"oid4vp": {
|
||||||
"status": "${ERROR_CODE_TO_STATUS_MAPPER[json.wallet_response.error_code] ?: 'ERROR'}",
|
"status": "${status}",
|
||||||
"verification_url": "${session['agov.eid.verification.link']}",
|
"verification_url": "${session['agov.eid.verification.link']}",
|
||||||
"id": "${idvalue}",
|
"id": "${idvalue}",
|
||||||
"error_code": "${json.wallet_response.error_code}",
|
"error_code": "${json.wallet_response.error_code}",
|
||||||
|
@ -318,10 +405,12 @@ if (getHeader('Content-Type') == 'application/json' && inargs.containsKey('o.id.
|
||||||
response.setHttpStatusCode(200)
|
response.setHttpStatusCode(200)
|
||||||
response.setIsDirectResponse(true)
|
response.setIsDirectResponse(true)
|
||||||
response.setStatus(AuthResponse.AUTH_CONTINUE)
|
response.setStatus(AuthResponse.AUTH_CONTINUE)
|
||||||
|
LOG.debug("Recieved json: End")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we reach this place, display GUI
|
// if we reach this place, display GUI
|
||||||
|
LOG.debug("Show GUI")
|
||||||
response.setStatus(AuthResponse.AUTH_CONTINUE)
|
response.setStatus(AuthResponse.AUTH_CONTINUE)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
|
@ -16,5 +16,6 @@ pattern:
|
||||||
- "pattern://aeb2fed9962dcd5f7893db51"
|
- "pattern://aeb2fed9962dcd5f7893db51"
|
||||||
signerTrustStore:
|
signerTrustStore:
|
||||||
- "pattern://55bf63a1b1716e9631f7080d"
|
- "pattern://55bf63a1b1716e9631f7080d"
|
||||||
|
dependencies: "res://7022472ae407577ae604bbb8#dependencies"
|
||||||
addons:
|
addons:
|
||||||
- "pattern://90af8358cc587f5c5aa79fec"
|
- "pattern://90af8358cc587f5c5aa79fec"
|
||||||
|
|
|
@ -147,6 +147,23 @@ variables:
|
||||||
pathInputMode: "OPTIONAL"
|
pathInputMode: "OPTIONAL"
|
||||||
value: "http://connect-application-billing.adn-agov-connect-01-dev:8082/connect/billing/relying-party/app-icon"
|
value: "http://connect-application-billing.adn-agov-connect-01-dev:8082/connect/billing/relying-party/app-icon"
|
||||||
requireOverloading: true
|
requireOverloading: true
|
||||||
|
base-security-response-headers-response-headers:
|
||||||
|
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
|
||||||
|
parameters:
|
||||||
|
minRequired: 1
|
||||||
|
separators:
|
||||||
|
- ":"
|
||||||
|
switchedSeparators: []
|
||||||
|
value:
|
||||||
|
- Strict-Transport-Security: "max-age=63072000; includeSubDomains;"
|
||||||
|
- X-Content-Type-Options: "nosniff"
|
||||||
|
- Referrer-Policy: "strict-origin-when-cross-origin"
|
||||||
|
- X-Frame-Options: "DENY"
|
||||||
|
- Cross-Origin-Opener-Policy: "same-origin"
|
||||||
|
- Cross-Origin-Embedder-Policy: "require-corp"
|
||||||
|
- Cross-Origin-Resource-Policy: "same-site"
|
||||||
|
- Permissions-Policy: "geolocation=(), camera=(), microphone=(), interest-cohort=()"
|
||||||
|
requireOverloading: true
|
||||||
csp-security-response-headers:
|
csp-security-response-headers:
|
||||||
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
|
className: "ch.nevis.admin.v4.plugin.base.generation.property.KeyValueProperty"
|
||||||
parameters:
|
parameters:
|
||||||
|
|
Loading…
Reference in New Issue