diff --git a/docusaurus.config.js b/docusaurus.config.js index 50ab22031ddc433d8005bb358465edca6a2825ec..13a315de97adfcb68d368a731ada8e3332b827bd 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -38,7 +38,7 @@ module.exports = { }, footer: { style: 'light', - copyright: `Copyright © ${new Date().getFullYear()} FITKO (Föderale IT-Kooperation) | Zum Gottschalkhof 3 | 60594 Frankfurt am Mail | E-Mail: poststelle@fitko.de | https://www.fitko.de | Die FITKO ist eine Anstalt des öffentlichen Rechts. Sie wird vertreten durch die Präsidentin Frau Dr. Annette Schmidt.`, + copyright: `Copyright © ${new Date().getFullYear()} FITKO (Föderale IT-Kooperation) | Zum Gottschalkhof 3 | 60594 Frankfurt am Main | E-Mail: poststelle@fitko.de | https://www.fitko.de | Die FITKO ist eine Anstalt des öffentlichen Rechts. Sie wird vertreten durch die Präsidentin Frau Dr. Annette Schmidt.`, }, }, presets: [ @@ -48,7 +48,7 @@ module.exports = { docs: { sidebarPath: require.resolve('./sidebars.js'), editUrl: ({ version, versionDocsDirPath, docPath }) => - `https://git.fitko.de/fit-connect/api/-/edit/${gitBranch}/${versionDocsDirPath}/${docPath}`, + `https://git.fitko.de/fit-connect/docs/-/edit/${gitBranch}/${versionDocsDirPath}/${docPath}`, routeBasePath: '/', }, theme: { diff --git a/examples/java/encryption/src/main/java/GenerateSignedToken.java b/examples/java/encryption/src/main/java/GenerateSignedToken.java new file mode 100644 index 0000000000000000000000000000000000000000..7190812e5d3fa1a6f277313e21b227c10072895e --- /dev/null +++ b/examples/java/encryption/src/main/java/GenerateSignedToken.java @@ -0,0 +1,71 @@ +import com.nimbusds.jose.*; +import com.nimbusds.jose.crypto.RSASSASigner; +import com.nimbusds.jose.jwk.JWK; +import com.nimbusds.jose.jwk.JWKSet; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.text.ParseException; +import java.util.Date; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; + +public class GenerateSignedToken { + + private static final InputStream jwksPath = GenerateSignedToken.class.getClassLoader().getResourceAsStream("jwks.json");; + private static final UUID signatureKeyId = UUID.fromString("6508dbcd-ab3b-4edb-a42b-37bc69f38fed"); + + private static final String subject = "submission:f65feab2-4883-4dff-85fb-169448545d9f"; + private static final String event = "https://schema.fitko.de/fit-connect/events/accept-submission"; + private static final String transactionId = "case:f73d30c6-8894-4444-8687-00ae756fea90"; + + + public static void main(String[] args) { + try { + JWKSet localKeys = JWKSet.load(jwksPath); + JWK key = localKeys.getKeyByKeyId(signatureKeyId.toString()); + + System.out.println(signatureKeyId); + System.out.println(localKeys); + + if (key == null) { + throw new RuntimeException("Cannot find key with specified Key Id"); + } + + JWSSigner signer = new RSASSASigner(key.toRSAKey()); + JWTClaimsSet claimsSet = new JWTClaimsSet.Builder() + // ToDO: Inject configured domain in stack + .issuer("https://api.fitko.de/fit-connect/") + .issueTime(new Date()) + .jwtID(UUID.randomUUID().toString()) + .subject(subject) + .claim("events", Map.of(event, Map.of())) + .claim("txn", transactionId) + .build(); + + JWSHeader header = JWSHeader.parse(Map.of( + "typ", "secevent+jwt", + "kid", key.getKeyID(), + "alg", "PS512" + )); + + SignedJWT signedJWT = new SignedJWT( + header, + claimsSet); + + signedJWT.sign(signer); + + System.out.println(signedJWT.serialize()); + } catch (IOException | ParseException e) { + e.printStackTrace(); + throw new RuntimeException("Error during loading of JWK-Set with signature keys."); + } catch (JOSEException e) { + e.printStackTrace(); + throw new RuntimeException("Could not generate SET"); + } + } +} diff --git a/examples/java/encryption/src/main/java/ParseSignedToken.java b/examples/java/encryption/src/main/java/ParseSignedToken.java new file mode 100644 index 0000000000000000000000000000000000000000..4daa7157ce44985a17cd5bc44a372ca5d23e2005 --- /dev/null +++ b/examples/java/encryption/src/main/java/ParseSignedToken.java @@ -0,0 +1,39 @@ +import com.nimbusds.jose.JWSAlgorithm; +import com.nimbusds.jose.JWSHeader; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +import java.text.ParseException; + +public class ParseSignedToken { + private static final String tokenString = "eyJraWQiOiI2NTA4ZGJjZC1hYjNiLTRlZGItYTQyYi0zN2JjNjlmMzhmZWQiLCJ0eXAiOiJzZWNldmVudCtqd3QiLCJhbGciOiJQUzUxMiJ9.eyJzdWIiOiJzdWJtaXNzaW9uOkY2NUZFQUIyLTQ4ODMtNERGRi04NUZCLTE2OTQ0ODU0NUQ5RiIsImlzcyI6Imh0dHBzOlwvXC9hcGkuZml0a28uZGVcL2ZpdC1jb25uZWN0XC8iLCJ0eG4iOiJjYXNlOkY3M0QzMEM2LTg4OTQtNDQ0NC04Njg3LTAwQUU3NTZGRUE5MCIsImlhdCI6MTYyNjM0MjkzNCwianRpIjoiZGI3MmIyMjctNWExMS00YzhiLWFlN2QtZTNjYmE2MjlkOTQ5IiwiZXZlbnRzIjp7Imh0dHBzOlwvXC9zY2hlbWEuZml0a28uZGVcL2ZpdC1jb25uZWN0XC9ldmVudHNcL2FjY2VwdC1zdWJtaXNzaW9uIjp7fX19.ZlKVrl0KIrT0eWiP7EzZ8zhqQRuqITVM66LY55BStRVz8r6mAN9lSos3S9lebXAbZSa5_x5NK99P3NuLuv2XdqnZBcW5l5vO1gghnuMDCh5YCKEd812ZcStlRJoq1c5E1cDfZ1Clkgbl8JAXOkwnNckEmD4y29eXrB0Dy3dK6Egx8qeR3b2pi1KzJshhohvgXwhNNYMszxWwUi0VvzLDy8VTJVD4jISMBL6Z7ujmt7wsoeSLpQpPJDL38y1TeLeT6AXc4siu7_cNphEBIw1yXl-R3X9SQFnS8466zUgokZ8hi2x66-yRDgnukNOOCREiD1OlYZGsL6kseONA9NKOpw"; + + private static void validateHeader(JWSHeader header) { + assert header.getAlgorithm() == JWSAlgorithm.PS512 : "The provided alg in the SET header is not allowed."; + assert header.getType().toString().equals("secevent+jwt") : "The provided typ in the SET header is not secevent+jwt"; + assert header.getKeyID() != null : "The kid the SET was signed with is not set."; + // ToDo: Check if kid is a valid UUID + } + + private static void validatePayload(JWTClaimsSet payload) throws ParseException { + assert payload.getClaim("txn") != null : "The claim txn is missing in the payload of the the SET."; + assert payload.getClaim("events") != null : "The claim events is missing in the payload of the SET."; + assert payload.getJSONObjectClaim("events").keySet().size() == 1 : "Only exactly one event is allowed."; + } + + public static void main(String[] args) { + try { + SignedJWT signedJWT = SignedJWT.parse(tokenString); + + try { + validateHeader(signedJWT.getHeader()); + validatePayload(signedJWT.getJWTClaimsSet()); + } catch (AssertionError e) { + throw new RuntimeException(e.getMessage()); + } + } catch (ParseException e) { + e.printStackTrace(); + } + + } +} diff --git a/examples/java/encryption/src/main/resources/jwks.json b/examples/java/encryption/src/main/resources/jwks.json new file mode 100644 index 0000000000000000000000000000000000000000..2d47273cf7a38c0e89c23560dde592c85430dc99 --- /dev/null +++ b/examples/java/encryption/src/main/resources/jwks.json @@ -0,0 +1,36 @@ +{ + "keys": [ + { + "alg": "PS512", + "d": "Xm0Ua2QK8sUjl2vWtaDRQoooKwRNRSCWPOEZG4p8Ru-45DZMJOD4kzdXSy57Qhbv6ggoukoY-HDMWP2dSbnmfneZjsCIUAgZQzrvYJlUR4jkVakTaq5hrmUDNIunjX8DSTqSX78I-fhMdSsF1WqI94ZXFIcME56dC9b85GeEUBduTLnRVTfMxuKQqCRKt7CacQN_JJNu2MsgEoJdb9emRdjJrwqae44h6iljwo5j14K6QWpe0QiZAZIMr2Rmx-_z4fmFkPBpm6gLAGNX_VknKLpUc2QEbBuKrPdYIhZKT-FwKigAlumPhS9q8ASphS7w6tL_RoiYWCQrFuFYaNN3OQ", + "dp": "tG_RjrefRSS_PcPg8JLFlmcob2s0ii0qvBGY1sND5WmCPPTtbwy3XelGJlDl_7I7aZHzl2cK0DE5I8To-HM1_SqBJQc_3UtccbEmNFwIWPrKzXSjJ3b9JEYBdab3cr5W5xLI22gcUp-qT9o3xVPoKRkQldXeweBpSB62oNUHYM8", + "dq": "iC-8YxuQHB3KOaxSmXJIJSgZMHyV-qiRyeQHHt1iPXDyyf0KNEdl4vzpmZNToAAn3IEHavcFxq0gEhOrKSdmFmvCWetH-PKR4Nyzf50G3PYhHy6z19xZpTIwJixJirvWsYzbZl6crGGLrUr27QV4GfhjPQGXyYIDx2xzpgtb1v8", + "e": "AQAB", + "key_ops": [ + "verify" + ], + "kid": "6508dbcd-ab3b-4edb-a42b-37bc69f38fed", + "kty": "RSA", + "n": "65rmDz943SDKYWt8KhmaUaFob08V3Y3_27yc7IXMH7IG3GDsDP49hXeJCkBFtkygZZj8zrrj-Xe2pW-KfZCyoucllfCrYwweISPLe0yilDw7Unz1uZH8V8h_92l6GFokiDIDzeDHifaqxZ0fVE9v7b93CDAxOdyRhM4p8VhoPn_KBEaFLfRxrY2DGWO24IE38Qk5V_1Xm41UuIBQOR1qoVJHu_2x2fgQ4cKdyhBrgXkMB0oqs-IKqMcmTbJCevrOxOugNr1G2HuvrytOMGsFh3UNfOgaTEqLz9yGZbfQvjOdICLUjdhxOXkFEgpFv6ga16_y9bAdoQJZRpcRr3_v9Q", + "p": "_hKAwPTn5X0bMNUNVzdtZAbhRea1nb2_ntKccPRcCNopXV-zokPPU20qIq351PpeSO4rQC-18JxCcu8wjvyNwWugOfQGeKk-E5nN1avLYPiLwLMXwZ3SuoKY8G5XhN6NAJCXW6gal6o4_clKw1BDTpyDtwN-9jiubZlH29mnM9M", + "q": "7WSGpeG_tOw1WiKa_-5cnOjUxfcD5X1BbmvSSkNSY2uXZ9t6QH4eUQh-sUzqm7G_2X56RuYcNvSIJf4kiwD7bg2-9S2LhqAgmQ7P6OhClC91rRr6RwUORobsexxUncL1sZj1T7M273ZZO0b1aW1hqI-71lWRZraWNDMkrwpXmBc", + "qi": "mmU2qZfOisOr2VWPOW1J-QVONqu6Bbs3KEutOOiqlo4oCcxGcAoa34ttRdRnnKq2scEfYVIUuaRFlw5lnwVgNTr-gOyFM3ctJoskts7AIuHjt7lSGp5DGQ9RZTVKJfKkgfCxxOT-Zga7fIP0sj92I5QkYB2IlUnsSoKFrtwl8eg" + }, + { + "alg": "PS512", + "d": "LNvxSSRjni6YlrsnTNhFeANQattEg2ozb3gFsXdNNUoWkbrfzxBe_5PuJVGxL_GhatINDtVzr2x_3rT7u386MqbZT0_jUCYnvHhSf1tZb_zCuev6gb8GWogXhBryyeuEQyYXBu_NkofsFodl55h_KxM7WwytA5eB6B0k8Loax_lS6Xae8pD5TUy_wbsEwgY12M1BTV5Q_Mj0H-O-jGgYkoH3pXz-dqeezAk19WxVYy9DDK39gbFnxW3kWuMYDbyq3ZcUL_tk-mjCuID7ED90Gxy-bX_ppp-kxD0LRBwxFc1OSM17m0qZhQdVJq28eWcNhVtd3ym8Mkd1zsRjc-gAafyaB0nczdX6z2LsqlZ9ZAz6N8AS6lCvdVbnJbh6NDMpgxtcrCun1x49kVdrmV-2rfiaRemKvHHfJWw6ZHcNpa3eW4NLaSljJSZebviYxCPB1DyMZRhCu9W2Ee_VQ4sAGJtLrMWcRtiL5KdG6BAwiIr3pUXphb9UgH8dL_uQQ7hoNOTAUlPek5t0V0F0z-f6zQ1O0DWqFOPO4_3WOI5NJF_mVsmO9DS9Nc9T5iAMtadm2FmgoecsFdBOV-AiG1xpixCVgz0iPhgDEHkNMKV1rpwQ8h3e4VZXQZuzqgZmGolB98AznKQKfnFjwB0DlRxn0vtAovLvxuA8ay71vBCBaHE", + "dp": "Ntxgy_DYcr1yaVFIG4RBxo0SrE3Efn14dB76Q3-7Ff9lMW5iMD6UUuI-PjSO-9XmdOJVoa8w7ia0QxdQucbGMbiWWWXQ4KumtGqJQxaNYJYPBZY40-BsBhB4U9VMwCNZiaFLYPA9T_cXQw7OdPmRVRhsfHGc9JxSd2F9xb6YsQF7O_YhZrJo2M3mD_DxqPPmPLkf86rono7SG1LakxR8TX6b8N3iOChuWEmkQ7A6UIpZaC4t7INdtVXfffl9R3xHfgV0So4rZe2lKScekOvG9s3V5rZFNIXnCXqG2LpXf4fp5xU93KA1yl04E9Dx6Esw2EH7A3lYLVTbwJBcDdNfsQ", + "dq": "OlXOPw1N-K5sbr2kVnoGCZuIiAf602_JnDvAmOwxRGNBRhieTLM3oQx9RayDh0EPxDZHX5jbktw2SqZPFXdhYlJpNamvQ0HFaAGARQcK5x1lCM8FFRCx6HkLeeeB59Ju3A4JpaynBIoMKFe3SdvgqqMIZ3EktrqhGZgNi_efHnn57ASJxj-dDINfBB7f3qCEyKSTvXQ3PdlOkurE_szIm1KS6tzFgzBfxXSiiYuV_oMArJOSALOA0Q446fEU4kzrGZI2JQCT1uZEM3q8BRPTcxmR_mgfcgDjpEYrmtH6udH_7I9r6IwbufiELe7MX-6kUbA8PS2H3BLfqB1ge6wUKQ", + "e": "AQAB", + "key_ops": [ + "verify" + ], + "kid": "14a70431-01e6-4d67-867d-d678a3686f4b", + "kty": "RSA", + "n": "wnqKgmQHSqJhvCfdUWWyi8qPz7J_KAdL2CkjB2rRWvGWFowkizSMjl4mzSSJVVA1UVPopTBBYd44ckn6SMRm7SK7b0N2BIeK23Bx7i6mugNDdkQePZDx2iRO_HfyINu2WIo5Fj_Iw9tUhzJr7IgzZ_fYRrglzXEy-80UIg5i1N6Rt-skwE7HBRB2HB_hD65OL-jefz1tgC1DvFPEDd0HnSUj4AnSPKCQeuCewWXXYfo_B42x28aD1TextSx4HTUZoFpB7WYUuX82-V-fSl5U4rwIpAi5TqYvhDR9IdfRS1k60Myk9LVIDOJ8b3p5M_-B8imctGFllzyk6aqnSOTkqEVFgO1eT3Go3Vjn739_QlL74v37QEYT-G5y541u8BwY67OIEeXyzjazGg3-Gefn4S_3dAemeVLUMcxrUgZuFk6sbHtzWcJXEFrRZZQECvn2bWjLKPrmuKrY8e6c6YplZvIbOZCP5z5IVgrqGhalJqx1wi6VuCBH6ZwE6rF1NZCsfY0jNvYiu3fp10k3fVi5L0EY-ESjbe8jmx025xXdEbiJ-Zrw2t0f5eO22TxE4-58JGi3rve15Ij_cjbGeliM7XQphogIijGbMX7mrNpWM5tE18aRVHuBhBhlSHAy5eLGZ7dpup3-E4yVv3TrQVvGtsjrJVjvJR-s_D7rWoBcJVM", + "p": "95WErVoEgW0R2ns2aldRmT3BnqDbFzLJWDzlNpPXoEk_3V7MiTuzKnWQ8uYJYqEF793GUfOQrrn8t65FeamexTSRt1-xI5VfTOrFCz5gqLq2n85UlTqhYRIhAXlmTjOTNvHhOZFVSjkILqVhn1N-X0uDRswpbkVMd4UdbQ5SbGr5OIpxQnSxL-RWsZtDnu4cSXbKz7aZrNq-xwGwxtUC0fh693b5y6ewwVksn5TIsg8Nwm8qrEmnzLqqE4yyarb3DNCezAoeLnym9Ivk7Gc646Hga2U4kOPSb-7M5lGWnXJc_WlCI7dp2ee3P4P_LPjK27MynoVn4Ov1PIm5YkAxuQ", + "q": "yRbmDPlxWYWW7vQ-9vuytHReMlATVAEJlmXBC8CU4Pu2qO7FGBieaHAB99ZT9zqIjdfCrYrXfjFaF_niGrG5kra-PK-m-xzTDNul0T1Yrw0k3tKRJ-GAQhKwYTR1MSAjGMm7N0rEm5Bo8-75nJ2hZov4mb1Ex0ab7gaqyui4SShY19pgIAMPg3rLzVevZAZLNIhTnoLx3MhQTzF_L7DRFrfbVxauL151K_SwbFet1jeuV2tTRbdO96N-ac8vtlfCCjKEfJ3Sv_zq9saGHFQjNd_cIOIvpDnQkHqV2paPwGZ3cZVcsaIESHIo6cutrwi6k_Z-G2KUPw3I4wlvBWTFaw", + "qi": "2eIh8Unn2uap4C8CFtDZhJZMVTv9z5YYaq3HCiP9k3Xist3_elVD87pj5ZeDG2HcjfpbXZDSWUvT7XIFe2tyyb3lkC5JCjSJDAEwxiOFlS637qufnmI2mgtURkSaftp-WI79IMzsXAeWNGXxzjS0hdMfZ3_jrd7d1YBIcMag45FZ2P0-aSf6MmPxiMzHXBKCsSY-WbMx30ZiH1ywxJWdExejnsb26FDZqkQtA2Y-_HVhf7bTwC4Tx0mtVzmXRw2UfFVINrf2hO-y7hMm5EL2v1hWOsofHePuyKtm7ijB8s5wFVF6MdXLDab9J4zbNI5aE5sZrBpH3yzJkSz4v2EMZA" + } + ] +}