159 lines
6.5 KiB
Groovy
159 lines
6.5 KiB
Groovy
import java.text.SimpleDateFormat
|
|
import groovy.text.SimpleTemplateEngine
|
|
|
|
import ch.nevis.idm.client.IdmRestClient
|
|
import ch.nevis.idm.client.IdmRestClientFactory
|
|
|
|
def getDateWithoutTimestamp(String date){
|
|
def result = date
|
|
if(date.matches('^[0-9-]+[+]{1}.*')){
|
|
result = date.replaceAll('[+]{1}.*', "")
|
|
}
|
|
return result
|
|
}
|
|
|
|
// NOTE/aca/2025/06/19: We could also reload the data from idm after the update instead of updating the session variables manualy -> probably better and less error-prone
|
|
def compareAndUpdateSessionVariables(sess, keys, isProperty){
|
|
def updatedKeys = []
|
|
for(key in keys){
|
|
def idmkey = isProperty ? "ch.nevis.idm.User.prop.$key" : "ch.nevis.idm.User.$key"
|
|
def eidValue = session["agov.eid.User.$key"] ?: ""
|
|
def idmValue = session[idmkey] ?: ""
|
|
if(!idmValue || eidValue != idmValue){
|
|
sess.setAttribute(idmkey, eidValue)
|
|
updatedKeys.add(key)
|
|
}
|
|
}
|
|
return updatedKeys
|
|
}
|
|
|
|
String user_update_dto_template = '''
|
|
{
|
|
"name": {
|
|
"firstName": "$firstName",
|
|
"familyName": "$familyName"
|
|
},
|
|
"properties": {
|
|
"svnr": "$svnr",
|
|
"placeOfBirth": "$placeOfBirth",
|
|
"nationality": "$nationality",
|
|
"eIdNumber": "$eIdNumber"
|
|
},
|
|
"gender": "$gender",
|
|
"birthDate": "$birthDate",
|
|
|
|
"modificationComment": "updated user information with eid attributes during request $request"
|
|
}
|
|
'''
|
|
|
|
// Accounting
|
|
def requester = session['ch.nevis.auth.saml.request.scoping.requesterId'] ?: 'unknown'
|
|
def requestId = session['ch.nevis.auth.saml.request.id'] ?: 'unknown'
|
|
def requestedAq = session['agov.requestedRoleLevel'] ?: 'unknown'
|
|
def user = session['ch.adnovum.nevisidm.user.extId'] ?: 'unknown'
|
|
def credentialType = session['authenticatedWith'] ?: 'unknown'
|
|
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'
|
|
|
|
|
|
|
|
def sess = request.getAuthSession(true)
|
|
|
|
// Convert EID gender format to IDM
|
|
if(sess.get('agov.eid.User.gender') == '1'){
|
|
sess.setAttribute('agov.eid.User.gender', 'MALE')
|
|
}
|
|
if(sess.get('agov.eid.User.gender') == '2'){
|
|
sess.setAttribute('agov.eid.User.gender', 'FEMALE')
|
|
}
|
|
if(sess.get('agov.eid.User.gender') == '3'){
|
|
sess.setAttribute('agov.eid.User.gender', 'OTHER')
|
|
}
|
|
|
|
// Compare eid and idm attributes + update idm session variables if they differ
|
|
def attributesToAudit = compareAndUpdateSessionVariables(sess, ["firstName", "lastName", "gender"], false)
|
|
// NOTE/aca/2025/06/14/: Potentally Throw a DATA ERROR if the properties are different? -> should the svnr number ever change?
|
|
def propertiesToAudit = compareAndUpdateSessionVariables(sess, ["svnr", "eIdNumber", "nationality", "placeOfBirth"], true)
|
|
|
|
|
|
// Handle birthdate seperately, since it can contain a timestamp -> we probably don't want to update if only the timestamp is wrong
|
|
String eidBirthdate = getDateWithoutTimestamp(session["agov.eid.User.birthDate"] ?: "")
|
|
String idmBirthdate = getDateWithoutTimestamp(session["ch.nevis.idm.User.birthDate"] ?: "")
|
|
LOG.debug("eidBirthdate: $eidBirthdate idmBirthdate: $idmBirthdate")
|
|
if(eidBirthdate != idmBirthdate){
|
|
sess.setAttribute("ch.nevis.idm.User.birthDate", eidBirthdate)
|
|
// For some reson IdmGetPropertyState uses a different date format than IdmSetPropertyState?
|
|
//def date = new SimpleDateFormat('yyyy-MM-dd').parse(eidBirthdate)
|
|
//def idmFromatedBirthDate = new SimpleDateFormat('dd.MM.yyyy').format(date)
|
|
//sess.setAttribute("ch.nevis.idm.User.birthDate.idmFormat", idmFromatedBirthDate)
|
|
attributesToAudit.add("birthDate")
|
|
}
|
|
|
|
// Check if we need to update IDM
|
|
def auditedRequired = attributesToAudit.size() > 0 || propertiesToAudit.size() > 0
|
|
|
|
if(auditedRequired){
|
|
// update attributes in idm & transition to User notification
|
|
IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)
|
|
|
|
String baseUrl = parameters.get("baseUrl")
|
|
String clientExtId = parameters.get("clientExtId")
|
|
String endPoint = "$baseUrl/api/core/v1"
|
|
String userExtId = sess.getAttribute("ch.nevis.idm.User.extId")
|
|
|
|
String requestUrl = "$endPoint/$clientExtId/users/$userExtId"
|
|
|
|
|
|
|
|
def binding = [
|
|
"firstName": sess.getAttribute('agov.eid.User.firstName'),
|
|
"familyName": sess.getAttribute('agov.eid.User.lastName'),
|
|
"svnr": sess.getAttribute('agov.eid.User.svnr'),
|
|
"placeOfBirth": sess.getAttribute('agov.eid.User.placeOfBirth'),
|
|
"nationality": sess.getAttribute('agov.eid.User.nationality'),
|
|
"eIdNumber": sess.getAttribute('agov.eid.User.eIdNumber'),
|
|
"gender": sess.getAttribute('agov.eid.User.gender').toLowerCase(),
|
|
"birthDate": sess.getAttribute('agov.eid.User.birthDate'),
|
|
"request": requestId
|
|
]
|
|
|
|
def templateEngine = new SimpleTemplateEngine()
|
|
def userUpdateDto = templateEngine.createTemplate(user_update_dto_template).make(binding).toString()
|
|
|
|
try {
|
|
idmRestClient.patch(requestUrl, userUpdateDto)
|
|
|
|
}catch(Exception e) {
|
|
LOG.error("Failed to update User data in IDM: ${e}")
|
|
LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Failed to update User data in IDM'")
|
|
response.setResult('error')
|
|
return
|
|
}
|
|
String printKeys = attributesToAudit.toListString()
|
|
LOG.debug("AuditedAttributes: $printKeys")
|
|
|
|
// Transform gender back to number
|
|
if(sess.get('ch.nevis.idm.User.gender') == 'MALE'){
|
|
sess.setAttribute('ch.nevis.idm.User.gender', '1')
|
|
}
|
|
if(sess.get('ch.nevis.idm.User.gender') == 'FEMALE'){
|
|
sess.setAttribute('ch.nevis.idm.User.gender', '2')
|
|
}
|
|
if(sess.get('ch.nevis.idm.User.gender') == 'OTHER'){
|
|
sess.setAttribute('ch.nevis.idm.User.gender', '3')
|
|
}
|
|
|
|
response.setResult('audited')
|
|
}else{
|
|
// Attributes match & no notification needed => continue by updating the linking credential and sending the saml assertion
|
|
// NOTE/aca/2025/06/19: We skip checking the account state, recovery code, mobile number and LoA
|
|
LOG.debug("No Audit Required: Logging user in")
|
|
response.setResult('noChange')
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|