summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2020-11-30 23:13:17 +0100
committerVivien Kraus <vivien@planete-kraus.eu>2021-06-05 16:14:50 +0200
commit38af62890b5a2604be21b7ffa0355e2bc39256b0 (patch)
treeb7e81e70fdef5de5611ec0b86991eca4f5e3fde0
parentfd8608644cda11b6cd48d313dc89ad0135240e19 (diff)
Fetch a client manifest on the web
-rw-r--r--doc/webid-oidc.texi36
-rw-r--r--po/fr.po240
-rw-r--r--po/webid-oidc.pot210
-rw-r--r--src/scm/webid-oidc/Makefile.am6
-rw-r--r--src/scm/webid-oidc/client-manifest.scm126
-rw-r--r--src/scm/webid-oidc/errors.scm92
-rw-r--r--tests/Makefile.am5
-rw-r--r--tests/client-manifest-fraudulent.scm66
-rw-r--r--tests/client-manifest-public.scm33
-rw-r--r--tests/client-manifest.scm85
10 files changed, 694 insertions, 205 deletions
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} &not-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."
@@ -556,13 +594,6 @@ msgstr "Type d’exception non pris en charge ~a."
#~ 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"
@@ -570,29 +601,6 @@ msgstr "Type d’exception non pris en charge ~a."
#~ 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: <http://www.w3.org/ns/solid/terms#> .
+
+<" 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 &not-a-client-manifest
+ (make-exception-type
+ '&not-a-client-manifest
+ &external-error
+ '(value cause)))
+
+(define-public (raise-not-a-client-manifest value cause)
+ (raise-exception
+ ((record-constructor &not-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))))
+ ((&not-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 2eb0db6..bce5c10 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: <http://www.w3.org/ns/solid/terms#> .
+
+<#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: <http://www.w3.org/ns/solid/terms#> .
+
+<#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))))))