diff --git a/package.json b/package.json index 3e129c5..681b3f5 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "SERVER_URL=https://e4cd-2a02-587-871c-8800-407e-b47f-6012-470b.ngrok-free.app node server.js" + "dev": "SERVER_URL=https://2f95-2a02-587-871c-8800-5569-20c0-5a74-e8bf.ngrok-free.app node server.js" }, "author": "", "license": "ISC", diff --git a/routes/codeFlowJwtRoutes.js b/routes/codeFlowJwtRoutes.js index 691bb29..0ffaa0f 100644 --- a/routes/codeFlowJwtRoutes.js +++ b/routes/codeFlowJwtRoutes.js @@ -63,11 +63,18 @@ codeFlowRouter.get("/authorize", async (req, res) => { const issuerState = decodeURIComponent(req.query.issuer_state); // This can be associated with the ITB session const state = req.query.state; const clientId = decodeURIComponent(req.query.client_id); //DID of the holder requesting the credential - const authorizationDetails = req.query.authorization_details - ? JSON.parse( - decodeURIComponent(req.query.authorization_details) //TODO this contains the credentials requested - ) - : null; + let authorizationDetails = ""; + try { + authorizationDetails = decodeURIComponent(req.query.authorization_details); //TODO this contains the credentials requested + } catch (error) { + console.log( + "No credentials requested! req.query.authorization_details missing!" + ); + errors.push( + "No credentials requested! req.query.authorization_details missing!" + ); + } + const redirectUri = decodeURIComponent(req.query.redirect_uri); const nonce = req.query.nonce; const codeChallenge = decodeURIComponent(req.query.code_challenge); diff --git a/routes/educationalRoutes.js b/routes/educationalRoutes.js index 6d55242..c305847 100644 --- a/routes/educationalRoutes.js +++ b/routes/educationalRoutes.js @@ -38,12 +38,21 @@ const publicKeyPem = fs.readFileSync("./public-key.pem", "utf-8"); educationalRouter.get(["/pre-offer-jwt-edu"], async (req, res) => { const uuid = req.query.sessionId ? req.query.sessionId : uuidv4(); + const personaId = req.query.persona; const preSessions = getPreCodeSessions(); - if (preSessions.sessions.indexOf(uuid) < 0) { - preSessions.sessions.push(uuid); + if (preSessions.sessions.indexOf(uuid + "-persona=" + personaId) < 0) { + preSessions.sessions.push(uuid + "-persona=" + personaId); preSessions.results.push({ sessionId: uuid, status: "pending" }); + preSessions.personas.push(null); + preSessions.accessTokens.push(null); + } + let credentialOffer = ""; + if (personaId) { + credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-pre-jwt-edu/${uuid}?persona=${personaId}`; //OfferUUID + } else { + credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-pre-jwt-edu/${uuid}`; } - let credentialOffer = `openid-credential-offer://?credential_offer_uri=${serverURL}/credential-offer-pre-jwt-edu/${uuid}`; //OfferUUID + let code = qr.image(credentialOffer, { type: "png", ec_level: "H", @@ -60,16 +69,30 @@ educationalRouter.get(["/pre-offer-jwt-edu"], async (req, res) => { }); educationalRouter.get(["/credential-offer-pre-jwt-edu/:id"], (req, res) => { - res.json({ - credential_issuer: serverURL, - credentials: ["EducationalID"], - grants: { - "urn:ietf:params:oauth:grant-type:pre-authorized_code": { - "pre-authorized_code": req.params.id, - user_pin_required: true, + let persona = req.query.persona; + if (!persona) { + res.json({ + credential_issuer: serverURL, + credentials: ["EducationalID"], + grants: { + "urn:ietf:params:oauth:grant-type:pre-authorized_code": { + "pre-authorized_code": req.params.id, + user_pin_required: true, + }, }, - }, - }); + }); + } else { + res.json({ + credential_issuer: serverURL, + credentials: ["EducationalID"], + grants: { + "urn:ietf:params:oauth:grant-type:pre-authorized_code": { + "pre-authorized_code": req.params.id + "-persona=" + persona, + user_pin_required: true, + }, + }, + }); + } }); educationalRouter.get(["/pre-offer-jwt-alliance"], async (req, res) => { @@ -95,17 +118,20 @@ educationalRouter.get(["/pre-offer-jwt-alliance"], async (req, res) => { }); }); -educationalRouter.get(["/credential-offer-pre-jwt-alliance/:id"], (req, res) => { - res.json({ - credential_issuer: serverURL, - credentials: ["allianceIDCredential"], - grants: { - "urn:ietf:params:oauth:grant-type:pre-authorized_code": { - "pre-authorized_code": req.params.id, - user_pin_required: true, +educationalRouter.get( + ["/credential-offer-pre-jwt-alliance/:id"], + (req, res) => { + res.json({ + credential_issuer: serverURL, + credentials: ["allianceIDCredential"], + grants: { + "urn:ietf:params:oauth:grant-type:pre-authorized_code": { + "pre-authorized_code": req.params.id, + user_pin_required: true, + }, }, - }, - }); -}); + }); + } +); export default educationalRouter; diff --git a/routes/routes.js b/routes/routes.js index 6551d7c..42b4ad2 100644 --- a/routes/routes.js +++ b/routes/routes.js @@ -432,6 +432,13 @@ router.post("/credential", async (req, res) => { requestedCredentials != null && requestedCredentials[0] === "EducationalID" ) { + const preSessions = getPreCodeSessions(); + let persona = getPersonaFromAccessToken( + token, + preSessions.personas, + preSessions.accessTokens + ); + payload = { iss: serverURL, sub: decodedHeaderSubjectDID || "", @@ -475,6 +482,77 @@ router.post("/credential", async (req, res) => { ).toISOString(), }, }; + + if (persona === "1") { + payload.vc.credentialSubject = { + id: decodedHeaderSubjectDID || "", + identifier: "mario.conti@ewc.eu", + schacPersonalUniqueCode: [ + "urn:schac:personalUniqueCode:int:esi:university.edu:12345", + ], + schacPersonalUniqueID: "urn:schac:personalUniqueID:us:12345", + schacHomeOrganization: "university.edu", + familyName: "Conti", + firstName: "Mario", + displayName: "Mario Conti", + dateOfBirth: "1990-01-01", + commonName: "Mario Contri", + mail: "mario.conti@ewc.eu", + eduPersonPrincipalName: "mario.conti@ewc.eu", + eduPersonPrimaryAffiliation: "student", + eduPersonAffiliation: ["member", "student"], + eduPersonScopedAffiliation: ["student@ewc.eu"], + eduPersonAssurance: [ + "https://wiki.refeds.org/display/ASS/REFEDS+Assurance+Framework+ver+1.0", + ], + } + } else if (persona === "2") { + payload.vc.credentialSubject = { + id: decodedHeaderSubjectDID || "", + identifier: "hannah@ewc.eu", + schacPersonalUniqueCode: [ + "urn:schac:personalUniqueCode:int:esi:university.edu:12345", + ], + schacPersonalUniqueID: "urn:schac:personalUniqueID:us:12345", + schacHomeOrganization: "university.edu", + familyName: "Matkalainen", + firstName: "Hannah", + displayName: "Hannah Matkalainen", + dateOfBirth: "1990-01-01", + commonName: "Hannah Matkalainen", + mail: "hannah@ewc.eu", + eduPersonPrincipalName: "hannah@ewc.eu", + eduPersonPrimaryAffiliation: "student", + eduPersonAffiliation: ["member", "student"], + eduPersonScopedAffiliation: ["student@ewc.eu"], + eduPersonAssurance: [ + "https://wiki.refeds.org/display/ASS/REFEDS+Assurance+Framework+ver+1.0", + ], + } + } else if (persona === "3") { + payload.vc.credentialSubject = { + id: decodedHeaderSubjectDID || "", + identifier: "felix@ewc.eu", + schacPersonalUniqueCode: [ + "urn:schac:personalUniqueCode:int:esi:university.edu:12345", + ], + schacPersonalUniqueID: "urn:schac:personalUniqueID:us:12345", + schacHomeOrganization: "university.edu", + familyName: "Fischer", + firstName: "Felix", + displayName: "Felix Fischer", + dateOfBirth: "1990-01-01", + commonName: "Felix Fischer", + mail: "felix@ewc.eu", + eduPersonPrincipalName: "felix@ewc.eu", + eduPersonPrimaryAffiliation: "student", + eduPersonAffiliation: ["member", "student"], + eduPersonScopedAffiliation: ["student@ewc.eu"], + eduPersonAssurance: [ + "https://wiki.refeds.org/display/ASS/REFEDS+Assurance+Framework+ver+1.0", + ], + } + } } else { if ( requestedCredentials != null &&