diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2021-10-14 11:36:14 +0200 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2021-10-20 18:04:30 +0200 |
commit | 34624c72245b483e645efd281a27c9c9e210a19a (patch) | |
tree | afca30257d8a7c842bd80a4121c69be201c5fdca | |
parent | 326f056867bab68ae94408a31af6f4c666dfb191 (diff) |
server: add an identity provider endpoint
-rw-r--r-- | doc/disfluid.texi | 104 | ||||
-rw-r--r-- | po/POTFILES.in | 3 | ||||
-rw-r--r-- | po/disfluid.pot | 305 | ||||
-rw-r--r-- | po/fr.po | 432 | ||||
-rw-r--r-- | src/scm/webid-oidc/Makefile.am | 4 | ||||
-rw-r--r-- | src/scm/webid-oidc/authorization-endpoint.scm | 135 | ||||
-rw-r--r-- | src/scm/webid-oidc/authorization-page-unsafe.scm | 137 | ||||
-rw-r--r-- | src/scm/webid-oidc/authorization-page.scm | 56 | ||||
-rw-r--r-- | src/scm/webid-oidc/identity-provider.scm | 150 | ||||
-rw-r--r-- | src/scm/webid-oidc/oidc-configuration.scm | 2 | ||||
-rw-r--r-- | src/scm/webid-oidc/server/endpoint/Makefile.am | 7 | ||||
-rw-r--r-- | src/scm/webid-oidc/server/endpoint/identity-provider.scm | 590 | ||||
-rw-r--r-- | src/scm/webid-oidc/token-endpoint.scm | 301 | ||||
-rw-r--r-- | tests/Makefile.am | 2 | ||||
-rw-r--r-- | tests/authorization-endpoint-get-form.scm | 3 | ||||
-rw-r--r-- | tests/authorization-endpoint-no-args.scm | 3 | ||||
-rw-r--r-- | tests/authorization-endpoint-submit-form.scm | 9 | ||||
-rw-r--r-- | tests/token-endpoint-issue.scm | 9 | ||||
-rw-r--r-- | tests/token-endpoint-refresh.scm | 15 |
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 @@ -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> |