Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 145 additions & 0 deletions schema/vc/mkSchema.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#! /bin/python3

import sys
import json
from pathlib import Path


def loadJSON(json_file):
with open(json_file) as json_file:
return json.load(json_file)

def p(message, writetolog=False):
if writetolog:
write_log(message)
else:
print(message)

def pj(the_json, writetolog=False):
p(json.dumps(the_json, indent=4, sort_keys=False), writetolog)


def write_file(contents, filepath, mkpath=True, overwrite=False, type='txt'):
if mkpath:
Path(filepath).mkdir(parents=True, exist_ok=overwrite)

if overwrite:
f = open(filepath, "w")
else:
f = open(filepath, "a")

match type:
case 'yaml':
yaml.preserve_quotes = True
yaml.dump(contents, f)
case 'json':
f.write(json.dumps(contents,sort_keys=False, indent=4, ensure_ascii=False,separators=(',', ':')))
case _:
# assume text
f.write(contents+"\n")

f.close()

def replace_capitals(s):
return ''.join(['' + ("_" + char.lower()) if char.isupper() else char for char in s]).strip()

def covert_schemaname(attributeName):
# Attributes need to be rename to claims
# as a general rule of thumb:
#
# eduPerson, voPerson and Schac schema names are just lowercased ad get added an underscore
#
# for the attrbute name: if a captical is found, it is replaced with a lower and prefixed with an underscore.
#
# sp eduPersonScopedAffiliation becomes: eduperson_scoped_affiliation
#
s= attributeName

if s.startswith('eduPerson'):
return ("eduperson" + fixName(replace_capitals(s[9:])))
elif s.startswith('voPerson'):
return ("voperson" + fixName(replace_capitals(s[7:])))
elif s.startswith('Schac'):
return ("schac" + fixName(replace_capitals(s[5:])))
else:
return (fixName(replace_capitals(s)))

def fixName(name):
return name.replace("_i_d", "_id").replace("_d_n", "_dn").replace("_u_r_i", "_uri").replace("_s_m_i_m_e", "_smime")

def mapType(equality, multivalued = False):

if multivalued:
match equality:
case "caseExactMatch" | "caseIgnoreMatch":
return "string"
case "integerMatch":
return "integer"
case "numericStringMatch":
return "number"
else:
return None

def main(argv):
schemaFile = {
"vcdm2.0": "schac_1_6_0.json_vcdm.json",
"sdjwt": "schac_1_6_0.json_sdjwt.json"
}

# Generate object properties based on ldif schema,coverted to json by chatGTP
# The resulting schac_ldif.json was added for reference
#
schemaJSON = loadJSON('schac_ldap.json')
object_props = {}
att = schemaJSON['schema']['attributes']

for a in att:
name = covert_schemaname(a['name'])
object_props[name] = {
"type": mapType(a['equality'], ('singleValue' in a)),
"description": a['description'],
}

# TODO: validate these
# TODO: we still have several format and pattern definitions missing
match a['name']:
case "schacHomeOrganizationType" | "schacUserPresenceID" |"schacPersonalPosition" | "schacPersonalUniqueCode" :
object_props[name]['type'] = "array"
object_props[name]['anyof'] = { "type": "uri" }

case "schacGender":
object_props[name]['type'] = "integer"
object_props[name]['deprecated'] = True

case "schacDateOfBirth":
object_props[name]['maxLength'] = 8

case "schacCountryOfCitizenship" | "schacCountryOfResidence":
object_props[name]['maxLength'] = 2

for type,filename in schemaFile.items():
schema = {
"$id": "https://refeds.org/schemas/vc/" + filename,
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$comment": "This schema implements SCHAC (SCHema for ACademia) version 1.6.0 (23 May 2022) - https://refeds.org/specifications/schac - This schema is maintained by REFEDs (https://refeds.org). The mission of REFEDS (the Research and Education FEDerations group) is to be the voice that articulates the mutual needs of research and education identity federations worldwide.",
"title": "SCHACcredentials",
"description": "Schema for verifiable credential claims describing a user in the context of SCHAC",
"type": "object",
"properties": {
"credentialSubject": {
"type": "object",
"properties": {}
}
}
}

match type:
case "vcdm2.0":
schema["properties"]["credentialSubject"]["properties"] = object_props
case "sdjwt":
schema["properties"] = object_props

write_file(schema, filename, mkpath=False, overwrite=True, type='json')

if __name__ == "__main__":
main(sys.argv[1:])
82 changes: 82 additions & 0 deletions schema/vc/schac_1_6_0.json_sdjwt.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
{
"$id":"https://refeds.org/schemas/vc/schac_1_6_0.json_sdjwt.json",
"$schema":"https://json-schema.org/draft/2020-12/schema",
"$comment":"This schema implements SCHAC (SCHema for ACademia) version 1.6.0 (23 May 2022) - https://refeds.org/specifications/schac - This schema is maintained by REFEDs (https://refeds.org). The mission of REFEDS (the Research and Education FEDerations group) is to be the voice that articulates the mutual needs of research and education identity federations worldwide.",
"title":"SCHACcredentials",
"description":"Schema for verifiable credential claims describing a user in the context of SCHAC",
"type":"object",
"properties":{
"schac_mother_tongue":{
"type":"string",
"description":"RFC 3066 code for preferred language of communication"
},
"schac_gender":{
"type":"integer",
"description":"Representation of human sex (see ISO 5218). Deprecated as of SCHAC 1.6.0",
"deprecated":true
},
"schac_date_of_birth":{
"type":"number",
"description":"Date of birth (format YYYYMMDD, only numeric chars)",
"maxLength":8
},
"schac_place_of_birth":{
"type":"string",
"description":"Birth place of a person"
},
"schac_country_of_citizenship":{
"type":"string",
"description":"Country of citizenship of a person. Format two-letter acronym according to ISO 3166-1 alpha 2",
"maxLength":2
},
"schac_sn1":{
"type":"string",
"description":"First surname of a person"
},
"schac_sn2":{
"type":"string",
"description":"Second surname of a person"
},
"schac_personal_title":{
"type":"string",
"description":"RFC1274: personal title"
},
"schac_home_organization":{
"type":"string",
"description":"Domain name of the home organization"
},
"schac_home_organization_type":{
"type":"array",
"description":"Type of the home organization",
"anyof":{
"type":"uri"
}
},
"schac_country_of_residence":{
"type":"string",
"description":"Country of residence of a person. Format two-letter acronym according to ISO 3166-1 alpha 2",
"maxLength":2
},
"schac_user_presence_id":{
"type":"array",
"description":"Used to store a set of values related to the network presence",
"anyof":{
"type":"uri"
}
},
"schac_personal_position":{
"type":"array",
"description":"Position inside an institution",
"anyof":{
"type":"uri"
}
},
"schac_personal_unique_code":{
"type":"array",
"description":"unique code for the subject",
"anyof":{
"type":"uri"
}
}
}
}
87 changes: 87 additions & 0 deletions schema/vc/schac_1_6_0.json_vcdm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
{
"$id":"https://refeds.org/schemas/vc/schac_1_6_0.json_vcdm.json",
"$schema":"https://json-schema.org/draft/2020-12/schema",
"$comment":"This schema implements SCHAC (SCHema for ACademia) version 1.6.0 (23 May 2022) - https://refeds.org/specifications/schac - This schema is maintained by REFEDs (https://refeds.org). The mission of REFEDS (the Research and Education FEDerations group) is to be the voice that articulates the mutual needs of research and education identity federations worldwide.",
"title":"SCHACcredentials",
"description":"Schema for verifiable credential claims describing a user in the context of SCHAC",
"type":"object",
"properties":{
"credentialSubject":{
"type":"object",
"properties":{
"schac_mother_tongue":{
"type":"string",
"description":"RFC 3066 code for preferred language of communication"
},
"schac_gender":{
"type":"integer",
"description":"Representation of human sex (see ISO 5218). Deprecated as of SCHAC 1.6.0",
"deprecated":true
},
"schac_date_of_birth":{
"type":"number",
"description":"Date of birth (format YYYYMMDD, only numeric chars)",
"maxLength":8
},
"schac_place_of_birth":{
"type":"string",
"description":"Birth place of a person"
},
"schac_country_of_citizenship":{
"type":"string",
"description":"Country of citizenship of a person. Format two-letter acronym according to ISO 3166-1 alpha 2",
"maxLength":2
},
"schac_sn1":{
"type":"string",
"description":"First surname of a person"
},
"schac_sn2":{
"type":"string",
"description":"Second surname of a person"
},
"schac_personal_title":{
"type":"string",
"description":"RFC1274: personal title"
},
"schac_home_organization":{
"type":"string",
"description":"Domain name of the home organization"
},
"schac_home_organization_type":{
"type":"array",
"description":"Type of the home organization",
"anyof":{
"type":"uri"
}
},
"schac_country_of_residence":{
"type":"string",
"description":"Country of residence of a person. Format two-letter acronym according to ISO 3166-1 alpha 2",
"maxLength":2
},
"schac_user_presence_id":{
"type":"array",
"description":"Used to store a set of values related to the network presence",
"anyof":{
"type":"uri"
}
},
"schac_personal_position":{
"type":"array",
"description":"Position inside an institution",
"anyof":{
"type":"uri"
}
},
"schac_personal_unique_code":{
"type":"array",
"description":"unique code for the subject",
"anyof":{
"type":"uri"
}
}
}
}
}
}
Loading