summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVivien Kraus <vivien@planete-kraus.eu>2021-10-14 11:36:14 +0200
committerVivien Kraus <vivien@planete-kraus.eu>2021-10-20 18:04:30 +0200
commit34624c72245b483e645efd281a27c9c9e210a19a (patch)
treeafca30257d8a7c842bd80a4121c69be201c5fdca
parent326f056867bab68ae94408a31af6f4c666dfb191 (diff)
server: add an identity provider endpoint
-rw-r--r--doc/disfluid.texi104
-rw-r--r--po/POTFILES.in3
-rw-r--r--po/disfluid.pot305
-rw-r--r--po/fr.po432
-rw-r--r--src/scm/webid-oidc/Makefile.am4
-rw-r--r--src/scm/webid-oidc/authorization-endpoint.scm135
-rw-r--r--src/scm/webid-oidc/authorization-page-unsafe.scm137
-rw-r--r--src/scm/webid-oidc/authorization-page.scm56
-rw-r--r--src/scm/webid-oidc/identity-provider.scm150
-rw-r--r--src/scm/webid-oidc/oidc-configuration.scm2
-rw-r--r--src/scm/webid-oidc/server/endpoint/Makefile.am7
-rw-r--r--src/scm/webid-oidc/server/endpoint/identity-provider.scm590
-rw-r--r--src/scm/webid-oidc/token-endpoint.scm301
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/authorization-endpoint-get-form.scm3
-rw-r--r--tests/authorization-endpoint-no-args.scm3
-rw-r--r--tests/authorization-endpoint-submit-form.scm9
-rw-r--r--tests/token-endpoint-issue.scm9
-rw-r--r--tests/token-endpoint-refresh.scm15
19 files changed, 1325 insertions, 942 deletions
diff --git a/doc/disfluid.texi b/doc/disfluid.texi
index 16cb1e3..d85afd8 100644
--- a/doc/disfluid.texi
+++ b/doc/disfluid.texi
@@ -1550,6 +1550,7 @@ the user.
* Hello world::
* Reverse proxy::
* Client pages::
+* Identity provider::
@end menu
@node Error signalling
@@ -1741,6 +1742,109 @@ This endpoint receives an authorization code, and display it to the
user, asking to paste it in the application.
@end deftp
+@node Identity provider
+@section Identity provider
+The @emph{(webid-oidc server endpoint identity-provider)} module
+defines endpoints that are required for an identity provider.
+
+@deftp {Class} <oidc-discovery> (<endpoint>) @var{configuration}
+Serve the OIDC @var{configuration}.
+
+You can construct it with @code{#:@var{configuration}}.
+@end deftp
+
+@deffn {Generic} configuration @var{endpoint}
+Return the OIDC configuration served by @var{endpoint}.
+@end deffn
+
+@deftp {Class} <authorization-endpoint> (<endpoint>) @var{subject} @var{encrypted-password} @var{key-file}
+The authorization endpoint prompts the user for a password, and then
+grants an authorization code. It is defined for one particular user,
+whose webid is @var{subject}, and who knows the password. The
+authorization endpoint signs authorization codes with the key under
+@var{key-file}. If this file does not exist, a new key will be
+generated.
+
+The constructor expects keyword arguments @code{#:@var{subject}},
+@code{#:@var{encrypted-password}} and @code{#:@var{key-file}}.
+@end deftp
+
+@deffn {Generic} subject @var{authorization-endpoint}
+Return the webid of the user authorized by
+@var{authorization-endpoint}.
+@end deffn
+
+@deffn {Generic} encrypted-password @var{authorization-endpoint}
+Return the encrypted password used to authentify the user at
+@var{authorization-endpoint}.
+@end deffn
+
+@deffn {Generic} key-file @var{authorization-endpoint}
+Return the file name where the key to sign authorization codes in
+@var{authorization-endpoint} is stored.
+@end deffn
+
+@deftp {Class} <token-endpoint> (<endpoint>) @var{issuer} @var{key-file}
+The token endpoint exchanges authorization codes or refresh tokens for
+new access tokens. The access token is signed with the key loaded from
+@var{key-file}, and the access token is bound to the @var{issuer} URI
+(host name).
+
+You can construct a token endpoint with the @code{#:@var{issuer}} and
+@code{#:@var{key-file}} keyword arguments.
+@end deftp
+
+@deffn {Generic} issuer @var{token-endpoint}
+Return the issuer (URI with no path) that this @var{token-endpoint}
+operates for.
+@end deffn
+
+@deffn {Generic} key-file @var{token-endpoint}
+Return the file name where the key to sign access tokens in
+@var{token-endpoint} is stored.
+@end deffn
+
+@deftp {Class} <jwks-endpoint> (<endpoint>) @var{key-file}
+The JWKS endpoint returns the list of valid public keys used by the
+identity provider. For now, only the public part of the key under
+@var{key-file} is served.
+
+You can construct one with the @code{#:@var{key-file}} header
+argument.
+@end deftp
+
+@deftp {Class} <identity-provider> (<router>) @var{oidc-discovery} @var{authorization-endpoint} @var{token-endpoint} @var{jwks-endpoint} @var{default}
+An identity provider is the sum of an @var{OIDC discovery} endpoint,
+an @var{authorization-endpoint}, an @var{token-endpoint} and an
+@var{jwks-endpoint}, and a @var{default} endpoint that gets all the
+requests that aren’t handled by the identity provider.
+
+You can construct one with the following keyword arguments:
+@code{#:@var{authorization-endpoint}}, @code{#:@var{token-endpoint}},
+@code{#:@var{jwks-endpoint}} and @code{#:@var{default}}.
+@end deftp
+
+@deffn {Generic} oidc-discovery @var{identity-provider}
+Return the OIDC discovery endpoint of the @var{identity-provider}.
+@end deffn
+
+@deffn {Generic} authorization-endpoint @var{identity-provider}
+Return the authorization endpoint of the @var{identity-provider}.
+@end deffn
+
+@deffn {Generic} token-endpoint @var{identity-provider}
+Return the token endpoint of the @var{identity-provider}.
+@end deffn
+
+@deffn {Generic} jwks-endpoint @var{identity-provider}
+Return the JWKS endpoint of the @var{identity-provider}.
+@end deffn
+
+@deffn {Generic} default @var{identity-provider}
+Return the endpoint where all requests that aren’t handled by any
+element of the @var{identity-provider} go.
+@end deffn
+
@node Running an Identity Provider
@chapter Running an Identity Provider
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3666403..0308b21 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -28,8 +28,6 @@ src/scm/webid-oidc/Makefile.am
src/scm/webid-oidc/access-token.scm
src/scm/webid-oidc/authorization-code.scm
src/scm/webid-oidc/authorization-endpoint.scm
-src/scm/webid-oidc/authorization-page-unsafe.scm
-src/scm/webid-oidc/authorization-page.scm
src/scm/webid-oidc/cache.scm
src/scm/webid-oidc/catalog.scm
src/scm/webid-oidc/client-manifest.scm
@@ -82,6 +80,7 @@ src/scm/webid-oidc/server/endpoint.scm
src/scm/webid-oidc/server/endpoint/authentication.scm
src/scm/webid-oidc/server/endpoint/client.scm
src/scm/webid-oidc/server/endpoint/hello.scm
+src/scm/webid-oidc/server/endpoint/identity-provider.scm
src/scm/webid-oidc/server/endpoint/reverse-proxy.scm
src/scm/webid-oidc/server/log.scm
src/scm/webid-oidc/server/precondition.scm
diff --git a/po/disfluid.pot b/po/disfluid.pot
index 030c1b2..7bdc5f6 100644
--- a/po/disfluid.pot
+++ b/po/disfluid.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: disfluid SNAPSHOT\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-10-19 11:31+0200\n"
+"POT-Creation-Date: 2021-10-20 18:03+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -276,88 +276,27 @@ msgid ""
"client-id) or (#:jwt-header and #:jwt-payload) should be passed"
msgstr ""
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:52
+#: src/scm/webid-oidc/authorization-endpoint.scm:70
#: src/scm/webid-oidc/client.scm:193 src/scm/webid-oidc/hello-world.scm:147
-#: src/scm/webid-oidc/identity-provider.scm:136
+#: src/scm/webid-oidc/identity-provider.scm:120
#: src/scm/webid-oidc/server/endpoint/client.scm:153
#: src/scm/webid-oidc/server/endpoint/hello.scm:63
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:389
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:403
#: src/scm/webid-oidc/server/endpoint/reverse-proxy.scm:125
-#: src/scm/webid-oidc/token-endpoint.scm:113
-#: src/scm/webid-oidc/token-endpoint.scm:139
-#: src/scm/webid-oidc/token-endpoint.scm:166
+#: src/scm/webid-oidc/token-endpoint.scm:68
msgid "xml-lang|en"
msgstr ""
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:67
-#: src/scm/webid-oidc/server/endpoint/client.scm:155
-msgid "page-title|Authorization"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:72
-msgid "Authorize this anonymous application?"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:73
-#, scheme-format
-msgid "Authorize <a href=~s>~a</a>?"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:75
-msgid "Do you want to authorize this application to represent you?"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:85
-msgid "Please retry your password:"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:86
-msgid "Please enter your password:"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:91
-msgid "Allow"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:95
-#: src/scm/webid-oidc/token-endpoint.scm:131
-#: src/scm/webid-oidc/token-endpoint.scm:158
-msgid "reason-phrase|Bad Request"
+#: src/scm/webid-oidc/authorization-endpoint.scm:73
+msgid "<h1>The authorization request failed</h1>"
msgstr ""
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:97
-msgid "Bad request"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:102
-msgid "The application did not set the <emph>client_id</emph> parameter."
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:107
-msgid "The application did not set the <emph>redirect_uri</emph> parameter."
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:112
-msgid "Sorry, no more information is available."
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:117
-msgid "The application you are trying to authorize behaved unexpectedly."
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:126
-#: src/scm/webid-oidc/resource-server.scm:283
-msgid "reason-phrase|Found"
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:130
-msgid "Redirecting..."
-msgstr ""
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:135
-#, scheme-format
-msgid ""
-"<p><a href=~s>~a</a> can now log in on your behalf. You still need to adjust "
-"permissions.</p>"
+#: src/scm/webid-oidc/authorization-endpoint.scm:78
+#: src/scm/webid-oidc/client.scm:201 src/scm/webid-oidc/hello-world.scm:155
+#: src/scm/webid-oidc/identity-provider.scm:128
+#: src/scm/webid-oidc/token-endpoint.scm:76
+msgid "<p>No more information.</p>"
msgstr ""
#: src/scm/webid-oidc/cache.scm:94
@@ -475,10 +414,6 @@ msgstr ""
msgid "<h1>The request failed</h1>"
msgstr ""
-#: src/scm/webid-oidc/client.scm:201 src/scm/webid-oidc/hello-world.scm:155
-msgid "<p>No more information.</p>"
-msgstr ""
-
#: src/scm/webid-oidc/client/accounts.scm:118
#, scheme-format
msgid "an authorization code is required: ~s, it can be obtained at ~s"
@@ -1063,12 +998,16 @@ msgstr ""
msgid "the #:attribute-value parameter should be a string or URI"
msgstr ""
-#: src/scm/webid-oidc/identity-provider.scm:74
-msgid "Warning: generating a new key pair."
+#: src/scm/webid-oidc/identity-provider.scm:61
+msgid "reason-phrase|Not Found"
msgstr ""
-#: src/scm/webid-oidc/identity-provider.scm:129
-msgid "reason-phrase|Not Found"
+#: src/scm/webid-oidc/identity-provider.scm:64
+msgid "<p>Your request cannot be handled by the identity provider.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/identity-provider.scm:123
+msgid "<h1>The identity provider request failed</h1>"
msgstr ""
#: src/scm/webid-oidc/jti.scm:59
@@ -2089,17 +2028,26 @@ msgstr ""
msgid "~a: ignoring a group that cannot be fetched\n"
msgstr ""
+#: src/scm/webid-oidc/resource-server.scm:283
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:369
+msgid "reason-phrase|Found"
+msgstr ""
+
#: src/scm/webid-oidc/resource-server.scm:300
-#: src/scm/webid-oidc/token-endpoint.scm:105
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:528
msgid "reason-phrase|Forbidden"
msgstr ""
#: src/scm/webid-oidc/resource-server.scm:304
#: src/scm/webid-oidc/server/endpoint/hello.scm:54
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:332
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:459
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:468
msgid "reason-phrase|Unauthorized"
msgstr ""
#: src/scm/webid-oidc/resource-server.scm:312
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:439
msgid "reason-phrase|Method Not Allowed"
msgstr ""
@@ -2108,6 +2056,7 @@ msgid "reason-phrase|Conflict"
msgstr ""
#: src/scm/webid-oidc/resource-server.scm:328
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:418
msgid "reason-phrase|Unsupported Media Type"
msgstr ""
@@ -2223,6 +2172,10 @@ msgstr ""
msgid "#:~a should be a list"
msgstr ""
+#: src/scm/webid-oidc/server/endpoint/client.scm:155
+msgid "page-title|Authorization"
+msgstr ""
+
#: src/scm/webid-oidc/server/endpoint/client.scm:157
msgid ""
"You have been authorized. Please paste the following code in the application:"
@@ -2251,6 +2204,146 @@ msgstr ""
msgid "<p>You are authenticated with Solid.</p>"
msgstr ""
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:108
+msgid "Warning: generating a new key pair.\n"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:136
+msgid "#:path must be exactly \"/.well-known/openid-configuration\""
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:144
+msgid "#:configuration must be an OIDC configuration"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:161
+msgid "#:subject should be an URI"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:166
+msgid "#:encrypted-password should be a string"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:171
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:196
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:207
+msgid "#:key-file should be a string"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:191
+msgid "#:subject should be an URI without a path, query or fragment"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:303
+#, scheme-format
+msgid "<h2>Do you wish to authorize <a href=~s>~a</a>?</h2>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:307
+msgid "If you wish to do so, please type your password:"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:313
+msgid "Allow"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:318
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:324
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:344
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:358
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:428
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:482
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:495
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:504
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:539
+msgid "reason-phrase|Bad Request"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:320
+msgid "The client_id query argument is not set."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:326
+msgid "The redirect_uri query argument is not set."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:334
+msgid "The password is incorrect."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:347
+#, scheme-format
+msgid "<p>The client, <a href=~s>~a</a>, cannot be queried.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:361
+#, scheme-format
+msgid ""
+"<p>The real client at <a href=~s>~a</a> does not control the advertised "
+"redirection URI.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:391
+msgid "Redirecting..."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:393
+msgid "You are being redirected."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:405
+msgid "Authorization..."
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:421
+msgid "<p>Please use <pre>application/x-www-form-urlencoded</pre>.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:431
+msgid "<p>Expected an UTF-8 request body.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:442
+msgid "<p>This is a token endpoint, please use <pre>POST</pre>.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:462
+msgid "<p>No DPoP proof has been found in your request.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:471
+msgid "<p>The DPoP proof is invalid.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:485
+msgid "<p>The <pre>grant_type</pre> parameter has not been found.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:498
+msgid "<p>Could not find an authorization code.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:507
+msgid "<p>The authorization code is invalid.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:519
+msgid "reason-phrase|Bad Requeset"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:522
+msgid "<p>Could not find a refresh token.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:531
+msgid "<p>The refresh token is invalid or has been revoked.</p>"
+msgstr ""
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:542
+#, scheme-format
+msgid "<p>Cannot process your grant type, ~a.</p>"
+msgstr ""
+
#: src/scm/webid-oidc/server/endpoint/reverse-proxy.scm:77
msgid "#:backend-uri should be an URI"
msgstr ""
@@ -2334,50 +2427,8 @@ msgstr ""
msgid "an error happened while updating file ~s"
msgstr ""
-#: src/scm/webid-oidc/token-endpoint.scm:93
-#, scheme-format
-msgid "while handling web failure for the token endpoint: ~a"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:95
-msgid "an error happened during the token endpoint failure handling"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:225
-msgid "missing grant type"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:229
-msgid "<p>You did not specify a grant_type for this request.</p>"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:243
-msgid "missing authorization code"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:247
-msgid ""
-"<p>You want to grant an authorization code, but you did not set one.</p>"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:268
-msgid "missing refresh token"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:272
-msgid "<p>You want to grant a refresh token, but you did not set one.</p>"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:285
-#, scheme-format
-msgid "unsupported grant type: ~s"
-msgstr ""
-
-#: src/scm/webid-oidc/token-endpoint.scm:290
-#, scheme-format
-msgid ""
-"<p>You want to use <pre>~s</pre> as a grant type, but this is not supported."
-"</p>"
+#: src/scm/webid-oidc/token-endpoint.scm:71
+msgid "<h1>The token request failed</h1>"
msgstr ""
#: src/ui/account-widget.glade:19
diff --git a/po/fr.po b/po/fr.po
index bbb4d5e..cc81b02 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: webid-oidc 0.0.0\n"
"Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n"
-"POT-Creation-Date: 2021-10-19 11:31+0200\n"
-"PO-Revision-Date: 2021-10-19 11:35+0200\n"
+"POT-Creation-Date: 2021-10-20 18:03+0200\n"
+"PO-Revision-Date: 2021-10-19 11:36+0200\n"
"Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n"
"Language-Team: French <vivien@planete-kraus.eu>\n"
"Language: fr\n"
@@ -307,92 +307,28 @@ msgstr ""
"lors de la création d’un code d’autorisation, il faut soit passer les champs "
"requis (#:webid et #:client-id), soit (#:jwt-header et #:jwt-payload)"
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:52
+#: src/scm/webid-oidc/authorization-endpoint.scm:70
#: src/scm/webid-oidc/client.scm:193 src/scm/webid-oidc/hello-world.scm:147
-#: src/scm/webid-oidc/identity-provider.scm:136
+#: src/scm/webid-oidc/identity-provider.scm:120
#: src/scm/webid-oidc/server/endpoint/client.scm:153
#: src/scm/webid-oidc/server/endpoint/hello.scm:63
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:389
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:403
#: src/scm/webid-oidc/server/endpoint/reverse-proxy.scm:125
-#: src/scm/webid-oidc/token-endpoint.scm:113
-#: src/scm/webid-oidc/token-endpoint.scm:139
-#: src/scm/webid-oidc/token-endpoint.scm:166
+#: src/scm/webid-oidc/token-endpoint.scm:68
msgid "xml-lang|en"
msgstr "fr"
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:67
-#: src/scm/webid-oidc/server/endpoint/client.scm:155
-msgid "page-title|Authorization"
-msgstr "Autorisation"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:72
-msgid "Authorize this anonymous application?"
-msgstr "Autoriser cette application anonyme ?"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:73
-#, scheme-format
-msgid "Authorize <a href=~s>~a</a>?"
-msgstr "Autoriser <a href=~s>~a</a> ?"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:75
-msgid "Do you want to authorize this application to represent you?"
-msgstr "Voulez-vous autoriser cette application à vous représenter ?"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:85
-msgid "Please retry your password:"
-msgstr "Veuillez réessayer votre mot de passe :"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:86
-msgid "Please enter your password:"
-msgstr "Veuillez entrer votre mot de passe :"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:91
-msgid "Allow"
-msgstr "Autoriser"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:95
-#: src/scm/webid-oidc/token-endpoint.scm:131
-#: src/scm/webid-oidc/token-endpoint.scm:158
-msgid "reason-phrase|Bad Request"
-msgstr "Requête Invalide"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:97
-msgid "Bad request"
-msgstr "Requête invalide"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:102
-msgid "The application did not set the <emph>client_id</emph> parameter."
-msgstr "L'application n'a pas spécifié le paramètre <emph>client_id</emph>."
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:107
-msgid "The application did not set the <emph>redirect_uri</emph> parameter."
-msgstr "L'application n'a pas spécifié le paramètre <emph>redirect_uri</emph>."
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:112
-msgid "Sorry, no more information is available."
-msgstr "Veuillez nous excuser, il n’y a pas plus d’information disponible."
+#: src/scm/webid-oidc/authorization-endpoint.scm:73
+msgid "<h1>The authorization request failed</h1>"
+msgstr "<h1>La requête d’autorisation a échoué</h1>"
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:117
-msgid "The application you are trying to authorize behaved unexpectedly."
-msgstr ""
-"L’application que vous essayez d’autoriser se comporte de façon inattendue."
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:126
-#: src/scm/webid-oidc/resource-server.scm:283
-msgid "reason-phrase|Found"
-msgstr "Trouvé"
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:130
-msgid "Redirecting..."
-msgstr "Redirection..."
-
-#: src/scm/webid-oidc/authorization-page-unsafe.scm:135
-#, scheme-format
-msgid ""
-"<p><a href=~s>~a</a> can now log in on your behalf. You still need to adjust "
-"permissions.</p>"
-msgstr ""
-"<p><a href=~s>~a</a> peut maintenant s'identifier en votre nom. Vous devez "
-"toujours ajuster ses permissions.</p>"
+#: src/scm/webid-oidc/authorization-endpoint.scm:78
+#: src/scm/webid-oidc/client.scm:201 src/scm/webid-oidc/hello-world.scm:155
+#: src/scm/webid-oidc/identity-provider.scm:128
+#: src/scm/webid-oidc/token-endpoint.scm:76
+msgid "<p>No more information.</p>"
+msgstr "<p>Pas plus d’information.</p>"
#: src/scm/webid-oidc/cache.scm:94
#, scheme-format
@@ -518,10 +454,6 @@ msgstr "fr-fr"
msgid "<h1>The request failed</h1>"
msgstr "<h1>La requête a échoué</h1>"
-#: src/scm/webid-oidc/client.scm:201 src/scm/webid-oidc/hello-world.scm:155
-msgid "<p>No more information.</p>"
-msgstr "<p>Pas plus d’information.</p>"
-
#: src/scm/webid-oidc/client/accounts.scm:118
#, scheme-format
msgid "an authorization code is required: ~s, it can be obtained at ~s"
@@ -1182,14 +1114,19 @@ msgid "the #:attribute-value parameter should be a string or URI"
msgstr ""
"le paramètre #:attribute-value doit être une chaîne de caractères ou une URI"
-#: src/scm/webid-oidc/identity-provider.scm:74
-msgid "Warning: generating a new key pair."
-msgstr "Attention : génération d'une nouvelle paire de clé."
-
-#: src/scm/webid-oidc/identity-provider.scm:129
+#: src/scm/webid-oidc/identity-provider.scm:61
msgid "reason-phrase|Not Found"
msgstr "Non Trouvé"
+#: src/scm/webid-oidc/identity-provider.scm:64
+msgid "<p>Your request cannot be handled by the identity provider.</p>"
+msgstr ""
+"<p>Votre requête n’a pas pu être traitée par le fournisseur d’identité.</p>"
+
+#: src/scm/webid-oidc/identity-provider.scm:123
+msgid "<h1>The identity provider request failed</h1>"
+msgstr "<h1>La requête du fournisseur d’identité a échoué</h1>"
+
#: src/scm/webid-oidc/jti.scm:59
#, scheme-format
msgid "a replay has been detected with JTI ~s"
@@ -2480,17 +2417,26 @@ msgstr "~a : j’ignore un groupe qui n’a pas pu être téléchargé : ~a\n"
msgid "~a: ignoring a group that cannot be fetched\n"
msgstr "~a : j’ignore un groupe qui ne peut pas être téléchargé\n"
+#: src/scm/webid-oidc/resource-server.scm:283
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:369
+msgid "reason-phrase|Found"
+msgstr "Trouvé"
+
#: src/scm/webid-oidc/resource-server.scm:300
-#: src/scm/webid-oidc/token-endpoint.scm:105
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:528
msgid "reason-phrase|Forbidden"
msgstr "Interdit"
#: src/scm/webid-oidc/resource-server.scm:304
#: src/scm/webid-oidc/server/endpoint/hello.scm:54
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:332
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:459
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:468
msgid "reason-phrase|Unauthorized"
msgstr "Non Autorisé"
#: src/scm/webid-oidc/resource-server.scm:312
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:439
msgid "reason-phrase|Method Not Allowed"
msgstr "Méthode Non Autorisée"
@@ -2499,6 +2445,7 @@ msgid "reason-phrase|Conflict"
msgstr "Conflit"
#: src/scm/webid-oidc/resource-server.scm:328
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:418
msgid "reason-phrase|Unsupported Media Type"
msgstr "Type de Média Non Supporté"
@@ -2619,6 +2566,10 @@ msgstr ""
msgid "#:~a should be a list"
msgstr "#:~a doit être une liste"
+#: src/scm/webid-oidc/server/endpoint/client.scm:155
+msgid "page-title|Authorization"
+msgstr "Autorisation"
+
#: src/scm/webid-oidc/server/endpoint/client.scm:157
msgid ""
"You have been authorized. Please paste the following code in the application:"
@@ -2651,6 +2602,149 @@ msgstr "<h1>Bonjour, ~a !</h1>"
msgid "<p>You are authenticated with Solid.</p>"
msgstr "<p>Vous êtes authentifié par Solid.</p>"
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:108
+msgid "Warning: generating a new key pair.\n"
+msgstr "Attention : génération d'une nouvelle paire de clé.\n"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:136
+msgid "#:path must be exactly \"/.well-known/openid-configuration\""
+msgstr "#:path doit être exactement « /.well-known/openid-configuration »"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:144
+msgid "#:configuration must be an OIDC configuration"
+msgstr "#:configuration doit être une configuration OIDC"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:161
+msgid "#:subject should be an URI"
+msgstr "#:subject doit être une URI"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:166
+msgid "#:encrypted-password should be a string"
+msgstr "#:encrypted-password doit être une chaîne de caractères"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:171
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:196
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:207
+msgid "#:key-file should be a string"
+msgstr "#:key-file doit être une chaîne de caractères"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:191
+msgid "#:subject should be an URI without a path, query or fragment"
+msgstr "#:subject doit être une URI sans chemin, requête ni fragment"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:303
+#, scheme-format
+msgid "<h2>Do you wish to authorize <a href=~s>~a</a>?</h2>"
+msgstr "<h2>Voulez-vous autoriser <a href=~s>~a</a> ?</h2>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:307
+msgid "If you wish to do so, please type your password:"
+msgstr "Si vous le voulez, entrez votre mot de passe :"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:313
+msgid "Allow"
+msgstr "Autoriser"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:318
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:324
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:344
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:358
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:428
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:482
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:495
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:504
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:539
+msgid "reason-phrase|Bad Request"
+msgstr "Requête Invalide"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:320
+msgid "The client_id query argument is not set."
+msgstr "Le paramètre de requête client_id n’est pas défini."
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:326
+msgid "The redirect_uri query argument is not set."
+msgstr "Le paramètre de requête redirect_uri n’est pas défini."
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:334
+msgid "The password is incorrect."
+msgstr "Le mot de passe est incorrect."
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:347
+#, scheme-format
+msgid "<p>The client, <a href=~s>~a</a>, cannot be queried.</p>"
+msgstr "<p>Le client, <a href=~s>~a</a>, n’a pas pu être requêté.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:361
+#, scheme-format
+msgid ""
+"<p>The real client at <a href=~s>~a</a> does not control the advertised "
+"redirection URI.</p>"
+msgstr ""
+"<p>Le véritable client <a href=~s>~a</a> ne contrôle pas l’URI de "
+"redirection publiée.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:391
+msgid "Redirecting..."
+msgstr "Redirection..."
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:393
+msgid "You are being redirected."
+msgstr "Vous êtes redirigé."
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:405
+msgid "Authorization..."
+msgstr "Autorisations…"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:421
+msgid "<p>Please use <pre>application/x-www-form-urlencoded</pre>.</p>"
+msgstr "<p>Veuillez utiliser <pre>application/x-www-form-urlencoded</pre>.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:431
+msgid "<p>Expected an UTF-8 request body.</p>"
+msgstr "<p>J’attends un corps de requête UTF-8.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:442
+msgid "<p>This is a token endpoint, please use <pre>POST</pre>.</p>"
+msgstr ""
+"<p>Ceci est un terminal de jeton, veuillez utiliser <pre>POST</pre>.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:462
+msgid "<p>No DPoP proof has been found in your request.</p>"
+msgstr "<p>Aucune preuve DPoP n’a été trouvée dans votre requête.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:471
+msgid "<p>The DPoP proof is invalid.</p>"
+msgstr "<p>La preuve DPoP est invalide.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:485
+msgid "<p>The <pre>grant_type</pre> parameter has not been found.</p>"
+msgstr "<p>Le paramètre <pre>grant_type</pre> n’a pas été trouvé.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:498
+msgid "<p>Could not find an authorization code.</p>"
+msgstr "<p>Je n’ai pas pu trouver de code d’autorisation.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:507
+msgid "<p>The authorization code is invalid.</p>"
+msgstr "<p>Le code d’autorisation est invalide.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:519
+msgid "reason-phrase|Bad Requeset"
+msgstr "Requête Invalide"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:522
+msgid "<p>Could not find a refresh token.</p>"
+msgstr "<p>Impossible de trouver un jeton de rafraîchissement.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:531
+msgid "<p>The refresh token is invalid or has been revoked.</p>"
+msgstr "<p>Le jeton de rafraîchissement est invalide ou a expiré.</p>"
+
+#: src/scm/webid-oidc/server/endpoint/identity-provider.scm:542
+#, scheme-format
+msgid "<p>Cannot process your grant type, ~a.</p>"
+msgstr "<p>Impossible de traiter votre type d’offre, ~a.</p>"
+
#: src/scm/webid-oidc/server/endpoint/reverse-proxy.scm:77
msgid "#:backend-uri should be an URI"
msgstr "#:backend-uri doit être une URI"
@@ -2734,58 +2828,9 @@ msgstr "pendant la mise à jour du fichier ~s : ~a"
msgid "an error happened while updating file ~s"
msgstr "une erreur est survenue pendant la mise à jour du fichier ~s"
-#: src/scm/webid-oidc/token-endpoint.scm:93
-#, scheme-format
-msgid "while handling web failure for the token endpoint: ~a"
-msgstr "lors de la gestion d’un échec web pour le terminal de jeton : ~a"
-
-#: src/scm/webid-oidc/token-endpoint.scm:95
-msgid "an error happened during the token endpoint failure handling"
-msgstr ""
-"une erreur est survenue pendant la gestion d’un échec du terminal de jeton"
-
-#: src/scm/webid-oidc/token-endpoint.scm:225
-msgid "missing grant type"
-msgstr "type d’offre manquant"
-
-#: src/scm/webid-oidc/token-endpoint.scm:229
-msgid "<p>You did not specify a grant_type for this request.</p>"
-msgstr "<p>Vous n’avez pas spécifié de grant_type pour cette requête.</p>"
-
-#: src/scm/webid-oidc/token-endpoint.scm:243
-msgid "missing authorization code"
-msgstr "code d’autorisation manquant"
-
-#: src/scm/webid-oidc/token-endpoint.scm:247
-msgid ""
-"<p>You want to grant an authorization code, but you did not set one.</p>"
-msgstr ""
-"<p>Vous voulez offrir un code d’autorisation, mais vous n’en avez pas défini."
-"</p>"
-
-#: src/scm/webid-oidc/token-endpoint.scm:268
-msgid "missing refresh token"
-msgstr "jeton de rafraîchissement manquant"
-
-#: src/scm/webid-oidc/token-endpoint.scm:272
-msgid "<p>You want to grant a refresh token, but you did not set one.</p>"
-msgstr ""
-"<p>Vous voulez offrir un jeton de rafraîchissement, mais vous n’en avez pas "
-"défini.</p>"
-
-#: src/scm/webid-oidc/token-endpoint.scm:285
-#, scheme-format
-msgid "unsupported grant type: ~s"
-msgstr "type d’offre non supporté : ~s"
-
-#: src/scm/webid-oidc/token-endpoint.scm:290
-#, scheme-format
-msgid ""
-"<p>You want to use <pre>~s</pre> as a grant type, but this is not supported."
-"</p>"
-msgstr ""
-"<p>Vous voulez utiliser <pre>~s</pre> comme type d’offre, mais ce n’est pas "
-"supporté.</p>"
+#: src/scm/webid-oidc/token-endpoint.scm:71
+msgid "<h1>The token request failed</h1>"
+msgstr "<h1>La requête de jeton a échoué</h1>"
#: src/ui/account-widget.glade:19
msgid "Identity:"
@@ -2919,6 +2964,91 @@ msgstr "Contenu :"
msgid "Discard edits"
msgstr "Rejeter les modifications"
+#~ msgid "Authorize this anonymous application?"
+#~ msgstr "Autoriser cette application anonyme ?"
+
+#~ msgid "Do you want to authorize this application to represent you?"
+#~ msgstr "Voulez-vous autoriser cette application à vous représenter ?"
+
+#~ msgid "Please enter your password:"
+#~ msgstr "Veuillez entrer votre mot de passe :"
+
+#~ msgid "Bad request"
+#~ msgstr "Requête invalide"
+
+#~ msgid "The application did not set the <emph>client_id</emph> parameter."
+#~ msgstr "L'application n'a pas spécifié le paramètre <emph>client_id</emph>."
+
+#~ msgid "The application did not set the <emph>redirect_uri</emph> parameter."
+#~ msgstr ""
+#~ "L'application n'a pas spécifié le paramètre <emph>redirect_uri</emph>."
+
+#~ msgid "Sorry, no more information is available."
+#~ msgstr "Veuillez nous excuser, il n’y a pas plus d’information disponible."
+
+#~ msgid "The application you are trying to authorize behaved unexpectedly."
+#~ msgstr ""
+#~ "L’application que vous essayez d’autoriser se comporte de façon "
+#~ "inattendue."
+
+#, scheme-format
+#~ msgid ""
+#~ "<p><a href=~s>~a</a> can now log in on your behalf. You still need to "
+#~ "adjust permissions.</p>"
+#~ msgstr ""
+#~ "<p><a href=~s>~a</a> peut maintenant s'identifier en votre nom. Vous "
+#~ "devez toujours ajuster ses permissions.</p>"
+
+#, scheme-format
+#~ msgid "while handling web failure for the token endpoint: ~a"
+#~ msgstr "lors de la gestion d’un échec web pour le terminal de jeton : ~a"
+
+#~ msgid "an error happened during the token endpoint failure handling"
+#~ msgstr ""
+#~ "une erreur est survenue pendant la gestion d’un échec du terminal de jeton"
+
+#~ msgid "missing grant type"
+#~ msgstr "type d’offre manquant"
+
+#~ msgid "<p>You did not specify a grant_type for this request.</p>"
+#~ msgstr "<p>Vous n’avez pas spécifié de grant_type pour cette requête.</p>"
+
+#~ msgid "missing authorization code"
+#~ msgstr "code d’autorisation manquant"
+
+#~ msgid ""
+#~ "<p>You want to grant an authorization code, but you did not set one.</p>"
+#~ msgstr ""
+#~ "<p>Vous voulez offrir un code d’autorisation, mais vous n’en avez pas "
+#~ "défini.</p>"
+
+#~ msgid "missing refresh token"
+#~ msgstr "jeton de rafraîchissement manquant"
+
+#~ msgid "<p>You want to grant a refresh token, but you did not set one.</p>"
+#~ msgstr ""
+#~ "<p>Vous voulez offrir un jeton de rafraîchissement, mais vous n’en avez "
+#~ "pas défini.</p>"
+
+#, scheme-format
+#~ msgid "unsupported grant type: ~s"
+#~ msgstr "type d’offre non supporté : ~s"
+
+#, scheme-format
+#~ msgid ""
+#~ "<p>You want to use <pre>~s</pre> as a grant type, but this is not "
+#~ "supported.</p>"
+#~ msgstr ""
+#~ "<p>Vous voulez utiliser <pre>~s</pre> comme type d’offre, mais ce n’est "
+#~ "pas supporté.</p>"
+
+#~ msgid "The client_id query argument cannot be parsed as an URI."
+#~ msgstr "L’argument client_id n’a pas pu être interprété comme URI."
+
+#~ msgid "The redirect_uri query argument cannot be parsed as an URI."
+#~ msgstr ""
+#~ "Le paramètre de requête redirect_uri n’a pas pu être interprété comme URI."
+
#~ msgid "#:client-name should be a string"
#~ msgstr "#:client-name doit être une chaîne de caractères"
@@ -3170,9 +3300,6 @@ msgstr "Rejeter les modifications"
#~ msgid "the authorization code is invalid: ~a"
#~ msgstr "le code d’autorisation est invalide : ~a"
-#~ msgid "the authorization code is invalid"
-#~ msgstr "le code d’autorisation est invalide"
-
#, scheme-format
#~ msgid "the authorization expired ~a, which is in the past (from ~a)"
#~ msgstr ""
@@ -3194,10 +3321,6 @@ msgstr "Rejeter les modifications"
#~ msgstr "ce n’est pas une preuve DPoP, parce que ce n’est même pas un JWS"
#, scheme-format
-#~ msgid "the DPoP proof is missing ~s"
-#~ msgstr "il manque ~s à la preuve DPoP"
-
-#, scheme-format
#~ msgid "the \"htm\" field should be a string, not ~s"
#~ msgstr "le champ « htm » doit être une chaîne de caractères, pas ~s"
@@ -3480,10 +3603,6 @@ msgstr "Rejeter les modifications"
#~ msgid "the sub field is missing"
#~ msgstr "le champ sub est manquant"
-#, scheme-format
-#~ msgid "the iss field is incorrect: ~s"
-#~ msgstr "le champ iss est incorrect : ~s"
-
#~ msgid "the iss field is missing"
#~ msgstr "le champ iss est manquant"
@@ -3821,10 +3940,6 @@ msgstr "Rejeter les modifications"
#~ msgid "the header ~a should be present."
#~ msgstr "l’en-tête ~a devrait être présent."
-#, scheme-format
-#~ msgid "the client_id field is incorrect: ~s"
-#~ msgstr "le champ client_id est incorrect : ~s"
-
#~ msgid "the client_id field is missing"
#~ msgstr "le champ client_id est manquant"
@@ -3836,9 +3951,6 @@ msgstr "Rejeter les modifications"
#~ msgid "the client manifest at ~a is advertised for ~a;"
#~ msgstr "le manifeste client ~a est publié pour ~a ;"
-#~ msgid "I could not issue an authorization code for you;"
-#~ msgstr "je n’ai pas pu émettre un code d’autorisation pour vous ;"
-
#, scheme-format
#~ msgid "Warning: ~a\n"
#~ msgstr "Avertissement : ~a\n"
diff --git a/src/scm/webid-oidc/Makefile.am b/src/scm/webid-oidc/Makefile.am
index 92429f7..1d5066b 100644
--- a/src/scm/webid-oidc/Makefile.am
+++ b/src/scm/webid-oidc/Makefile.am
@@ -31,8 +31,6 @@ dist_webidoidcmod_DATA += \
%reldir%/authorization-code.scm \
%reldir%/refresh-token.scm \
%reldir%/oidc-id-token.scm \
- %reldir%/authorization-page.scm \
- %reldir%/authorization-page-unsafe.scm \
%reldir%/authorization-endpoint.scm \
%reldir%/token-endpoint.scm \
%reldir%/identity-provider.scm \
@@ -69,8 +67,6 @@ webidoidcgo_DATA += \
%reldir%/authorization-code.go \
%reldir%/refresh-token.go \
%reldir%/oidc-id-token.go \
- %reldir%/authorization-page.go \
- %reldir%/authorization-page-unsafe.go \
%reldir%/authorization-endpoint.go \
%reldir%/token-endpoint.go \
%reldir%/identity-provider.go \
diff --git a/src/scm/webid-oidc/authorization-endpoint.scm b/src/scm/webid-oidc/authorization-endpoint.scm
index cbf91cf..74417aa 100644
--- a/src/scm/webid-oidc/authorization-endpoint.scm
+++ b/src/scm/webid-oidc/authorization-endpoint.scm
@@ -16,10 +16,12 @@
(define-module (webid-oidc authorization-endpoint)
#:use-module (webid-oidc errors)
- #:use-module (webid-oidc authorization-page)
+ #:use-module (webid-oidc server endpoint)
+ #:use-module (webid-oidc server endpoint identity-provider)
#:use-module (webid-oidc jwk)
#:use-module (webid-oidc authorization-code)
#:use-module (webid-oidc client-manifest)
+ #:use-module (webid-oidc web-i18n)
#:use-module ((webid-oidc parameters) #:prefix p:)
#:use-module (web uri)
#:use-module (web request)
@@ -30,6 +32,7 @@
#:use-module (ice-9 receive)
#:use-module (ice-9 optargs)
#:use-module (ice-9 match)
+ #:use-module (sxml simple)
#:use-module (oop goops)
#:declarative? #t
#:duplicates (merge-generics)
@@ -40,97 +43,43 @@
))
-(define (verify-password encrypted-password password)
- (let ((c (crypt password encrypted-password)))
- (string=? c encrypted-password)))
-
-(define (make-authorization-endpoint subject encrypted-password jwk)
- (define (parse-arg x decode-plus-to-space?)
- (map (lambda (x) (uri-decode
- x
- #:decode-plus-to-space? decode-plus-to-space?))
- (string-split x #\=)))
- (lambda* (request request-body)
+(define (make-authorization-endpoint subject encrypted-password jwk-file)
+ (define endpoint
+ (make <authorization-endpoint>
+ #:subject subject
+ #:encrypted-password encrypted-password
+ #:key-file jwk-file))
+ (lambda (request request-body)
(when (bytevector? request-body)
(set! request-body (utf8->string request-body)))
- (let* ((uri (request-uri request))
- (method (request-method request))
- (query (uri-query uri))
- (query-parts (if query
- (string-split query #\&)
- '()))
- (get-args (map (cute parse-arg <> #f) query-parts))
- (form-args
- (match (request-content-type request)
- ((application/x-www-form-urlencoded . _)
- (map (cute parse-arg <> #t)
- (string-split request-body #\&)))
- (else '())))
- (accept-language
- (sort (request-accept-language request)
- (lambda (x y) (>= (car x) (car y)))))
- (locale
- (match accept-language
- (((_ . lng) _ ...) lng)
- (else "C"))))
- (let ((client-id
- (match (assoc-ref get-args "client_id")
- (((? string->uri client-id) . _)
- (string->uri client-id))
- (else #f)))
- (redirect-uri
- (match (assoc-ref get-args "redirect_uri")
- (((? string->uri redirect-uri) . _)
- (string->uri redirect-uri))
- (else #f)))
- (password
- (match (assoc-ref form-args "password")
- ((password . _)
- password)
- (else #f)))
- (state
- (match (assoc-ref get-args "state")
- ((state . _)
- state)
- (else #f))))
- (cond
- ((not client-id)
- (error-no-client-id locale))
- ((not redirect-uri)
- (error-no-redirect-uri locale))
- ((and (eq? method 'POST)
- (string? password)
- (verify-password encrypted-password password))
- (with-exception-handler
- (lambda (error)
- (error-application locale error))
- (lambda ()
- (let ((code (issue <authorization-code>
- jwk
- #:webid subject
- #:client-id client-id))
- (mf (make <client-manifest>
- #:client-id client-id)))
- (check-redirect-uri mf redirect-uri)
- (let ((query
- (if state
- (format #f "code=~a&state=~a"
- (uri-encode code)
- (uri-encode state))
- (format #f "code=~a"
- (uri-encode code)))))
- (let ((uri
- (build-uri 'https
- #:userinfo (uri-userinfo redirect-uri)
- #:host (uri-host redirect-uri)
- #:port (uri-port redirect-uri)
- #:path (uri-path redirect-uri)
- #:query query)))
- (redirection locale client-id uri)))))
- #:unwind? #t))
- (else
- (authorization-page locale
- (not (and password
- (verify-password encrypted-password password)))
- client-id
- uri)))))))
+ (parameterize ((web-locale request))
+ (with-exception-handler
+ (lambda (exn)
+ (unless (web-exception? exn)
+ (raise-exception exn))
+ (values
+ (build-response
+ #:code (web-exception-code exn)
+ #:reason-phrase (web-exception-reason-phrase exn)
+ #:headers `((content-type application/xhtml+xml)))
+ (call-with-output-string
+ (cute sxml->xml
+ `(*TOP*
+ (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
+ (html (@ (xmlns "http://www.w3.org/1999/xhtml")
+ (xml:lang ,(W_ "xml-lang|en")))
+ (body
+ ,(call-with-input-string
+ (format #f (W_ "<h1>The authorization request failed</h1>"))
+ xml->sxml)
+ ,(if (user-message? exn)
+ (user-message-sxml exn)
+ (call-with-input-string
+ (format #f (W_ "<p>No more information.</p>"))
+ xml->sxml)))))
+ <>))))
+ (lambda ()
+ (receive (response response-body response-meta)
+ (handle endpoint request request-body)
+ (values response response-body)))
+ #:unwind? #t))))
diff --git a/src/scm/webid-oidc/authorization-page-unsafe.scm b/src/scm/webid-oidc/authorization-page-unsafe.scm
deleted file mode 100644
index 640ad53..0000000
--- a/src/scm/webid-oidc/authorization-page-unsafe.scm
+++ /dev/null
@@ -1,137 +0,0 @@
-;; disfluid, implementation of the Solid specification
-;; Copyright (C) 2020, 2021 Vivien Kraus
-
-;; This program is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public License
-;; along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-(define-module (webid-oidc authorization-page-unsafe)
- #:use-module (webid-oidc errors)
- #:use-module (sxml simple)
- #:use-module (web uri)
- #:use-module (web response)
- #:use-module (webid-oidc web-i18n)
- #:use-module (ice-9 exceptions)
- #:use-module (ice-9 string-fun)
- #:use-module (ice-9 match)
- #:use-module (sxml simple)
- #:use-module (sxml match)
- #:declarative? #t
- #:export
- (
- authorization-page
- error-no-client-id
- error-no-redirect-uri
- error-application
- redirection
- ))
-
-(define (str->sxml str)
- (sxml-match
- (xml->sxml
- (string-append "<protect>" str "</protect>"))
- ((*TOP* (protect ,element ...))
- (list element ...))))
-
-(define (make-page title . body)
- (with-output-to-string
- (lambda ()
- (sxml->xml
- `(*TOP*
- (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
- (html (@ (xmlns "http://www.w3.org/1999/xhtml")
- (xml:lang ,(W_ "xml-lang|en")))
- (head
- (title ,title))
- (body
- ,@body)))))))
-
-(define (authorization-page credential-invalid?
- client-id post-uri)
- (when (uri? client-id)
- (set! client-id (uri->string client-id)))
- (when (string? post-uri)
- (set! post-uri (string->uri post-uri)))
- (values (build-response
- #:headers `((content-type application/xhtml+xml)))
- (make-page
- (W_ "page-title|Authorization")
- (if (equal?
- (string->uri client-id)
- (string->uri
- "http://www.w3.org/ns/solid/terms#PublicOidcClient"))
- `(h1 ,@(str->sxml (W_ "Authorize this anonymous application?")))
- `(h1 ,@(str->sxml (format #f (W_ "Authorize <a href=~s>~a</a>?")
- client-id client-id))))
- `(p ,@(str->sxml (W_ "Do you want to authorize this application to represent you?")))
- `(form (@ (action ,(uri->string post-uri))
- (method "POST"))
- (div
- (label (@ (for "password")
- ,@(if credential-invalid?
- '((class "authz-page-credential-error"))
- '()))
- ,@(str->sxml
- (if credential-invalid?
- (W_ "Please retry your password:")
- (W_ "Please enter your password:"))))
- (input (@ (type "password")
- (name "password")
- (id "password"))))
- (input (@ (type "submit")
- (value ,(W_ "Allow"))))))))
-
-(define (bad-request . body)
- (values (build-response #:code 400
- #:reason-phrase (W_ "reason-phrase|Bad Request")
- #:headers '((content-type application/xhtml+xml)))
- (apply make-page (W_ "Bad request") body)))
-
-(define (error-no-client-id)
- (bad-request
- `(p ,@(str->sxml
- (W_ "The application did not set the <emph>client_id</emph> parameter.")))))
-
-(define (error-no-redirect-uri)
- (bad-request
- `(p ,@(str->sxml
- (W_ "The application did not set the <emph>redirect_uri</emph> parameter.")))))
-
-(define (wrap-error err)
- (if (message-for-the-user? err)
- (user-message err)
- `(p (W_ "Sorry, no more information is available."))))
-
-(define (error-application error)
- (bad-request
- `(div
- (p ,(W_ "The application you are trying to authorize behaved unexpectedly."))
- ,@(sxml-match
- (wrap-error error)
- ((div ,element ...)
- `(,element ...))
- (,else `(,else))))))
-
-(define (redirection client-id uri)
- (values (build-response
- #:code 302 #:reason-phrase (W_ "reason-phrase|Found")
- #:headers `((location . ,uri)
- (content-type application/xhtml+xml)))
- (make-page
- (W_ "Redirecting...")
- `(h1 "Authorization granted, you are being redirected")
- `(p ,@(str->sxml
- (format
- #f
- (W_ "<p><a href=~s>~a</a> can now log in on your behalf. You still need to adjust permissions.</p>")
- (uri->string client-id)
- (uri->string client-id)))))))
diff --git a/src/scm/webid-oidc/authorization-page.scm b/src/scm/webid-oidc/authorization-page.scm
deleted file mode 100644
index 536137e..0000000
--- a/src/scm/webid-oidc/authorization-page.scm
+++ /dev/null
@@ -1,56 +0,0 @@
-;; disfluid, implementation of the Solid specification
-;; Copyright (C) 2020, 2021 Vivien Kraus
-
-;; This program is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU Affero General Public License as
-;; published by the Free Software Foundation, either version 3 of the
-;; License, or (at your option) any later version.
-
-;; This program is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU Affero General Public License for more details.
-
-;; You should have received a copy of the GNU Affero General Public License
-;; along with this program. If not, see <https://www.gnu.org/licenses/>.
-
-(define-module (webid-oidc authorization-page)
- #:use-module (webid-oidc errors)
- #:use-module ((webid-oidc web-i18n) #:prefix i18n:)
- #:use-module ((webid-oidc authorization-page-unsafe) #:prefix unsafe:)
- #:use-module (ice-9 string-fun)
- #:use-module (ice-9 receive)
- #:use-module (ice-9 threads)
- #:declarative? #t
- #:export
- (
-
- authorization-page
- error-no-client-id
- error-no-redirect-uri
- error-application
- redirection
-
- ))
-
-(define (authorization-page
- locale credential-invalid? client-id post-uri)
- (parameterize ((i18n:web-locale locale))
- (unsafe:authorization-page credential-invalid?
- client-id post-uri)))
-
-(define (error-no-client-id locale)
- (parameterize ((i18n:web-locale locale))
- (unsafe:error-no-client-id)))
-
-(define (error-no-redirect-uri locale)
- (parameterize ((i18n:web-locale locale))
- (unsafe:error-no-redirect-uri)))
-
-(define (error-application locale error)
- (parameterize ((i18n:web-locale locale))
- (unsafe:error-application error)))
-
-(define (redirection locale client-id uri)
- (parameterize ((i18n:web-locale locale))
- (unsafe:redirection client-id uri)))
diff --git a/src/scm/webid-oidc/identity-provider.scm b/src/scm/webid-oidc/identity-provider.scm
index de56228..5970574 100644
--- a/src/scm/webid-oidc/identity-provider.scm
+++ b/src/scm/webid-oidc/identity-provider.scm
@@ -18,6 +18,8 @@
#:use-module (webid-oidc errors)
#:use-module (webid-oidc authorization-endpoint)
#:use-module (webid-oidc token-endpoint)
+ #:use-module (webid-oidc server endpoint)
+ #:use-module (webid-oidc server endpoint identity-provider)
#:use-module (webid-oidc oidc-configuration)
#:use-module (webid-oidc jwk)
#:use-module ((webid-oidc config) #:prefix cfg:)
@@ -39,6 +41,7 @@
#:use-module (sxml simple)
#:use-module (sxml match)
#:use-module (srfi srfi-19)
+ #:use-module (srfi srfi-26)
#:use-module (rnrs bytevectors)
#:use-module (oop goops)
#:duplicates (merge-generics)
@@ -50,9 +53,16 @@
))
-(define* (same-uri? a b #:key (skip-query #f))
- (and (equal? (uri-path a) (uri-path b))
- (or skip-query (equal? (uri-query a) (uri-query b)))))
+(define-class <default> (<endpoint>))
+
+(define-method (handle (endpoint <default>) request request-body)
+ (raise-exception
+ (make-exception
+ (make-web-exception 404 (W_ "reason-phrase|Not Found"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Your request cannot be handled by the identity provider.</p>"))
+ xml->sxml)))))
(define* (make-identity-provider
issuer
@@ -62,84 +72,64 @@
jwks-uri
authorization-endpoint-uri
token-endpoint-uri)
- (let ((key
- (catch #t
- (lambda ()
- (call-with-input-file key-file
- (lambda (port)
- (jwk->key
- (stubs:json->scm port)))))
- (lambda error
- (format (current-error-port)
- (G_ "Warning: generating a new key pair."))
- (let ((k (generate-key #:n-size 2048)))
- (stubs:call-with-output-file*
- key-file
- (lambda (port)
- (stubs:scm->json (key->jwk k) port #:pretty #t)))
- k)))))
- (let ((authorization-endpoint
- (make-authorization-endpoint subject encrypted-password key))
- (token-endpoint
- (make-token-endpoint token-endpoint-uri issuer key))
- (openid-configuration
+ (let ((discovery
+ (make <oidc-discovery>
+ #:path "/.well-known/openid-configuration"
+ #:configuration
(make <oidc-configuration>
#:jwks-uri jwks-uri
#:authorization-endpoint authorization-endpoint-uri
- #:token-endpoint token-endpoint-uri))
- (openid-configuration-uri
- (build-uri 'https
- #:host (uri-host issuer)
- #:path "/.well-known/openid-configuration")))
+ #:token-endpoint token-endpoint-uri)))
+ (authz
+ (make <authorization-endpoint>
+ #:subject subject
+ #:encrypted-password encrypted-password
+ #:key-file key-file
+ #:path (uri-path authorization-endpoint-uri)))
+ (token
+ (make <token-endpoint>
+ #:path (uri-path token-endpoint-uri)
+ #:issuer issuer
+ #:key-file key-file))
+ (jwks
+ (make <jwks-endpoint>
+ #:path (uri-path jwks-uri)
+ #:key-file key-file)))
+ (let ((idp (make <identity-provider>
+ #:oidc-discovery discovery
+ #:authorization-endpoint authz
+ #:token-endpoint token
+ #:jwks-endpoint jwks
+ #:default (make <default>))))
(lambda (request request-body)
- (let ((uri (request-uri request))
- (current-time ((p:current-date))))
- (parameterize ((web-locale request))
- (cond ((same-uri? uri openid-configuration-uri)
- (let* ((current-sec (time-second (date->time-utc current-time)))
- (exp-sec (+ current-sec 3600))
- (exp (time-utc->date
- (make-time time-utc 0 exp-sec))))
- (serve openid-configuration exp)))
- ((same-uri? uri jwks-uri)
- (let* ((current-sec (time-second (date->time-utc current-time)))
- (exp-sec (+ current-sec 3600))
- (exp (time-utc->date
- (make-time time-utc 0 exp-sec))))
- (serve (make <jwks> #:keys (list key)) exp)))
- ((same-uri? uri authorization-endpoint-uri #:skip-query #t)
- (authorization-endpoint request request-body))
- ((same-uri? uri token-endpoint-uri)
- (token-endpoint request request-body))
- ((same-uri? uri subject)
- (values
- (build-response #:headers '((content-type text/turtle))
- #:port #f)
- (format #f
- "@prefix foaf: <http://xmlns.com/foaf/0.1/> .
-@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
-
-<#~a> a foaf:Person ;
- rdfs:comment \"It works. Now you should use another service to serve that resource.\" .
-"
- (uri-fragment subject))))
- (else
- (values
- (build-response #:code 404
- #:reason-phrase (W_ "reason-phrase|Not Found")
- #:headers '((content-type application/xhtml+xml)))
- (with-output-to-string
- (lambda ()
- (sxml->xml
- `(*TOP* (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
- (html (@ (xmlns "http://www.w3.org/1999/xhtml")
- (xml:lang ,(W_ "xml-lang|en")))
- (body
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<h1>Resource not found</h1>")))
- ((*TOP* ,title) title))
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<p>This OpenID Connect identity provider does not know the resource you are requesting.</p>")))
- ((*TOP* ,p) p)))))))))))))))))
+ (parameterize ((web-locale request))
+ (with-exception-handler
+ (lambda (exn)
+ (unless (web-exception? exn)
+ (raise-exception exn))
+ (values
+ (build-response
+ #:code (web-exception-code exn)
+ #:reason-phrase (web-exception-reason-phrase exn)
+ #:headers `((content-type application/xhtml+xml)))
+ (call-with-output-string
+ (cute sxml->xml
+ `(*TOP*
+ (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
+ (html (@ (xmlns "http://www.w3.org/1999/xhtml")
+ (xml:lang ,(W_ "xml-lang|en")))
+ (body
+ ,(call-with-input-string
+ (format #f (W_ "<h1>The identity provider request failed</h1>"))
+ xml->sxml)
+ ,(if (user-message? exn)
+ (user-message-sxml exn)
+ (call-with-input-string
+ (format #f (W_ "<p>No more information.</p>"))
+ xml->sxml)))))
+ <>))))
+ (lambda ()
+ (receive (response response-body response-meta)
+ (handle idp request request-body)
+ (values response response-body)))
+ #:unwind? #t))))))
diff --git a/src/scm/webid-oidc/oidc-configuration.scm b/src/scm/webid-oidc/oidc-configuration.scm
index 094bf8a..9748ab9 100644
--- a/src/scm/webid-oidc/oidc-configuration.scm
+++ b/src/scm/webid-oidc/oidc-configuration.scm
@@ -183,7 +183,7 @@
(else
(raise-exception
(make-exception
- (make-invalid-oidc-configuratin)
+ (make-invalid-oidc-configuration)
(make-exception-with-message
(G_ "when making an OIDC configuration, either its required #:jwks-uri, #:authorization-endpoint and #:token-endpoint fields or #:server or #:json-data should be passed")))))))))
diff --git a/src/scm/webid-oidc/server/endpoint/Makefile.am b/src/scm/webid-oidc/server/endpoint/Makefile.am
index e6c6158..7248538 100644
--- a/src/scm/webid-oidc/server/endpoint/Makefile.am
+++ b/src/scm/webid-oidc/server/endpoint/Makefile.am
@@ -18,10 +18,13 @@ dist_endpointserverwebidoidcmod_DATA += \
%reldir%/reverse-proxy.scm \
%reldir%/authentication.scm \
%reldir%/hello.scm \
- %reldir%/client.scm
+ %reldir%/client.scm \
+ %reldir%/identity-provider.scm
endpointserverwebidoidcgo_DATA += \
%reldir%/reverse-proxy.go \
%reldir%/authentication.go \
%reldir%/hello.go \
- %reldir%/client.go
+ %reldir%/client.go \
+ %reldir%/identity-provider.go
+
diff --git a/src/scm/webid-oidc/server/endpoint/identity-provider.scm b/src/scm/webid-oidc/server/endpoint/identity-provider.scm
new file mode 100644
index 0000000..d259ce9
--- /dev/null
+++ b/src/scm/webid-oidc/server/endpoint/identity-provider.scm
@@ -0,0 +1,590 @@
+;; disfluid, implementation of the Solid specification
+;; Copyright (C) 2021 Vivien Kraus
+
+;; This program is free software: you can redistribute it and/or modify
+;; it under the terms of the GNU Affero General Public License as
+;; published by the Free Software Foundation, either version 3 of the
+;; License, or (at your option) any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU Affero General Public License for more details.
+
+;; You should have received a copy of the GNU Affero General Public License
+;; along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+(define-module (webid-oidc server endpoint identity-provider)
+ #:use-module (webid-oidc errors)
+ #:use-module (webid-oidc authorization-code)
+ #:use-module (webid-oidc oidc-id-token)
+ #:use-module (webid-oidc access-token)
+ #:use-module (webid-oidc dpop-proof)
+ #:use-module (webid-oidc refresh-token)
+ #:use-module (webid-oidc oidc-configuration)
+ #:use-module (webid-oidc server endpoint)
+ #:use-module (webid-oidc provider-confirmation)
+ #:use-module (webid-oidc client-manifest)
+ #:use-module (webid-oidc jwk)
+ #:use-module ((webid-oidc parameters) #:prefix p:)
+ #:use-module ((webid-oidc config) #:prefix cfg:)
+ #:use-module ((webid-oidc stubs) #:prefix stubs:)
+ #:use-module (web request)
+ #:use-module (web response)
+ #:use-module (web uri)
+ #:use-module (web server)
+ #:use-module (web client)
+ #:use-module (ice-9 optargs)
+ #:use-module (ice-9 receive)
+ #:use-module (webid-oidc web-i18n)
+ #:use-module (ice-9 getopt-long)
+ #:use-module (ice-9 suspendable-ports)
+ #:use-module (ice-9 control)
+ #:use-module (ice-9 match)
+ #:use-module (ice-9 exceptions)
+ #:use-module (sxml simple)
+ #:use-module (srfi srfi-19)
+ #:use-module (srfi srfi-26)
+ #:use-module (oop goops)
+ #:use-module (sxml simple)
+ #:use-module (rnrs bytevectors)
+ #:duplicates (merge-generics)
+ #:declarative? #t
+ #:export
+ (
+ <oidc-discovery>
+ configuration
+
+ <authorization-endpoint>
+ subject
+ encrypted-password
+ key-file
+
+ <token-endpoint>
+ issuer
+ ;; key-file
+
+ <jwks-endpoint>
+ ;; key-file
+
+ <identity-provider>
+ oidc-discovery
+ authorization-endpoint
+ token-endpoint
+ jwks-endpoint
+ default
+ ))
+
+(define* (read-key-file key-file #:key (create? #f))
+ (define returned #f)
+ (if create?
+ (begin
+ (stubs:atomically-update-file
+ key-file
+ (string-append key-file ".lock")
+ (lambda (output-port)
+ (catch #t
+ (lambda ()
+ (call-with-input-file key-file
+ (lambda (port)
+ (set! returned
+ (jwk->key
+ (stubs:json->scm port))))))
+ (lambda error
+ ;; Generate the key and save it
+ (set! returned (generate-key #:n-size 2048))))
+ ;; Either the key already existed, so we save the exact same
+ ;; key, or it did not, so we save a new one.
+ (stubs:scm->json (key->jwk returned) output-port #:pretty #t)
+ #t))
+ returned)
+ ;; Try to read it first:
+ (catch #t
+ (lambda ()
+ (call-with-input-file key-file
+ (lambda (port)
+ (jwk->key (stubs:json->scm port)))))
+ (lambda error
+ (format (current-error-port) (G_ "Warning: generating a new key pair.\n"))
+ (read-key-file key-file #:create? #t)))))
+
+(define-class <oidc-discovery> (<endpoint>)
+ (configuration #:init-keyword #:configuration #:getter configuration))
+
+(define-class <authorization-endpoint> (<endpoint>)
+ (subject #:init-keyword #:subject #:getter subject)
+ (encrypted-password #:init-keyword #:encrypted-password #:getter encrypted-password)
+ (key-file #:init-keyword #:key-file #:getter key-file))
+
+(define-class <token-endpoint> (<endpoint>)
+ (issuer #:init-keyword #:issuer #:getter issuer)
+ (key-file #:init-keyword #:key-file #:getter key-file))
+
+(define-class <jwks-endpoint> (<endpoint>)
+ (key-file #:init-keyword #:key-file #:getter key-file))
+
+(define-class <identity-provider> (<router>)
+ (oidc-discovery #:init-keyword #:oidc-discovery #:getter oidc-discovery)
+ (authorization-endpoint #:init-keyword #:authorization-endpoint #:getter authorization-endpoint)
+ (token-endpoint #:init-keyword #:token-endpoint #:getter token-endpoint)
+ (jwks-endpoint #:init-keyword #:jwks-endpoint #:getter jwks-endpoint))
+
+(define-method (initialize (cfg <oidc-discovery>) initargs)
+ (next-method)
+ (unless (equal? (path cfg) "/.well-known/openid-configuration")
+ (scm-error 'wrong-type-arg "make <oidc-discovery>"
+ (G_ "#:path must be exactly \"/.well-known/openid-configuration\"")
+ '()
+ (list (path cfg))))
+ (let-keywords
+ initargs #t
+ ((configuration #f))
+ (unless (is-a? configuration <oidc-configuration>)
+ (scm-error 'wrong-type-arg "make <oidc-discovery>"
+ (G_ "#:configuration must be an OIDC configuration")
+ '()
+ (list configuration)))))
+
+(define-method (initialize (a <authorization-endpoint>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((subject #f)
+ (encrypted-password #f)
+ (key-file #f))
+ (match subject
+ ((? string? (= string->uri (? uri? subject)))
+ (slot-set! a 'subject subject))
+ ((? uri?) #t)
+ (else
+ (scm-error 'wrong-type-arg "make <authorization-endpoint>"
+ (G_ "#:subject should be an URI")
+ '()
+ (list subject))))
+ (unless (string? encrypted-password)
+ (scm-error 'wrong-type-arg "make <authorization-endpoint>"
+ (G_ "#:encrypted-password should be a string")
+ '()
+ (list encrypted-password)))
+ (unless (string? key-file)
+ (scm-error 'wrong-type-arg "make <authorization-endpoint>"
+ (G_ "#:key-file should be a string")
+ '()
+ (list key-file)))))
+
+(define-method (initialize (t <token-endpoint>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((issuer #f)
+ (key-file #f))
+ (match issuer
+ ((? string? (= string->uri (? uri? issuer)))
+ (slot-set! t 'issuer issuer))
+ ((and (? uri?)
+ (= uri-path "")
+ (= uri-query #f)
+ (= uri-fragment #f))
+ #t)
+ (else
+ (scm-error 'wrong-type-arg "make <token-endpoint>"
+ (G_ "#:subject should be an URI without a path, query or fragment")
+ '()
+ (list issuer))))
+ (unless (string? key-file)
+ (scm-error 'wrong-type-arg "make <token-endpoint>"
+ (G_ "#:key-file should be a string")
+ '()
+ (list key-file)))))
+
+(define-method (initialize (j <jwks-endpoint>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((key-file #f))
+ (unless (string? key-file)
+ (scm-error 'wrong-type-arg "make <jwks-endpoint>"
+ (G_ "#:key-file should be a string")
+ '()
+ (list key-file)))))
+
+(define-method (initialize (idp <identity-provider>) initargs)
+ (next-method)
+ (let-keywords
+ initargs #t
+ ((oidc-discovery #f)
+ (authorization-endpoint #f)
+ (token-endpoint #f)
+ (jwks-endpoint #f)
+ (default #f))
+ (match (routed idp)
+ (((? (cute eq? <> oidc-discovery))
+ (? (cute eq? <> authorization-endpoint))
+ (? (cute eq? <> token-endpoint))
+ (? (cute eq? <> jwks-endpoint))
+ (? (cute eq? <> default)))
+ ;; Recursive initialization done
+ #t)
+ (else
+ ;; Re-initialize with the proper endpoints
+ (initialize idp
+ `(#:routed (,oidc-discovery
+ ,authorization-endpoint
+ ,token-endpoint
+ ,jwks-endpoint
+ ,default)
+ ,@initargs))))))
+
+(define-method (handle (endpoint <oidc-discovery>) request request-body)
+ (let* ((current-sec (time-second (date->time-utc ((p:current-date)))))
+ (exp-sec (+ current-sec 3600))
+ (exp (time-utc->date
+ (make-time time-utc 0 exp-sec))))
+ (receive (response response-body)
+ (serve (configuration endpoint) exp)
+ (values response response-body '()))))
+
+(define (verify-password encrypted-password password)
+ (let ((c (crypt password encrypted-password)))
+ (string=? c encrypted-password)))
+
+(define (split-args str decode-plus-to-space?)
+ (apply append
+ (map
+ (lambda (k=v)
+ (catch #t
+ (lambda ()
+ (match (string-split k=v #\=)
+ (((= (cute uri-decode <> #:decode-plus-to-space? decode-plus-to-space?)
+ (= string->symbol key))
+ (= uri-decode value))
+ `((,key . ,value)))
+ (else '())))
+ (lambda error '())))
+ (catch #t
+ (lambda ()
+ (string-split str #\&))
+ (lambda error
+ '())))))
+
+(define-method (handle (endpoint <authorization-endpoint>) request request-body)
+ (let ((query-args
+ (split-args
+ (uri-query (request-uri request))
+ #f))
+ (form-args
+ (split-args
+ (and (match (request-content-type request)
+ ((or 'application/x-www-form-urlencoded
+ ('application/x-www-form-urlencoded _ ...))
+ #t)
+ (else #f))
+ (if (bytevector? request)
+ (false-if-exception
+ (utf8->string request-body))
+ request-body))
+ #t)))
+ (let ((client-id
+ (match (assq-ref query-args 'client_id)
+ ((? string? (= string->uri (? uri? uri)))
+ uri)
+ (else #f)))
+ (redirect-uri
+ (match (assq-ref query-args 'redirect_uri)
+ ((? string? (= string->uri (? uri? uri)))
+ uri)
+ (else #f)))
+ (password (assq-ref form-args 'password))
+ (state (assq-ref query-args 'state)))
+ (define form
+ (if (uri? client-id)
+ `(div
+ ,(call-with-input-string
+ (format #f (W_ "<h2>Do you wish to authorize <a href=~s>~a</a>?</h2>")
+ (uri->string client-id)
+ (uri->string client-id))
+ xml->sxml)
+ (p ,(W_ "If you wish to do so, please type your password:"))
+ (form (@ (method "post"))
+ (input (@ (type "password")
+ (name "password")
+ (id "password")))
+ (input (@ (type "submit")
+ (value ,(W_ "Allow"))))))
+ '(p)))
+ (unless client-id
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ `(p ,(W_ "The client_id query argument is not set."))))))
+ (unless redirect-uri
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ `(p ,(W_ "The redirect_uri query argument is not set."))))))
+ (if (eq? (request-method request) 'POST)
+ (begin
+ (unless (and password (verify-password (encrypted-password endpoint) password))
+ (raise-exception
+ (make-exception
+ (make-web-exception 401 (W_ "reason-phrase|Unauthorized"))
+ (make-user-message
+ `(p ,(W_ "The password is incorrect.")))
+ (make-user-message form))))
+ (let ((code (issue <authorization-code>
+ (read-key-file (key-file endpoint))
+ #:webid (subject endpoint)
+ #:client-id client-id))
+ (mf
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The client, <a href=~s>~a</a>, cannot be queried.</p>")
+ (uri->string client-id)
+ (uri->string client-id))
+ xml->sxml))
+ exn))
+ (lambda ()
+ (make <client-manifest>
+ #:client-id client-id)))))
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The real client at <a href=~s>~a</a> does not control the advertised redirection URI.</p>"))
+ xml->sxml))
+ exn))
+ (lambda ()
+ (check-redirect-uri mf redirect-uri)))
+ (values
+ (build-response
+ #:code 302
+ #:reason-phrase (W_ "reason-phrase|Found")
+ #:headers `((location
+ . ,(build-uri 'https
+ #:userinfo (uri-userinfo redirect-uri)
+ #:host (uri-host redirect-uri)
+ #:port (uri-port redirect-uri)
+ #:path (uri-path redirect-uri)
+ #:query
+ (if state
+ (format #f "code=~a&state=~a"
+ (uri-encode code)
+ (uri-encode state))
+ (string-append "code="
+ (uri-encode code)))))
+ (content-type application/xhtml+xml)))
+ (call-with-output-string
+ (cute sxml->xml
+ `(*TOP*
+ (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
+ (html (@ (xmlns "http://www.w3.org/1999/xhtml")
+ (xml:lang ,(W_ "xml-lang|en")))
+ (head
+ (title ,(W_ "Redirecting...")))
+ (body
+ (p ,(W_ "You are being redirected.")))))
+ <>))
+ '())))
+ (values
+ (build-response #:headers `((content-type application/xhtml+xml)))
+ (call-with-output-string
+ (cute sxml->xml
+ `(*TOP*
+ (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
+ (html (@ (xmlns "http://www.w3.org/1999/xhtml")
+ (xml:lang ,(W_ "xml-lang|en")))
+ (head
+ (title ,(W_ "Authorization...")))
+ (body ,form)))
+ <>))
+ '())))))
+
+(define-method (handle (endpoint <token-endpoint>) request request-body)
+ (unless (match (request-content-type request)
+ ((or 'application/x-www-form-urlencoded
+ ('application/x-www-form-urlencoded _ ...))
+ #t)
+ (else #f))
+ (raise-exception
+ (make-exception
+ (make-web-exception 415 (W_ "reason-phrase|Unsupported Media Type"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Please use <pre>application/x-www-form-urlencoded</pre>.</p>"))
+ xml->sxml)))))
+ (when (bytevector? request-body)
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Expected an UTF-8 request body.</p>"))
+ xml->sxml))
+ exn)))
+ (lambda ()
+ (set! request-body (utf8->string request-body)))))
+ (unless (eq? (request-method request) 'POST)
+ (raise-exception
+ (make-exception
+ (make-web-exception 405 (W_ "reason-phrase|Method Not Allowed"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>This is a token endpoint, please use <pre>POST</pre>.</p>"))
+ xml->sxml)))))
+ (let ((form-args (split-args request-body #t))
+ (true-uri
+ (let ((server-uri (issuer endpoint)))
+ (build-uri (uri-scheme server-uri)
+ #:userinfo (uri-userinfo server-uri)
+ #:host (uri-host server-uri)
+ #:port (uri-port server-uri)
+ #:path (uri-path (request-uri request))
+ #:query (uri-query (request-uri request))))))
+ (let ((grant-type (assq-ref form-args 'grant_type))
+ (dpop
+ (let ((proof (assq-ref (request-headers request) 'dpop)))
+ (unless proof
+ (raise-exception
+ (make-exception
+ (make-web-exception 401 (W_ "reason-phrase|Unauthorized"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>No DPoP proof has been found in your request.</p>"))
+ xml->sxml)))))
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-exception
+ (make-web-exception 401 (W_ "reason-phrase|Unauthorized"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The DPoP proof is invalid.</p>"))
+ xml->sxml)))))
+ (lambda ()
+ (decode <dpop-proof> proof
+ #:method (request-method request)
+ #:uri true-uri
+ #:cnf/check
+ (lambda (jkt) #t)))))))
+ (unless grant-type
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The <pre>grant_type</pre> parameter has not been found.</p>"))
+ xml->sxml)))))
+ (receive (webid client-id)
+ (case (string->symbol grant-type)
+ ((authorization_code)
+ (let ((code
+ (let ((str (assq-ref form-args 'code)))
+ (unless str
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Could not find an authorization code.</p>"))
+ xml->sxml)))))
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The authorization code is invalid.</p>"))
+ xml->sxml))
+ exn)))
+ (lambda ()
+ (decode <authorization-code> str
+ #:issuer-key (read-key-file (key-file endpoint))))))))
+ (values (webid code) (client-id code))))
+ ((refresh_token)
+ (let ((refresh-token (assq-ref form-args 'refresh_token)))
+ (unless refresh-token
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Requeset"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Could not find a refresh token.</p>"))
+ xml->sxml)))))
+ (with-exception-handler
+ (lambda (exn)
+ (raise-exception
+ (make-exception
+ (make-web-exception 403 (W_ "reason-phrase|Forbidden"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>The refresh token is invalid or has been revoked.</p>"))
+ xml->sxml))
+ exn)))
+ (lambda ()
+ (with-refresh-token refresh-token (jwk dpop) values)))))
+ (else
+ (raise-exception
+ (make-exception
+ (make-web-exception 400 (W_ "reason-phrase|Bad Request"))
+ (make-user-message
+ (call-with-input-string
+ (format #f (W_ "<p>Cannot process your grant type, ~a.</p>")
+ (call-with-output-string
+ (cute sxml->xml `(pre ,grant-type) <>)))
+ xml->sxml))))))
+ ;; So, either from an authorization code or a refresh token, I
+ ;; have a webid and client-id.
+ (receive (id-token access-token refresh-token)
+ (let ((key-file (read-key-file (key-file endpoint))))
+ (let ((id-token
+ (issue <id-token> key-file
+ #:webid webid
+ #:iss (issuer endpoint)
+ #:aud client-id))
+ (access-token
+ (issue <access-token> key-file
+ #:webid webid
+ #:iss (issuer endpoint)
+ #:client-key (jwk dpop)
+ #:client-id client-id))
+ (refresh-token
+ ;; Reuse it if already present
+ (if (equal? grant-type "refresh_token")
+ (assq-ref form-args 'refresh_token)
+ (issue-refresh-token
+ webid client-id (jkt (jwk dpop))))))
+ (values id-token access-token refresh-token)))
+ (values
+ (build-response #:headers '((content-type application/json)
+ (cache-control (no-cache no-store)))
+ #:port #f)
+ (stubs:scm->json-string
+ `((id_token . ,id-token)
+ (access_token . ,access-token)
+ (token_type . "DPoP")
+ (expires_in . ,(p:oidc-token-default-validity))
+ (refresh_token . ,refresh-token)))
+ `((user . ,webid)
+ (client-id . ,client-id))))))))
+
+(define-method (handle (endpoint <jwks-endpoint>) request request-body)
+ (let ((jwks (make <jwks> #:keys (list (read-key-file (key-file endpoint))))))
+ (let* ((current-sec (time-second (date->time-utc ((p:current-date)))))
+ (exp-sec (+ current-sec 3600))
+ (exp (time-utc->date
+ (make-time time-utc 0 exp-sec))))
+ (receive (response response-body)
+ (serve jwks exp)
+ (values response response-body '())))))
+
diff --git a/src/scm/webid-oidc/token-endpoint.scm b/src/scm/webid-oidc/token-endpoint.scm
index 53ff1cc..f96e768 100644
--- a/src/scm/webid-oidc/token-endpoint.scm
+++ b/src/scm/webid-oidc/token-endpoint.scm
@@ -15,6 +15,7 @@
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
(define-module (webid-oidc token-endpoint)
+ #:use-module (webid-oidc server endpoint identity-provider)
#:use-module (webid-oidc errors)
#:use-module (webid-oidc server endpoint)
#:use-module (webid-oidc authorization-code)
@@ -35,6 +36,7 @@
#:use-module (ice-9 control)
#:use-module (ice-9 exceptions)
#:use-module (srfi srfi-19)
+ #:use-module (srfi srfi-26)
#:use-module (rnrs bytevectors)
#:use-module (sxml simple)
#:use-module (sxml match)
@@ -43,285 +45,50 @@
#:declarative? #t
#:export
(
- &unsupported-grant-type
- make-unsupported-grant-type
- unsupported-grant-type?
- unsupported-grant-type-grant-type
-
- &no-authorization-code
- make-no-authorization-code
- no-authorization-code?
-
- &no-refresh-token
- make-no-refresh-token
- no-refresh-token?
-
make-token-endpoint
))
-(define-exception-type
- &unsupported-grant-type
- &external-error
- make-unsupported-grant-type
- unsupported-grant-type?
- (grant-type unsupported-grant-type-grant-type))
-
-(define-exception-type
- &no-authorization-code
- &external-error
- make-no-authorization-code
- no-authorization-code?)
-
-(define-exception-type
- &no-refresh-token
- &external-error
- make-no-refresh-token
- no-refresh-token?)
-
(define (try-handle-web-failure thunk)
(call/ec
(lambda (return)
(with-exception-handler
(lambda (error)
- (unless (or (unsupported-grant-type? error)
- (no-authorization-code? error)
- (no-refresh-token? error)
- (refresh:invalid-refresh-token? error)
- (invalid-authorization-code? error))
- (let ((final-message
- (if (exception-with-message? error)
- (format #f (G_ "while handling web failure for the token endpoint: ~a")
- (exception-message error))
- (format #f (G_ "an error happened during the token endpoint failure handling")))))
- (raise-exception
- (make-exception
- (make-exception-with-message final-message)
- error))))
- (cond
- ((refresh:invalid-refresh-token? error)
- (return
- (build-response
- #:code 403
- #:reason-phrase (G_ "reason-phrase|Forbidden")
- #:headers '((content-type application/xhtml-xml)))
- (call-with-output-string
- (lambda (port)
- (sxml->xml
- `(*TOP*
- (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
- (html (@ (xmlns "http://www.w3.org/1999/xhtml")
- (xml:lang ,(W_ "xml-lang|en")))
- (body
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<h1>Invalid refresh token</h1>")))
- ((*TOP* ,title) title))
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<p>The refresh token you sent is invalid, or it is already bound to another key.</p>")))
- ((*TOP* ,p) p))
- ,@(if (user-message? error)
- (list (user-message-sxml error))
- '()))))
- port)))))
- ((invalid-authorization-code? error)
- (return
- (build-response
- #:code 400
- #:reason-phrase (G_ "reason-phrase|Bad Request")
- #:headers '((content-type application/xhtml-xml)))
- (call-with-output-string
- (lambda (port)
- (sxml->xml
- `(*TOP*
- (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
- (html (@ (xmlns "http://www.w3.org/1999/xhtml")
- (xml:lang ,(W_ "xml-lang|en")))
- (body
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<h1>Invalid authorization code</h1>")))
- ((*TOP* ,title) title))
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<p>The authorization code is forged, or expired.</p>")))
- ((*TOP* ,p) p))
- ,@(if (user-message? error)
- (list (user-message-sxml error))
- '()))))
- port)))))
- ;; Other bad request
- (else
- (return
- (build-response
- #:code 400
- #:reason-phrase (G_ "reason-phrase|Bad Request")
- #:headers '((content-type application/xhtml+xml)))
- (call-with-output-string
- (lambda (port)
- (sxml->xml
- `(*TOP*
- (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
- (html (@ (xmlns "http://www.w3.org/1999/xhtml")
- (xml:lang ,(W_ "xml-lang|en")))
- (body
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<h1>Bad token request</h1>")))
- ((*TOP* ,title) title))
- ,(sxml-match
- (xml->sxml
- (W_ (format #f "<p>The token request failed.</p>")))
- ((*TOP* ,p) p))
- ,@(if (user-message? error)
- (list (user-message-sxml error))
- '()))))
- port)))))))
+ (unless (web-exception? error)
+ (raise-exception error))
+ (return
+ (build-response
+ #:code (web-exception-code error)
+ #:reason-phrase (web-exception-reason-phrase error)
+ #:headers `((content-type application/xhtml+xml)))
+ (call-with-output-string
+ (cute sxml->xml
+ `(*TOP*
+ (*PI* xml "version=\"1.0\" encoding=\"utf-8\"")
+ (html (@ (xmlns "http://www.w3.org/1999/xhtml")
+ (xml:lang ,(W_ "xml-lang|en")))
+ (body
+ ,(call-with-input-string
+ (format #f (W_ "<h1>The token request failed</h1>"))
+ xml->sxml)
+ ,(if (user-message? error)
+ (user-message-sxml error)
+ (call-with-input-string
+ (format #f (W_ "<p>No more information.</p>"))
+ xml->sxml)))))
+ <>))))
thunk))))
-(define (make-token-endpoint token-endpoint-uri iss issuer-key)
+(define (make-token-endpoint token-endpoint-uri iss issuer-key-file)
+ (define endpoint
+ (make <token-endpoint>
+ #:issuer iss
+ #:key-file issuer-key-file))
(lambda (request request-body)
(when (bytevector? request-body)
(set! request-body (utf8->string request-body)))
(try-handle-web-failure
(lambda ()
- (parameterize ((p:current-date ((p:current-date)))
- (web-locale request))
- (let ((current-time ((p:current-date))) ;; thunk parameter
- (form-args
- (if (and (request-content-type request)
- (eq? (car (request-content-type request))
- 'application/x-www-form-urlencoded))
- (filter
- (lambda (x) x)
- (map (lambda (kv)
- (let ((parsed
- (list->vector
- (map (lambda (x)
- (uri-decode x #:decode-plus-to-space? #t))
- (string-split kv #\=)))))
- (if (eq? (vector-length parsed) 2)
- `(,(vector-ref parsed 0) . ,(vector-ref parsed 1))
- #f)))
- (string-split request-body #\&)))
- '()))
- (method (request-method request))
- ;; Maybe we’re behind a reverse proxy, so the authority of
- ;; (request-uri request) is meaningless.
- (uri (build-uri (uri-scheme token-endpoint-uri)
- #:userinfo (uri-userinfo token-endpoint-uri)
- #:host (uri-host token-endpoint-uri)
- #:port (uri-port token-endpoint-uri)
- #:path (uri-path (request-uri request))
- #:query (uri-query (request-uri request)))))
- (let ((grant-type (assoc-ref form-args "grant_type"))
- (dpop (decode <dpop-proof> (assq-ref (request-headers request) 'dpop)
- #:method method
- #:uri uri
- #:cnf/check
- (lambda (jkt) #t))))
- (unless (and grant-type (string? grant-type))
- (let ((final-message
- (format #f (G_ "missing grant type")))
- (final-user-message
- (sxml-match
- (xml->sxml
- (format #f (W_ "<p>You did not specify a grant_type for this request.</p>")))
- ((*TOP* ,p) p))))
- (raise-exception
- (make-exception
- (make-unsupported-grant-type #f)
- (make-exception-with-message final-message)
- (make-user-message final-user-message)))))
- (receive (webid client-id)
- (case (string->symbol grant-type)
- ((authorization_code)
- (let ((code
- (let ((str (assoc-ref form-args "code")))
- (unless str
- (let ((final-message
- (format #f (G_ "missing authorization code")))
- (final-user-message
- (sxml-match
- (xml->sxml
- (format #f (W_ "<p>You want to grant an authorization code, but you did not set one.</p>")))
- ((*TOP* ,p) p))))
- (raise-exception
- (make-exception
- (make-no-authorization-code)
- (make-exception-with-message final-message)
- (make-user-message final-user-message)))))
- (with-exception-handler
- (lambda (error)
- (raise-exception
- (make-exception
- (make-invalid-authorization-code)
- error)))
- (lambda ()
- (decode <authorization-code> str
- #:issuer-key issuer-key))))))
- (values (webid code) (client-id code))))
- ((refresh_token)
- (let ((refresh-token (assoc-ref form-args "refresh_token")))
- (unless refresh-token
- (let ((final-message
- (format #f (G_ "missing refresh token")))
- (final-user-message
- (sxml-match
- (xml->sxml
- (format #f (W_ "<p>You want to grant a refresh token, but you did not set one.</p>")))
- ((*TOP* ,p) p))))
- (raise-exception
- (make-exception
- (make-no-refresh-token)
- (make-exception-with-message final-message)
- (make-user-message final-user-message)))))
- (refresh:with-refresh-token
- refresh-token
- (jwk dpop)
- values)))
- (else
- (let ((final-message
- (format #f (G_ "unsupported grant type: ~s")
- grant-type))
- (final-user-message
- (sxml-match
- (xml->sxml
- (format #f (W_ "<p>You want to use <pre>~s</pre> as a grant type, but this is not supported.</p>")
- grant-type))
- ((*TOP* ,p) p))))
- (raise-exception
- (make-exception
- (make-unsupported-grant-type grant-type)
- (make-exception-with-message final-message)
- (make-user-message final-user-message))))))
- (let ((id-token
- (issue <id-token>
- issuer-key
- #:webid webid
- #:iss iss
- #:aud client-id))
- (access-token
- (issue <access-token>
- issuer-key
- #:webid webid
- #:iss iss
- #:client-key (jwk dpop)
- #:client-id client-id))
- (refresh-token
- (if (equal? grant-type "refresh_token")
- (assoc-ref form-args "refresh_token")
- (refresh:issue-refresh-token webid client-id
- (jkt (jwk dpop))))))
- (values
- (build-response #:headers '((content-type application/json)
- (cache-control (no-cache no-store)))
- #:port #f)
- (stubs:scm->json-string
- `((id_token . ,id-token)
- (access_token . ,access-token)
- (token_type . "DPoP")
- (expires_in . ,(p:oidc-token-default-validity))
- (refresh_token . ,refresh-token)))
- client-id
- #f))))))))))
+ (parameterize ((web-locale request))
+ (receive (response response-body response-meta)
+ (handle endpoint request request-body)
+ (values response response-body)))))))
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a35c853..b24819c 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -83,6 +83,8 @@ clean-local: %canon_reldir%-clean-local
%canon_reldir%-clean-local:
rm -rf %reldir%/*.cache
rm -rf %reldir%/*.home
+ rm -f key-file.jwk.lock
+ rm -f key-file.jwk
AM_TESTS_ENVIRONMENT = $(top_builddir)/pre-inst-env
SCM_LOG_COMPILER = $(GUILE)
diff --git a/tests/authorization-endpoint-get-form.scm b/tests/authorization-endpoint-get-form.scm
index 27f22f9..25b7128 100644
--- a/tests/authorization-endpoint-get-form.scm
+++ b/tests/authorization-endpoint-get-form.scm
@@ -29,12 +29,11 @@
(with-test-environment
"authorization-endpoint-get-form"
(lambda ()
- (define key (generate-key #:n-size 2048))
(define subject (string->uri "https://authorization-endpoint-get-form.scm/profile/card#me"))
(define password "p4ssw0rd")
(define endpoint
(make-authorization-endpoint
- subject password key))
+ subject password "key-file.jwk"))
(receive (response response-body)
(parameterize ((p:current-date 0))
(endpoint
diff --git a/tests/authorization-endpoint-no-args.scm b/tests/authorization-endpoint-no-args.scm
index 164e345..7976d9d 100644
--- a/tests/authorization-endpoint-no-args.scm
+++ b/tests/authorization-endpoint-no-args.scm
@@ -29,11 +29,10 @@
(with-test-environment
"authorization-endpoint-no-args"
(lambda ()
- (define key (generate-key #:n-size 2048))
(define subject (string->uri "https://authorization-endpoint-get-form.scm/profile/card#me"))
(define password "p4ssw0rd")
(define endpoint
- (make-authorization-endpoint subject password key))
+ (make-authorization-endpoint subject password "./key-file.jwk"))
(receive (response response-body)
(parameterize ((p:current-date 0))
(endpoint
diff --git a/tests/authorization-endpoint-submit-form.scm b/tests/authorization-endpoint-submit-form.scm
index 4f11db0..78216a9 100644
--- a/tests/authorization-endpoint-submit-form.scm
+++ b/tests/authorization-endpoint-submit-form.scm
@@ -23,6 +23,7 @@
#:use-module (webid-oidc jti)
#:use-module (webid-oidc testing)
#:use-module ((webid-oidc parameters) #:prefix p:)
+ #:use-module ((webid-oidc stubs) #:prefix stubs:)
#:use-module (web uri)
#:use-module (web request)
#:use-module (web response)
@@ -37,7 +38,6 @@
(with-test-environment
"authorization-endpoint-submit-form"
(lambda ()
- (define key (generate-key #:n-size 2048))
(define subject (string->uri "https://authorization-endpoint-submit-form.scm/profile/card#me"))
(define client (string->uri "https://authorization-endpoint-submit-form.scm/client/card#app"))
(define redirect (string->uri "https://authorization-endpoint-submit-form.scm/client/redirect"))
@@ -55,7 +55,7 @@
(define the-response-body (cdr served))
(define endpoint
(make-authorization-endpoint
- subject encrypted-password key))
+ subject encrypted-password "key-file.jwk"))
(parameterize ((p:anonymous-http-request
(lambda* (uri #:key (headers '()) #:allow-other-keys)
(unless (equal? uri what-uri-to-expect)
@@ -113,6 +113,9 @@
(parameterize ((p:current-date 60))
(decode <authorization-code>
(car (assoc-ref args "code"))
- #:issuer-key key))))
+ #:issuer-key
+ (call-with-input-file "key-file.jwk"
+ (lambda (port)
+ (jwk->key (stubs:json->scm port))))))))
(unless parsed
(exit 10))))))))))))
diff --git a/tests/token-endpoint-issue.scm b/tests/token-endpoint-issue.scm
index 8fdd1ad..f986e8e 100644
--- a/tests/token-endpoint-issue.scm
+++ b/tests/token-endpoint-issue.scm
@@ -36,6 +36,12 @@
"token-endpoint-issue"
(lambda ()
(define key (generate-key #:n-size 2048))
+ (call-with-output-file "key-file.jwk"
+ (lambda (port)
+ (stubs:scm->json
+ (key->jwk key)
+ port
+ #:pretty #t)))
(define client-key (generate-key #:n-size 2048))
(define subject (string->uri "https://token-endpoint-issue.scm/profile/card#me"))
(define client (string->uri "https://token-endpoint-issue.scm/client/card#app"))
@@ -49,7 +55,7 @@
(define endpoint
(make-token-endpoint
(string->uri "https://token-endpoint-issue.scm/token")
- issuer key))
+ issuer "key-file.jwk"))
(receive (response response-body . _)
;; The code is fake!
(let ((dpop
@@ -90,7 +96,6 @@
#:port #t)
(string-append "grant_type=authorization_code&code=" authz))))
(unless (eq? (response-code response) 200)
- (write response)
(exit 4))
(unless (eq? (car (response-content-type response)) 'application/json)
(exit 5))
diff --git a/tests/token-endpoint-refresh.scm b/tests/token-endpoint-refresh.scm
index 90e2625..91effe0 100644
--- a/tests/token-endpoint-refresh.scm
+++ b/tests/token-endpoint-refresh.scm
@@ -37,15 +37,22 @@
"token-endpoint-refresh"
(lambda ()
(define key (generate-key #:n-size 2048))
+ (call-with-output-file "key-file.jwk"
+ (lambda (port)
+ (stubs:scm->json
+ (key->jwk key)
+ port
+ #:pretty #t)))
(define client-key (generate-key #:n-size 2048))
(define subject (string->uri "https://token-endpoint-issue.scm/profile/card#me"))
(define client (string->uri "https://token-endpoint-issue.scm/client/card#app"))
(define issuer (string->uri "https://issuer.token-endpoint-issue.scm"))
(define refresh-code
(issue-refresh-token subject client (jkt client-key)))
- (define endpoint (make-token-endpoint
- (string->uri "https://token-endpoint-issue.scm/token")
- issuer key))
+ (define endpoint
+ (make-token-endpoint
+ (string->uri "https://token-endpoint-issue.scm/token")
+ issuer "key-file.jwk"))
(receive (response response-body . _)
;; The refresh token is fake!
(let ((dpop
@@ -67,7 +74,7 @@
"refresh_token=fake")))
(unless (eq? (response-code response) 400)
(exit 3))
- (receive (response response-body user error)
+ (receive (response response-body)
(let ((dpop
(parameterize ((p:current-date 10))
(issue <dpop-proof>