From 4c115aac6d776ae21dd3d96a59683afa09982742 Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Mon, 30 Nov 2020 23:13:17 +0100 Subject: Fetch a client manifest on the web --- doc/webid-oidc.texi | 36 +++++ po/fr.po | 240 +++++++++++++++++---------------- po/webid-oidc.pot | 210 +++++++++++++++++------------ src/scm/webid-oidc/Makefile.am | 6 +- src/scm/webid-oidc/client-manifest.scm | 126 +++++++++++++++++ src/scm/webid-oidc/errors.scm | 92 +++++++++++++ tests/Makefile.am | 5 +- tests/client-manifest-fraudulent.scm | 66 +++++++++ tests/client-manifest-public.scm | 33 +++++ tests/client-manifest.scm | 85 ++++++++++++ 10 files changed, 694 insertions(+), 205 deletions(-) create mode 100644 src/scm/webid-oidc/client-manifest.scm create mode 100644 tests/client-manifest-fraudulent.scm create mode 100644 tests/client-manifest-public.scm create mode 100644 tests/client-manifest.scm diff --git a/doc/webid-oidc.texi b/doc/webid-oidc.texi index dc83ecc..9f456f3 100644 --- a/doc/webid-oidc.texi +++ b/doc/webid-oidc.texi @@ -390,6 +390,20 @@ The @var{value} of the htm field in the DPoP proof is incorrect. The @var{value} of the htu field in the DPoP proof is incorrect. @end deftp +@deftp {exception type} &incorrect-redirect-uris-field @var{value} +The @var{value} of the redirect-uris field of a client manifest is +incorrect. +@end deftp + +@deftp {exception type} &incorrect-typ-field @var{value} +The @var{value} of the typ field in the DPoP proof header is +incorrect. +@end deftp + +@deftp {exception type} ¬-a-client-manifest @var{value} @var{cause} +The @var{client-manifest} is incorrect. +@end deftp + @node Invalid JWT @section Invalid JWT Each JWT type – access token, DPoP proof, ID token, authorization code @@ -533,6 +547,10 @@ It is impossible to fetch the keys of @var{issuer} at @var{uri}. Could not fetch the graph referenced by @var{uri}. @end deftp +@deftp {exception type} &cannot-fetch-client-manifest @var{id} @var{cause} +Could not fetch a client manifest at @var{id}. +@end deftp + @node Other errors in the protocol or from a reasonable implementation @section Other errors in the protocol or from a reasonable implementation The protocol does not rely solely on JWT validation, so these errors @@ -567,6 +585,24 @@ occurred while confirming. The @var{jti} of the proof has already been issued in a recent past. @end deftp +@deftp {exception type} &unauthorized-redirection-uri @var{manifest} @var{uri} +The authorization @var{uri} is not advertised in @var{manifest}. +@end deftp + +@deftp {exception type} &cannot-serve-public-manifest +You cannot serve the public client manifest. +@end deftp + +@deftp {exception type} &no-client-manifest-registration @var{id} +The @var{id} client manifest does not have a registration triple in +its document. +@end deftp + +@deftp {exception type} &inconsistent-client-manifest-id @var{id} @var{advertised-id} +The client @var{manifest} is being fetched at @var{id}, but it is +valid for another client @var{advertised-id}. +@end deftp + @node GNU Free Documentation License @appendix GNU Free Documentation License diff --git a/po/fr.po b/po/fr.po index 80c20e2..b510987 100644 --- a/po/fr.po +++ b/po/fr.po @@ -126,101 +126,101 @@ msgstr "Utilisation : generate-random [NOMBRE D'OCTETS]\n" msgid "Usage: generate-key [NUMBER OF BITS | CURVE]\n" msgstr "Utilisation : generate-key [NOMBRE DE BITS | COURBE]\n" -#: src/scm/webid-oidc/errors.scm:560 +#: src/scm/webid-oidc/errors.scm:630 msgid "that’s how it is" msgstr "c’est comme ça" -#: src/scm/webid-oidc/errors.scm:565 +#: src/scm/webid-oidc/errors.scm:635 #, scheme-format msgid "the value ~s is not a base64 string (because ~a)" msgstr "la valeur ~s n’est pas une chaîne base64 (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:568 +#: src/scm/webid-oidc/errors.scm:638 #, scheme-format msgid "the value ~s is not JSON (because ~a)" msgstr "la valeur ~s n’est pas du JSON (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:571 +#: src/scm/webid-oidc/errors.scm:641 #, scheme-format msgid "the value ~s is not Turtle (because ~a)" msgstr "la valeur ~s n’est pas du Turtle (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:574 +#: src/scm/webid-oidc/errors.scm:644 #, scheme-format msgid "the value ~s does not identify an elleptic curve" msgstr "la valeur ~s n’identifie pas une courbe elliptique" -#: src/scm/webid-oidc/errors.scm:579 +#: src/scm/webid-oidc/errors.scm:649 #, scheme-format msgid "the value ~s does not identify a JWK (because ~a)" msgstr "la valeur ~s n’identifie pas une JWK (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:581 +#: src/scm/webid-oidc/errors.scm:651 #, scheme-format msgid "the value ~s does not identify a JWK" msgstr "la valeur ~s n’identifie pas une JWK" -#: src/scm/webid-oidc/errors.scm:586 +#: src/scm/webid-oidc/errors.scm:656 #, scheme-format msgid "the value ~s does not identify a public JWK (because ~a)" msgstr "la valeur ~s n’identifie pas une JWK publique (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:588 +#: src/scm/webid-oidc/errors.scm:658 #, scheme-format msgid "the value ~s does not identify a public JWK" msgstr "la valeur ~s n’identifie pas une JWK publique" -#: src/scm/webid-oidc/errors.scm:593 +#: src/scm/webid-oidc/errors.scm:663 #, scheme-format msgid "the value ~s does not identify a private JWK (because ~a)" msgstr "la valeur ~s n’identifie pas une JWK privée (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:595 +#: src/scm/webid-oidc/errors.scm:665 #, scheme-format msgid "the value ~s does not identify a private JWK" msgstr "la valeur ~s n’identifie pas une JWK privée" -#: src/scm/webid-oidc/errors.scm:600 +#: src/scm/webid-oidc/errors.scm:670 #, scheme-format msgid "the value ~s does not identify a JWKS (because ~a)" msgstr "la valeur ~s n’identifie pas un JWKS (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:602 +#: src/scm/webid-oidc/errors.scm:672 #, scheme-format msgid "the value ~s does not identify a JWKS" msgstr "la valeur ~s n’identifie pas un JWKS" -#: src/scm/webid-oidc/errors.scm:605 +#: src/scm/webid-oidc/errors.scm:675 #, scheme-format msgid "the value ~s does not identify a hash algorithm" msgstr "la valeur ~s n’identifie pas un algorithme de hachage" -#: src/scm/webid-oidc/errors.scm:608 +#: src/scm/webid-oidc/errors.scm:678 #, scheme-format msgid "the value ~s is not an alist or misses key ~s" msgstr "la valeur ~s n’est pas une alist ou il manque la clé ~s" -#: src/scm/webid-oidc/errors.scm:611 +#: src/scm/webid-oidc/errors.scm:681 #, scheme-format msgid "the value ~s is not a JWS header (because ~a)" msgstr "la valeur ~s n’est pas un header JWS (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:614 +#: src/scm/webid-oidc/errors.scm:684 #, scheme-format msgid "the value ~s is not a JWS payload (because ~a)" msgstr "la valeur ~s n’est pas un contenu JWS (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:617 +#: src/scm/webid-oidc/errors.scm:687 #, scheme-format msgid "the value ~s is not a JWS (because ~a)" msgstr "la valeur ~s n’est pas un JWS (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:620 +#: src/scm/webid-oidc/errors.scm:690 #, scheme-format msgid "the string ~s cannot be split in 3 parts with ~s" msgstr "la chaîne ~s ne peut pas être découpée en 3 parties avec ~s" -#: src/scm/webid-oidc/errors.scm:623 +#: src/scm/webid-oidc/errors.scm:693 #, scheme-format msgid "" "all key candidates failed to verify signature ~s with algorithm ~s and " @@ -229,17 +229,17 @@ msgstr "" "aucune clé candidate n’a pu vérifier la signature ~s avec l’algorithme ~s et " "le contenu ~a (il y en avait ~a : ~s)" -#: src/scm/webid-oidc/errors.scm:626 +#: src/scm/webid-oidc/errors.scm:696 #, scheme-format msgid "I cannot decode JWS ~a (because ~a)" msgstr "je n’ai pas pu décoder le JWS encodé par ~a (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:629 +#: src/scm/webid-oidc/errors.scm:699 #, scheme-format msgid "I cannot encode JWS ~a (because ~a)" msgstr "je n’ai pas pu encoder le JWS ~a (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:632 +#: src/scm/webid-oidc/errors.scm:702 #, scheme-format msgid "" "the server request unexpectedly failed with code ~a and reason phrase ~s" @@ -247,303 +247,341 @@ msgstr "" "la requête au serveur a échoué de façon inattendue avec un code ~a et une " "raison ~s" -#: src/scm/webid-oidc/errors.scm:637 +#: src/scm/webid-oidc/errors.scm:707 #, scheme-format msgid "the header ~a should not have the value ~s" msgstr "l’en-tête ~a ne devrait pas avoir la valeur ~s" -#: src/scm/webid-oidc/errors.scm:639 +#: src/scm/webid-oidc/errors.scm:709 #, scheme-format msgid "the header ~a should be present" msgstr "l’en-tête ~a devrait être présent" -#: src/scm/webid-oidc/errors.scm:642 +#: src/scm/webid-oidc/errors.scm:712 #, scheme-format msgid "the server response wasn't expected: ~s (because ~a)" msgstr "la réponse du serveur est inattendue : ~s (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:648 +#: src/scm/webid-oidc/errors.scm:718 #, scheme-format msgid "the value ~s is not an OIDC configuration (because ~a)" msgstr "la valeur ~s n’est pas une configuration OIDC (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:653 +#: src/scm/webid-oidc/errors.scm:723 #, scheme-format msgid "the webid field is incorrect: ~s" msgstr "le champ webid est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:654 +#: src/scm/webid-oidc/errors.scm:724 msgid "the webid field is missing" msgstr "le champ webid est manquant" -#: src/scm/webid-oidc/errors.scm:658 +#: src/scm/webid-oidc/errors.scm:728 #, scheme-format msgid "the iss field is incorrect: ~s" msgstr "le champ iss est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:659 +#: src/scm/webid-oidc/errors.scm:729 msgid "the iss field is missing" msgstr "le champ iss est manquant" -#: src/scm/webid-oidc/errors.scm:663 +#: src/scm/webid-oidc/errors.scm:733 #, scheme-format msgid "the aud field is incorrect: ~s" msgstr "le champ aud est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:664 +#: src/scm/webid-oidc/errors.scm:734 msgid "the aud field is missing" msgstr "le champ aud est manquant" -#: src/scm/webid-oidc/errors.scm:668 +#: src/scm/webid-oidc/errors.scm:738 #, scheme-format msgid "the iat field is incorrect: ~s" msgstr "le champ iat est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:669 +#: src/scm/webid-oidc/errors.scm:739 msgid "the iat field is missing" msgstr "le champ iat est manquant" -#: src/scm/webid-oidc/errors.scm:673 +#: src/scm/webid-oidc/errors.scm:743 #, scheme-format msgid "the exp field is incorrect: ~s" msgstr "le champ exp est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:674 +#: src/scm/webid-oidc/errors.scm:744 msgid "the exp field is missing" msgstr "le champ exp est manquant" -#: src/scm/webid-oidc/errors.scm:678 +#: src/scm/webid-oidc/errors.scm:748 #, scheme-format msgid "the cnf/jkt field is incorrect: ~s" msgstr "le champ cnf/jkt est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:679 +#: src/scm/webid-oidc/errors.scm:749 msgid "the cnf/jkt field is missing" msgstr "le champ cnf/jkt est manquant" -#: src/scm/webid-oidc/errors.scm:683 +#: src/scm/webid-oidc/errors.scm:753 #, scheme-format msgid "the client-id field is incorrect: ~s" msgstr "le champ client-id est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:684 +#: src/scm/webid-oidc/errors.scm:754 msgid "the client-id field is missing" msgstr "le champ client-id est manquant" -#: src/scm/webid-oidc/errors.scm:688 +#: src/scm/webid-oidc/errors.scm:758 +#, scheme-format +msgid "the redirect_uris field is incorrect: ~s" +msgstr "le champ redirect_uris est incorrect : ~s" + +#: src/scm/webid-oidc/errors.scm:759 +msgid "the redirect_uris field is missing" +msgstr "le champ redirect_uris est manquant" + +#: src/scm/webid-oidc/errors.scm:763 #, scheme-format msgid "the typ field is incorrect: ~s" msgstr "le champ typ est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:689 +#: src/scm/webid-oidc/errors.scm:764 msgid "the typ field is missing" msgstr "le champ typ est manquant" -#: src/scm/webid-oidc/errors.scm:693 +#: src/scm/webid-oidc/errors.scm:768 #, scheme-format msgid "the jwk field is incorrect: ~s (because ~a)" msgstr "le champ jwk est incorrect : ~s (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:695 +#: src/scm/webid-oidc/errors.scm:770 msgid "the jwk field is missing" msgstr "le champ jwk est manquant" -#: src/scm/webid-oidc/errors.scm:699 +#: src/scm/webid-oidc/errors.scm:774 #, scheme-format msgid "the jti field is incorrect: ~s" msgstr "le champ jti est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:700 +#: src/scm/webid-oidc/errors.scm:775 msgid "the jti field is missing" msgstr "le champ jti est manquant" -#: src/scm/webid-oidc/errors.scm:704 +#: src/scm/webid-oidc/errors.scm:779 #, scheme-format msgid "the htm field is incorrect: ~s" msgstr "le champ htm est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:705 +#: src/scm/webid-oidc/errors.scm:780 msgid "the htm field is missing" msgstr "le champ htm est manquant" -#: src/scm/webid-oidc/errors.scm:709 +#: src/scm/webid-oidc/errors.scm:784 #, scheme-format msgid "the htu field is incorrect: ~s" msgstr "le champ htu est incorrect : ~s" -#: src/scm/webid-oidc/errors.scm:710 +#: src/scm/webid-oidc/errors.scm:785 msgid "the htu field is missing" msgstr "le champ htu est manquant" -#: src/scm/webid-oidc/errors.scm:712 +#: src/scm/webid-oidc/errors.scm:787 #, scheme-format msgid "~s is not an access token (because ~a)" msgstr "~s n’est pas un jeton d’accès (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:715 +#: src/scm/webid-oidc/errors.scm:790 #, scheme-format msgid "~s is not an access token header (because ~a)" msgstr "~s n’est pas un en-tête de jeton d’accès (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:718 +#: src/scm/webid-oidc/errors.scm:793 #, scheme-format msgid "~s is not an access token payload (because ~a)" msgstr "~s n’est pas un contenu de jeton d’accès (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:721 +#: src/scm/webid-oidc/errors.scm:796 #, scheme-format msgid "~s is not a DPoP proof (because ~a)" msgstr "~s n’est pas une preuve DPoP (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:724 +#: src/scm/webid-oidc/errors.scm:799 #, scheme-format msgid "~s is not a DPoP proof header (because ~a)" msgstr "~s n’est pas un en-tête de preuve DPoP (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:727 +#: src/scm/webid-oidc/errors.scm:802 #, scheme-format msgid "~s is not a DPoP proof payload (because ~a)" msgstr "~s n’est pas un contenu de preuve DPoP (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:730 +#: src/scm/webid-oidc/errors.scm:805 #, scheme-format msgid "I cannot fetch the issuer configuration of ~a (because ~a)" msgstr "" "je n’ai pas pu récupérer la configuration de l’émetteur ~a (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:737 +#: src/scm/webid-oidc/errors.scm:812 #, scheme-format msgid "I cannot fetch the JWKS of ~a at ~a (because ~a)" msgstr "je n’ai pas pu récupérer le JWKS de ~a à ~a (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:748 +#: src/scm/webid-oidc/errors.scm:823 #, scheme-format msgid "the HTTP method is signed for ~s, but ~s was requested" msgstr "la méthode HTTP a été signée pour ~s, mais ~s a été demandé" -#: src/scm/webid-oidc/errors.scm:751 +#: src/scm/webid-oidc/errors.scm:826 #, scheme-format msgid "the HTTP uri is signed for ~a, but ~a was requested" msgstr "l’uri HTTP a été signé pour ~a, mais ~a a été demandé" -#: src/scm/webid-oidc/errors.scm:754 +#: src/scm/webid-oidc/errors.scm:829 #, scheme-format msgid "the date is ~a, but the DPoP proof is signed in the future at ~a" msgstr "la date est ~a, mais la preuve DPoP a été signée dans le futur à ~a" -#: src/scm/webid-oidc/errors.scm:758 +#: src/scm/webid-oidc/errors.scm:833 #, scheme-format msgid "the date is ~a, but the DPoP proof was signed too long ago at ~a" msgstr "" "la date est ~a, mais la preuve DPoP a été signée il y a trop longtemps à ~a" -#: src/scm/webid-oidc/errors.scm:767 +#: src/scm/webid-oidc/errors.scm:842 #, scheme-format msgid "the key ~s does not hash to ~a" msgstr "la clé ~s ne donne pas un hash de ~a" -#: src/scm/webid-oidc/errors.scm:769 +#: src/scm/webid-oidc/errors.scm:844 #, scheme-format msgid "the key confirmation of ~s failed (because ~a)" msgstr "la confirmation de clé de ~s a échoué (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:771 +#: src/scm/webid-oidc/errors.scm:846 #, scheme-format msgid "the key confirmation of ~s failed" msgstr "la confirmation de la clé ~s a échoué" -#: src/scm/webid-oidc/errors.scm:773 +#: src/scm/webid-oidc/errors.scm:848 #, scheme-format msgid "the jti ~s has already been found (because ~a)" msgstr "le jti ~s a déjà été trouvé (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:776 +#: src/scm/webid-oidc/errors.scm:851 #, scheme-format msgid "I cannot decode ~s as an access token (because ~a)" msgstr "je n’ai pas pu décoder ~s comme jeton d’accès (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:779 +#: src/scm/webid-oidc/errors.scm:854 #, scheme-format msgid "I cannot encode ~s as an access token with key ~s (because ~a)" msgstr "" "je n’ai pas pu encoder ~s comme un jeton d’accès avec la clé ~s (parce que " "~a)" -#: src/scm/webid-oidc/errors.scm:782 +#: src/scm/webid-oidc/errors.scm:857 #, scheme-format msgid "I cannot decode ~s as a DPoP proof (because ~a)" msgstr "je n’ai pas pu décoder ~s comme preuve DPoP (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:785 +#: src/scm/webid-oidc/errors.scm:860 #, scheme-format msgid "I cannot encode ~s as a DPoP proof (because ~a)" msgstr "je n’ai pas pu encoder ~s comme une preuve DPoP (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:788 +#: src/scm/webid-oidc/errors.scm:863 #, scheme-format msgid "I could not fetch a RDF graph at ~a (because ~a)" msgstr "je n’ai pas pu récupérer de graphe RDF à ~a (parce que ~a)" -#: src/scm/webid-oidc/errors.scm:793 +#: src/scm/webid-oidc/errors.scm:866 +#, scheme-format +msgid "~s is not a client manifest (because ~a)" +msgstr "~s n’est pas un manifeste client (parce que ~a)" + +#: src/scm/webid-oidc/errors.scm:869 +#, scheme-format +msgid "~s does not authorize redirection URI ~a" +msgstr "~s n’autorise pas l’URI de redirection ~a" + +#: src/scm/webid-oidc/errors.scm:872 +msgid "I cannot serve a public manifest" +msgstr "je ne peux pas servir un manifeste public" + +#: src/scm/webid-oidc/errors.scm:874 +#, scheme-format +msgid "~a does not have a client manifest registration triple" +msgstr "~a n’a pas de triplet d’enregistrement de manifeste client" + +#: src/scm/webid-oidc/errors.scm:877 +#, scheme-format +msgid "the client manifest at ~a is advertised for ~a" +msgstr "le manifeste client ~a est publié pour ~a" + +#: src/scm/webid-oidc/errors.scm:880 +#, scheme-format +msgid "I could not fetch the client manifest of ~a (because ~a)" +msgstr "je n’ai pas pu récupérer le manifeste client de ~a (parce que ~a)" + +#: src/scm/webid-oidc/errors.scm:885 msgid "that’s it" msgstr "c’est tout" -#: src/scm/webid-oidc/errors.scm:797 +#: src/scm/webid-oidc/errors.scm:889 #, scheme-format msgid "~a and ~a" msgstr "~a et ~a" -#: src/scm/webid-oidc/errors.scm:800 +#: src/scm/webid-oidc/errors.scm:892 #, scheme-format msgid "~a, ~a" msgstr "~a, ~a" -#: src/scm/webid-oidc/errors.scm:804 +#: src/scm/webid-oidc/errors.scm:896 #, scheme-format msgid "the signature ~a does not match key ~s with payload ~a" msgstr "la signature ~a ne correspond pas à la clé ~s avec le contenu ~a" -#: src/scm/webid-oidc/errors.scm:807 +#: src/scm/webid-oidc/errors.scm:899 msgid "there is an undefined variable" msgstr "il y a une variable non définie" -#: src/scm/webid-oidc/errors.scm:809 +#: src/scm/webid-oidc/errors.scm:901 #, scheme-format msgid "the origin is ~a" msgstr "l’origine est ~a" -#: src/scm/webid-oidc/errors.scm:812 +#: src/scm/webid-oidc/errors.scm:904 #, scheme-format msgid "a message is attached: ~a" msgstr "un message est attaché : ~a" -#: src/scm/webid-oidc/errors.scm:815 +#: src/scm/webid-oidc/errors.scm:907 #, scheme-format msgid "the values ~s are problematic" msgstr "les valeurs ~s sont problématiques" -#: src/scm/webid-oidc/errors.scm:818 +#: src/scm/webid-oidc/errors.scm:910 msgid "there is a kind and args" msgstr "il y a un type et des arguments" -#: src/scm/webid-oidc/errors.scm:820 +#: src/scm/webid-oidc/errors.scm:912 msgid "there is an assertion failure" msgstr "il y a un échec d’assertion" -#: src/scm/webid-oidc/errors.scm:822 +#: src/scm/webid-oidc/errors.scm:914 #, scheme-format msgid "the program quits with code ~a" msgstr "le programme quitte avec le code ~a" -#: src/scm/webid-oidc/errors.scm:825 +#: src/scm/webid-oidc/errors.scm:917 msgid "the program cannot recover from this exception" msgstr "le programme ne peut pas récupérer après cette exception" -#: src/scm/webid-oidc/errors.scm:827 +#: src/scm/webid-oidc/errors.scm:919 msgid "there is an error" msgstr "il y a une erreur" -#: src/scm/webid-oidc/errors.scm:829 +#: src/scm/webid-oidc/errors.scm:921 #, scheme-format msgid "Unhandled exception type ~a." msgstr "Type d’exception non pris en charge ~a." @@ -555,13 +593,6 @@ msgstr "Type d’exception non pris en charge ~a." #~ msgid "the sub field is missing" #~ msgstr "le champ sub est manquant" -#, scheme-format -#~ msgid "the redirect_uris field is incorrect: ~s" -#~ msgstr "le champ redirect_uris est incorrect : ~s" - -#~ msgid "the redirect_uris field is missing" -#~ msgstr "le champ redirect_uris est manquant" - #, scheme-format #~ msgid "the nonce field is incorrect: ~s" #~ msgstr "le champ nonce est incorrect : ~s" @@ -569,29 +600,6 @@ msgstr "Type d’exception non pris en charge ~a." #~ msgid "the nonce field is missing" #~ msgstr "le champ nonce est manquant" -#, scheme-format -#~ msgid "~s is not a client manifest (because ~a)" -#~ msgstr "~s n’est pas un manifeste client (parce que ~a)" - -#, scheme-format -#~ msgid "~s does not authorize redirection URI ~a" -#~ msgstr "~s n’autorise pas l’URI de redirection ~a" - -#~ msgid "I cannot serve a public manifest" -#~ msgstr "je ne peux pas servir un manifeste public" - -#, scheme-format -#~ msgid "~a does not have a client manifest registration triple" -#~ msgstr "~a n’a pas de triplet d’enregistrement de manifeste client" - -#, scheme-format -#~ msgid "the client manifest at ~a is advertised for ~a" -#~ msgstr "le manifeste client ~a est publié pour ~a" - -#, scheme-format -#~ msgid "I could not fetch the client manifest of ~a (because ~a)" -#~ msgstr "je n’ai pas pu récupérer le manifeste client de ~a (parce que ~a)" - #, scheme-format #~ msgid "~s is not an authorization code (because ~a)" #~ msgstr "~s n’est pas un code d’autorisation (parce que ~a)" diff --git a/po/webid-oidc.pot b/po/webid-oidc.pot index df200d3..e9f6b2d 100644 --- a/po/webid-oidc.pot +++ b/po/webid-oidc.pot @@ -122,416 +122,454 @@ msgstr "" msgid "Usage: generate-key [NUMBER OF BITS | CURVE]\n" msgstr "" -#: src/scm/webid-oidc/errors.scm:560 +#: src/scm/webid-oidc/errors.scm:630 msgid "that’s how it is" msgstr "" -#: src/scm/webid-oidc/errors.scm:565 +#: src/scm/webid-oidc/errors.scm:635 #, scheme-format msgid "the value ~s is not a base64 string (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:568 +#: src/scm/webid-oidc/errors.scm:638 #, scheme-format msgid "the value ~s is not JSON (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:571 +#: src/scm/webid-oidc/errors.scm:641 #, scheme-format msgid "the value ~s is not Turtle (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:574 +#: src/scm/webid-oidc/errors.scm:644 #, scheme-format msgid "the value ~s does not identify an elleptic curve" msgstr "" -#: src/scm/webid-oidc/errors.scm:579 +#: src/scm/webid-oidc/errors.scm:649 #, scheme-format msgid "the value ~s does not identify a JWK (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:581 +#: src/scm/webid-oidc/errors.scm:651 #, scheme-format msgid "the value ~s does not identify a JWK" msgstr "" -#: src/scm/webid-oidc/errors.scm:586 +#: src/scm/webid-oidc/errors.scm:656 #, scheme-format msgid "the value ~s does not identify a public JWK (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:588 +#: src/scm/webid-oidc/errors.scm:658 #, scheme-format msgid "the value ~s does not identify a public JWK" msgstr "" -#: src/scm/webid-oidc/errors.scm:593 +#: src/scm/webid-oidc/errors.scm:663 #, scheme-format msgid "the value ~s does not identify a private JWK (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:595 +#: src/scm/webid-oidc/errors.scm:665 #, scheme-format msgid "the value ~s does not identify a private JWK" msgstr "" -#: src/scm/webid-oidc/errors.scm:600 +#: src/scm/webid-oidc/errors.scm:670 #, scheme-format msgid "the value ~s does not identify a JWKS (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:602 +#: src/scm/webid-oidc/errors.scm:672 #, scheme-format msgid "the value ~s does not identify a JWKS" msgstr "" -#: src/scm/webid-oidc/errors.scm:605 +#: src/scm/webid-oidc/errors.scm:675 #, scheme-format msgid "the value ~s does not identify a hash algorithm" msgstr "" -#: src/scm/webid-oidc/errors.scm:608 +#: src/scm/webid-oidc/errors.scm:678 #, scheme-format msgid "the value ~s is not an alist or misses key ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:611 +#: src/scm/webid-oidc/errors.scm:681 #, scheme-format msgid "the value ~s is not a JWS header (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:614 +#: src/scm/webid-oidc/errors.scm:684 #, scheme-format msgid "the value ~s is not a JWS payload (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:617 +#: src/scm/webid-oidc/errors.scm:687 #, scheme-format msgid "the value ~s is not a JWS (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:620 +#: src/scm/webid-oidc/errors.scm:690 #, scheme-format msgid "the string ~s cannot be split in 3 parts with ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:623 +#: src/scm/webid-oidc/errors.scm:693 #, scheme-format msgid "" "all key candidates failed to verify signature ~s with algorithm ~s and " "payload ~a (there were ~a: ~s)" msgstr "" -#: src/scm/webid-oidc/errors.scm:626 +#: src/scm/webid-oidc/errors.scm:696 #, scheme-format msgid "I cannot decode JWS ~a (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:629 +#: src/scm/webid-oidc/errors.scm:699 #, scheme-format msgid "I cannot encode JWS ~a (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:632 +#: src/scm/webid-oidc/errors.scm:702 #, scheme-format msgid "" "the server request unexpectedly failed with code ~a and reason phrase ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:637 +#: src/scm/webid-oidc/errors.scm:707 #, scheme-format msgid "the header ~a should not have the value ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:639 +#: src/scm/webid-oidc/errors.scm:709 #, scheme-format msgid "the header ~a should be present" msgstr "" -#: src/scm/webid-oidc/errors.scm:642 +#: src/scm/webid-oidc/errors.scm:712 #, scheme-format msgid "the server response wasn't expected: ~s (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:648 +#: src/scm/webid-oidc/errors.scm:718 #, scheme-format msgid "the value ~s is not an OIDC configuration (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:653 +#: src/scm/webid-oidc/errors.scm:723 #, scheme-format msgid "the webid field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:654 +#: src/scm/webid-oidc/errors.scm:724 msgid "the webid field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:658 +#: src/scm/webid-oidc/errors.scm:728 #, scheme-format msgid "the iss field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:659 +#: src/scm/webid-oidc/errors.scm:729 msgid "the iss field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:663 +#: src/scm/webid-oidc/errors.scm:733 #, scheme-format msgid "the aud field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:664 +#: src/scm/webid-oidc/errors.scm:734 msgid "the aud field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:668 +#: src/scm/webid-oidc/errors.scm:738 #, scheme-format msgid "the iat field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:669 +#: src/scm/webid-oidc/errors.scm:739 msgid "the iat field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:673 +#: src/scm/webid-oidc/errors.scm:743 #, scheme-format msgid "the exp field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:674 +#: src/scm/webid-oidc/errors.scm:744 msgid "the exp field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:678 +#: src/scm/webid-oidc/errors.scm:748 #, scheme-format msgid "the cnf/jkt field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:679 +#: src/scm/webid-oidc/errors.scm:749 msgid "the cnf/jkt field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:683 +#: src/scm/webid-oidc/errors.scm:753 #, scheme-format msgid "the client-id field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:684 +#: src/scm/webid-oidc/errors.scm:754 msgid "the client-id field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:688 +#: src/scm/webid-oidc/errors.scm:758 +#, scheme-format +msgid "the redirect_uris field is incorrect: ~s" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:759 +msgid "the redirect_uris field is missing" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:763 #, scheme-format msgid "the typ field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:689 +#: src/scm/webid-oidc/errors.scm:764 msgid "the typ field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:693 +#: src/scm/webid-oidc/errors.scm:768 #, scheme-format msgid "the jwk field is incorrect: ~s (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:695 +#: src/scm/webid-oidc/errors.scm:770 msgid "the jwk field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:699 +#: src/scm/webid-oidc/errors.scm:774 #, scheme-format msgid "the jti field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:700 +#: src/scm/webid-oidc/errors.scm:775 msgid "the jti field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:704 +#: src/scm/webid-oidc/errors.scm:779 #, scheme-format msgid "the htm field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:705 +#: src/scm/webid-oidc/errors.scm:780 msgid "the htm field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:709 +#: src/scm/webid-oidc/errors.scm:784 #, scheme-format msgid "the htu field is incorrect: ~s" msgstr "" -#: src/scm/webid-oidc/errors.scm:710 +#: src/scm/webid-oidc/errors.scm:785 msgid "the htu field is missing" msgstr "" -#: src/scm/webid-oidc/errors.scm:712 +#: src/scm/webid-oidc/errors.scm:787 #, scheme-format msgid "~s is not an access token (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:715 +#: src/scm/webid-oidc/errors.scm:790 #, scheme-format msgid "~s is not an access token header (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:718 +#: src/scm/webid-oidc/errors.scm:793 #, scheme-format msgid "~s is not an access token payload (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:721 +#: src/scm/webid-oidc/errors.scm:796 #, scheme-format msgid "~s is not a DPoP proof (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:724 +#: src/scm/webid-oidc/errors.scm:799 #, scheme-format msgid "~s is not a DPoP proof header (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:727 +#: src/scm/webid-oidc/errors.scm:802 #, scheme-format msgid "~s is not a DPoP proof payload (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:730 +#: src/scm/webid-oidc/errors.scm:805 #, scheme-format msgid "I cannot fetch the issuer configuration of ~a (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:737 +#: src/scm/webid-oidc/errors.scm:812 #, scheme-format msgid "I cannot fetch the JWKS of ~a at ~a (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:748 +#: src/scm/webid-oidc/errors.scm:823 #, scheme-format msgid "the HTTP method is signed for ~s, but ~s was requested" msgstr "" -#: src/scm/webid-oidc/errors.scm:751 +#: src/scm/webid-oidc/errors.scm:826 #, scheme-format msgid "the HTTP uri is signed for ~a, but ~a was requested" msgstr "" -#: src/scm/webid-oidc/errors.scm:754 +#: src/scm/webid-oidc/errors.scm:829 #, scheme-format msgid "the date is ~a, but the DPoP proof is signed in the future at ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:758 +#: src/scm/webid-oidc/errors.scm:833 #, scheme-format msgid "the date is ~a, but the DPoP proof was signed too long ago at ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:767 +#: src/scm/webid-oidc/errors.scm:842 #, scheme-format msgid "the key ~s does not hash to ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:769 +#: src/scm/webid-oidc/errors.scm:844 #, scheme-format msgid "the key confirmation of ~s failed (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:771 +#: src/scm/webid-oidc/errors.scm:846 #, scheme-format msgid "the key confirmation of ~s failed" msgstr "" -#: src/scm/webid-oidc/errors.scm:773 +#: src/scm/webid-oidc/errors.scm:848 #, scheme-format msgid "the jti ~s has already been found (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:776 +#: src/scm/webid-oidc/errors.scm:851 #, scheme-format msgid "I cannot decode ~s as an access token (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:779 +#: src/scm/webid-oidc/errors.scm:854 #, scheme-format msgid "I cannot encode ~s as an access token with key ~s (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:782 +#: src/scm/webid-oidc/errors.scm:857 #, scheme-format msgid "I cannot decode ~s as a DPoP proof (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:785 +#: src/scm/webid-oidc/errors.scm:860 #, scheme-format msgid "I cannot encode ~s as a DPoP proof (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:788 +#: src/scm/webid-oidc/errors.scm:863 #, scheme-format msgid "I could not fetch a RDF graph at ~a (because ~a)" msgstr "" -#: src/scm/webid-oidc/errors.scm:793 +#: src/scm/webid-oidc/errors.scm:866 +#, scheme-format +msgid "~s is not a client manifest (because ~a)" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:869 +#, scheme-format +msgid "~s does not authorize redirection URI ~a" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:872 +msgid "I cannot serve a public manifest" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:874 +#, scheme-format +msgid "~a does not have a client manifest registration triple" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:877 +#, scheme-format +msgid "the client manifest at ~a is advertised for ~a" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:880 +#, scheme-format +msgid "I could not fetch the client manifest of ~a (because ~a)" +msgstr "" + +#: src/scm/webid-oidc/errors.scm:885 msgid "that’s it" msgstr "" -#: src/scm/webid-oidc/errors.scm:797 +#: src/scm/webid-oidc/errors.scm:889 #, scheme-format msgid "~a and ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:800 +#: src/scm/webid-oidc/errors.scm:892 #, scheme-format msgid "~a, ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:804 +#: src/scm/webid-oidc/errors.scm:896 #, scheme-format msgid "the signature ~a does not match key ~s with payload ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:807 +#: src/scm/webid-oidc/errors.scm:899 msgid "there is an undefined variable" msgstr "" -#: src/scm/webid-oidc/errors.scm:809 +#: src/scm/webid-oidc/errors.scm:901 #, scheme-format msgid "the origin is ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:812 +#: src/scm/webid-oidc/errors.scm:904 #, scheme-format msgid "a message is attached: ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:815 +#: src/scm/webid-oidc/errors.scm:907 #, scheme-format msgid "the values ~s are problematic" msgstr "" -#: src/scm/webid-oidc/errors.scm:818 +#: src/scm/webid-oidc/errors.scm:910 msgid "there is a kind and args" msgstr "" -#: src/scm/webid-oidc/errors.scm:820 +#: src/scm/webid-oidc/errors.scm:912 msgid "there is an assertion failure" msgstr "" -#: src/scm/webid-oidc/errors.scm:822 +#: src/scm/webid-oidc/errors.scm:914 #, scheme-format msgid "the program quits with code ~a" msgstr "" -#: src/scm/webid-oidc/errors.scm:825 +#: src/scm/webid-oidc/errors.scm:917 msgid "the program cannot recover from this exception" msgstr "" -#: src/scm/webid-oidc/errors.scm:827 +#: src/scm/webid-oidc/errors.scm:919 msgid "there is an error" msgstr "" -#: src/scm/webid-oidc/errors.scm:829 +#: src/scm/webid-oidc/errors.scm:921 #, scheme-format msgid "Unhandled exception type ~a." msgstr "" diff --git a/src/scm/webid-oidc/Makefile.am b/src/scm/webid-oidc/Makefile.am index 31c23ab..709eb1b 100644 --- a/src/scm/webid-oidc/Makefile.am +++ b/src/scm/webid-oidc/Makefile.am @@ -9,7 +9,8 @@ dist_webidoidcmod_DATA += \ %reldir%/access-token.scm \ %reldir%/jti.scm \ %reldir%/dpop-proof.scm \ - %reldir%/fetch.scm + %reldir%/fetch.scm \ + %reldir%/client-manifest.scm webidoidcgo_DATA += \ %reldir%/errors.go \ %reldir%/stubs.go \ @@ -21,4 +22,5 @@ webidoidcgo_DATA += \ %reldir%/access-token.go \ %reldir%/jti.go \ %reldir%/dpop-proof.go \ - %reldir%/fetch.go + %reldir%/fetch.go \ + %reldir%/client-manifest.go diff --git a/src/scm/webid-oidc/client-manifest.scm b/src/scm/webid-oidc/client-manifest.scm new file mode 100644 index 0000000..54c098a --- /dev/null +++ b/src/scm/webid-oidc/client-manifest.scm @@ -0,0 +1,126 @@ +(define-module (webid-oidc client-manifest) + #:use-module (webid-oidc errors) + #:use-module (webid-oidc fetch) + #:use-module ((webid-oidc stubs) #:prefix stubs:) + #:use-module (web uri) + #:use-module (web client) + #:use-module (web response) + #:use-module (rnrs bytevectors) + #:use-module (srfi srfi-19) + #:use-module (ice-9 receive) + #:use-module (ice-9 optargs) + #:use-module (rdf rdf) + #:use-module (turtle tordf)) + +(define-public public-oidc-client + 'public-oidc-client) + +(define-public (all-uris x) + (or (null? x) + (and (string->uri (car x)) + (all-uris (cdr x))))) + +(define-public (the-client-manifest x) + (if (eq? x public-oidc-client) + public-oidc-client + (let ((client-id (assq-ref x 'client_id)) + (redirect-uris (assq-ref x 'redirect_uris))) + (unless (and client-id (string? client-id) (string->uri client-id)) + (raise-incorrect-client-id-field client-id)) + (unless (and redirect-uris + (vector? redirect-uris) + (all-uris (vector->list redirect-uris))) + (raise-incorrect-redirect-uris-field redirect-uris)) + x))) + +(define-public (client-manifest? obj) + (false-if-exception + (and (the-client-manifest obj) #t))) + +(define-public (make-client-manifest client-id redirect-uris) + (the-client-manifest + `((client_id . ,(uri->string client-id)) + (redirect_uris . ,(list->vector + (map uri->string + redirect-uris)))))) + +(define-public (client-manifest-client-id mf) + (if (eq? mf public-oidc-client) + (string->uri "http://www.w3.org/ns/solid/terms#PublicOidcClient") + (string->uri (assq-ref (the-client-manifest mf) 'client_id)))) + +(define (check-redirect mf uris redir) + (if (null? uris) + (raise-unauthorized-redirection-uri mf (string->uri redir)) + (or (string=? (car uris) redir) + (check-redirect mf (cdr uris) redir)))) + +(define-public (client-manifest-check-redirect-uri mf redir) + (unless (uri? redir) + (set! redir (string->uri redir))) + (if (eq? mf public-oidc-client) + #t + (let ((redirect-uris + (assq-ref (the-client-manifest mf) 'redirect_uris))) + (check-redirect (the-client-manifest mf) + (vector->list redirect-uris) + (uri->string redir))))) + +(define (turtle-escape str) + (define (folder c other) + (if (or (eq? c #\\) (eq? c #\")) + (cons* c #\\ other) + (cons c other))) + (list->string (reverse (string-fold folder '() str)))) + +(define-public (serve-client-manifest expiration-date mf) + (when (eq? mf public-oidc-client) + (raise-cannot-serve-public-manifest)) + (let ((json-object (stubs:scm->json-string (the-client-manifest mf))) + (id (uri->string (client-manifest-client-id (the-client-manifest mf))))) + (let ((resource (string-append " +@prefix solid: . + +<" id "> solid:oidcRegistration \"\"\" +" (turtle-escape json-object) " +\"\"\" . +"))) + (values (build-response #:headers `((content-type text/turtle) + (expires . ,expiration-date))) + resource)))) + +(define (find-registration id graph) + (cond ((null? graph) + (raise-no-client-manifest-registration (string->uri id))) + ((and (string=? (rdf-triple-predicate (car graph)) + "http://www.w3.org/ns/solid/terms#oidcRegistration") + (string? (rdf-triple-subject (car graph))) + (string=? (rdf-triple-subject (car graph)) id) + (rdf-literal? (rdf-triple-object (car graph))) + (string=? (rdf-literal-type (rdf-triple-object (car graph))) + "http://www.w3.org/2001/XMLSchema#string")) + (let ((object (rdf-triple-object (car graph)))) + (let ((ret (stubs:json-string->scm (rdf-literal-lexical-form object)))) + (if (client-manifest? ret) + (begin + (unless (equal? (uri->string (client-manifest-client-id ret)) + id) + (raise-inconsistent-client-manifest-id (string->uri id) + (client-manifest-client-id ret))) + ret) + (find-registration id (cdr graph)))))) + (else (find-registration id (cdr graph))))) + +(define*-public (get-client-manifest id + #:key + (http-get http-get)) + (with-exception-handler + (lambda (error) + (raise-cannot-fetch-client-manifest id error)) + (lambda () + (if (equal? id + (string->uri + "http://www.w3.org/ns/solid/terms#PublicOidcClient")) + public-oidc-client + (let ((graph (fetch id #:http-get http-get))) + (find-registration (uri->string id) graph)))))) diff --git a/src/scm/webid-oidc/errors.scm b/src/scm/webid-oidc/errors.scm index 2dc9edc..d6f685a 100644 --- a/src/scm/webid-oidc/errors.scm +++ b/src/scm/webid-oidc/errors.scm @@ -309,6 +309,16 @@ (raise-exception ((record-constructor &incorrect-client-id-field) value))) +(define-public &incorrect-redirect-uris-field + (make-exception-type + '&incorrect-redirect-uris-field + &external-error + '(value))) + +(define-public (raise-incorrect-redirect-uris-field value) + (raise-exception + ((record-constructor &incorrect-redirect-uris-field) value))) + (define-public &incorrect-typ-field (make-exception-type '&incorrect-typ-field @@ -549,6 +559,66 @@ (raise-exception ((record-constructor &cannot-fetch-linked-data) uri cause))) +(define-public ¬-a-client-manifest + (make-exception-type + '¬-a-client-manifest + &external-error + '(value cause))) + +(define-public (raise-not-a-client-manifest value cause) + (raise-exception + ((record-constructor ¬-a-client-manifest) value cause))) + +(define-public &unauthorized-redirection-uri + (make-exception-type + '&unauthorized-redirection-uri + &external-error + '(manifest uri))) + +(define-public (raise-unauthorized-redirection-uri manifest uri) + (raise-exception + ((record-constructor &unauthorized-redirection-uri) manifest uri))) + +(define-public &cannot-serve-public-manifest + (make-exception-type + '&cannot-serve-public-manifest + &external-error + '())) + +(define-public (raise-cannot-serve-public-manifest) + (raise-exception + ((record-constructor &cannot-serve-public-manifest)))) + +(define-public &no-client-manifest-registration + (make-exception-type + '&no-client-manifest-registration + &external-error + '(id))) + +(define-public (raise-no-client-manifest-registration id) + (raise-exception + ((record-constructor &no-client-manifest-registration) id))) + +(define-public &inconsistent-client-manifest-id + (make-exception-type + '&inconsistent-client-manifest-id + &external-error + '(id advertised-id))) + +(define-public (raise-inconsistent-client-manifest-id id advertised-id) + (raise-exception + ((record-constructor &inconsistent-client-manifest-id) id advertised-id))) + +(define-public &cannot-fetch-client-manifest + (make-exception-type + '&cannot-fetch-client-manifest + &external-error + '(id cause))) + +(define-public (raise-cannot-fetch-client-manifest id cause) + (raise-exception + ((record-constructor &cannot-fetch-client-manifest) id cause))) + (define*-public (error->str err #:key (max-depth #f)) (if (record? err) (let* ((type (record-type-descriptor err)) @@ -682,6 +752,11 @@ (if value (format #f (G_ "the client-id field is incorrect: ~s") value) (format #f (G_ "the client-id field is missing"))))) + ((&incorrect-redirect-uris-field) + (let ((value (get 'value))) + (if value + (format #f (G_ "the redirect_uris field is incorrect: ~s") value) + (format #f (G_ "the redirect_uris field is missing"))))) ((&incorrect-typ-field) (let ((value (get 'value))) (if value @@ -787,6 +862,23 @@ ((&cannot-fetch-linked-data) (format #f (G_ "I could not fetch a RDF graph at ~a (because ~a)") (uri->string (get 'uri)) (recurse (get 'cause)))) + ((¬-a-client-manifest) + (format #f (G_ "~s is not a client manifest (because ~a)") + (get 'value) (recurse (get 'cause)))) + ((&unauthorized-redirection-uri) + (format #f (G_ "~s does not authorize redirection URI ~a") + (get 'manifest) (uri->string (get 'uri)))) + ((&cannot-serve-public-manifest) + (format #f (G_ "I cannot serve a public manifest"))) + ((&no-client-manifest-registration) + (format #f (G_ "~a does not have a client manifest registration triple") + (uri->string (get 'id)))) + ((&inconsistent-client-manifest-id) + (format #f (G_ "the client manifest at ~a is advertised for ~a") + (uri->string (get 'id)) (uri->string (get 'advertised-id)))) + ((&cannot-fetch-client-manifest) + (format #f (G_ "I could not fetch the client manifest of ~a (because ~a)") + (uri->string (get 'id)) (recurse (get 'cause)))) ((&compound-exception) (let ((components (get 'components))) (if (null? components) diff --git a/tests/Makefile.am b/tests/Makefile.am index 37a4a82..8ccfa68 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -23,7 +23,10 @@ TESTS = %reldir%/load-library.scm \ %reldir%/dpop-proof-iat-in-future.scm \ %reldir%/dpop-proof-iat-too-late.scm \ %reldir%/dpop-proof-wrong-key.scm \ - %reldir%/dpop-proof-replay.scm + %reldir%/dpop-proof-replay.scm \ + %reldir%/client-manifest-public.scm \ + %reldir%/client-manifest.scm \ + %reldir%/client-manifest-fraudulent.scm EXTRA_DIST += $(TESTS) diff --git a/tests/client-manifest-fraudulent.scm b/tests/client-manifest-fraudulent.scm new file mode 100644 index 0000000..c12643e --- /dev/null +++ b/tests/client-manifest-fraudulent.scm @@ -0,0 +1,66 @@ +(use-modules (webid-oidc client-manifest) + (webid-oidc cache) + (webid-oidc testing) + (webid-oidc errors) + (web uri) + (srfi srfi-19) + (web response) + (ice-9 optargs) + (ice-9 receive)) + +;; In this example, the client_id of the oidcRegistration does not +;; match the base URI. + +(with-test-environment + "client-manifest-fraudulent" + (lambda () + (define the-current-time 0) + (define (current-time) + (make-time time-utc 0 the-current-time)) + (define what-to-respond + (build-response #:headers '((content-type text/turtle)))) + (define what-to-respond-body + "@prefix solid: . + +<#app> solid:oidcRegistration \"\"\"{ + \"client_id\" : \"https://app.example.com/id#app\", + \"redirect_uris\" : [\"https://app.example.com/callback\"], + \"client_name\" : \"Solid Application Name\", + \"client_uri\" : \"https://app.example.com/\", + \"logo_uri\" : \"https://app.example.com/logo.png\", + \"tos_uri\" : \"https://app.example.com/tos.html\", + \"scope\" : \"openid profile offline_access\", + \"grant_types\" : [\"refresh_token\",\"authorization_code\"], + \"response_types\" : [\"code\"], + \"default_max_age\" : 60000, + \"require_auth_time\" : true + }\"\"\" . +") + (define headers-to-expect + '((accept (text/turtle)))) + (define uri-to-expect + (string->uri "https://fraudulent-app.example.com/id#app")) + (define* (respond uri #:key (headers '())) + (when (string? uri) + (set! uri (string->uri uri))) + (unless (equal? uri uri-to-expect) + (exit 1)) + (unless (equal? headers headers-to-expect) + (exit 2)) + (values what-to-respond what-to-respond-body)) + (define cache-http-get + (with-cache + #:current-time current-time + #:http-get respond)) + (with-exception-handler + (lambda (error) + (unless ((record-predicate &inconsistent-client-manifest-id) + ((record-accessor &cannot-fetch-client-manifest 'cause) error)) + (exit 3))) + (lambda () + (get-client-manifest + (string->uri "https://fraudulent-app.example.com/id#app") + #:http-get cache-http-get) + (exit 4)) + #:unwind? #t + #:unwind-for-type &cannot-fetch-client-manifest))) diff --git a/tests/client-manifest-public.scm b/tests/client-manifest-public.scm new file mode 100644 index 0000000..e285782 --- /dev/null +++ b/tests/client-manifest-public.scm @@ -0,0 +1,33 @@ +(use-modules (webid-oidc client-manifest) + (webid-oidc testing) + (webid-oidc errors) + (web uri) + (srfi srfi-19) + (web response)) + +(with-test-environment + "client-manifest-public" + (lambda () + (define mf + (get-client-manifest + (string->uri "http://www.w3.org/ns/solid/terms#PublicOidcClient") + #:http-get + (lambda args + (exit 1)))) + (define id (client-manifest-client-id mf)) + (unless (equal? id (string->uri "http://www.w3.org/ns/solid/terms#PublicOidcClient")) + (exit 2)) + (unless (client-manifest-check-redirect-uri mf "https://example.com") + (exit 3)) + (with-exception-handler + (lambda (error) + (unless ((record-predicate &cannot-serve-public-manifest) error) + (exit 4))) + (lambda () + (serve-client-manifest + (time-utc->date + (make-time time-utc 0 0)) + mf) + (exit 5)) + #:unwind? #t + #:unwind-for-type &cannot-serve-public-manifest))) diff --git a/tests/client-manifest.scm b/tests/client-manifest.scm new file mode 100644 index 0000000..cee586c --- /dev/null +++ b/tests/client-manifest.scm @@ -0,0 +1,85 @@ +(use-modules (webid-oidc client-manifest) + (webid-oidc cache) + (webid-oidc testing) + (webid-oidc errors) + (web uri) + (srfi srfi-19) + (web response) + (ice-9 optargs) + (ice-9 receive)) + +(with-test-environment + "client-manifest" + (lambda () + (define what-to-respond + (build-response #:headers '((content-type text/turtle)))) + (define what-to-respond-body + "@prefix solid: . + +<#app> solid:oidcRegistration \"\"\"{ + \"client_id\" : \"https://app.example.com/id#app\", + \"redirect_uris\" : [\"https://app.example.com/callback\"], + \"client_name\" : \"Solid Application Name\", + \"client_uri\" : \"https://app.example.com/\", + \"logo_uri\" : \"https://app.example.com/logo.png\", + \"tos_uri\" : \"https://app.example.com/tos.html\", + \"scope\" : \"openid profile offline_access\", + \"grant_types\" : [\"refresh_token\",\"authorization_code\"], + \"response_types\" : [\"code\"], + \"default_max_age\" : 60000, + \"require_auth_time\" : true + }\"\"\" . +") + (define* (respond uri #:key (headers '())) + (unless (equal? headers '((accept (text/turtle)))) + (exit 1)) + (when (string? uri) + (set! uri (string->uri uri))) + (unless (equal? uri + (string->uri "https://app.example.com/id#app")) + (exit 2)) + (values what-to-respond what-to-respond-body)) + (define current-time 0) + (define cache-http-get + (with-cache + #:current-time + (lambda () + (make-time time-utc 0 current-time)) + #:http-get respond)) + (define mf + (get-client-manifest + (string->uri "https://app.example.com/id#app") + #:http-get cache-http-get)) + (define id (client-manifest-client-id mf)) + (unless (equal? id (string->uri "https://app.example.com/id#app")) + (exit 3)) + (unless (client-manifest-check-redirect-uri mf "https://app.example.com/callback") + (exit 4)) + (with-exception-handler + (lambda (error) + (unless ((record-predicate &unauthorized-redirection-uri) error) + (exit 5))) + (lambda () + (client-manifest-check-redirect-uri mf "https://fraudulent-app.example.com/callback") + (exit 55)) + #:unwind? #t + #:unwind-for-type &unauthorized-redirection-uri) + (receive (response response-body) + (serve-client-manifest + (time-utc->date (make-time time-utc 0 3600)) + mf) + (unless (equal? (response-content-type response) '(text/turtle)) + (exit 6)) + (set! what-to-respond response) + (set! what-to-respond-body response-body) + (set! current-time 10) + (let ((re-parsed (get-client-manifest + (string->uri "https://app.example.com/id#app") + #:http-get cache-http-get))) + (map (lambda (key) + (unless (equal? (assq-ref mf key) + (assq-ref re-parsed key)) + (exit 9))) + '(client_id redirect_uris client_name client_uri + logo_uri tos_uri scope grant_types response_types + default_max_age require_auth_time)))))) -- cgit v1.2.3