diff options
author | Vivien Kraus <vivien@planete-kraus.eu> | 2021-05-05 15:22:01 +0200 |
---|---|---|
committer | Vivien Kraus <vivien@planete-kraus.eu> | 2021-05-11 02:24:27 +0200 |
commit | efe7603fafdd281047b213191b3a28048e88c08a (patch) | |
tree | 60e89c1ac32905cc9401eeb897350ba691ce140e | |
parent | 61af76ce784e08a0e9479c4370aa1e5a4c1b7e91 (diff) |
Add a server for an application
-rwxr-xr-x | bootstrap | 2 | ||||
-rw-r--r-- | doc/manual.html | 73 | ||||
-rw-r--r-- | guix/vkraus/packages/webid-oidc.scm | 2 | ||||
-rw-r--r-- | guix/vkraus/services/webid-oidc.scm | 81 | ||||
-rw-r--r-- | man/Makefile.am | 6 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rw-r--r-- | po/fr.po | 237 | ||||
-rw-r--r-- | po/webid-oidc.pot | 93 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/scm/webid-oidc/client.scm | 261 | ||||
-rwxr-xr-x | src/webid-oidc-client-service | 7 |
11 files changed, 635 insertions, 130 deletions
@@ -12,7 +12,7 @@ mkdir -p .native || exit 1 cd .native || exit 1 bash ../configure SHELL=$(which sh) || exit 1 -for file in ../src/webid-oidc-issuer ../src/webid-oidc-reverse-proxy +for file in ../src/webid-oidc-issuer ../src/webid-oidc-reverse-proxy ../src/webid-oidc-client-service do sed -i "s|/usr/local/bin/guile|$(which guile)|g" $file || exit 1 done diff --git a/doc/manual.html b/doc/manual.html index 3073b19..610bc02 100644 --- a/doc/manual.html +++ b/doc/manual.html @@ -1244,6 +1244,79 @@ returns the time. It is used to issue DPoP proofs. </p> </info:deffn> + <p> + The identity provider needs to call the application on the + web. So, your client should have a public endpoint on the web. + </p> + <info:deffn type="function" name="serve-application" arguments="id redirect-uri [#client-name] [#client-uri]"> + <p> + Return a handler for web requests to serve the application + manifest and the redirection to transmit the authorization + code. You should set the <info:var>client-name</info:var> to + your application name and <info:var>client-uri</info:var> to + point to where to a presentation of your application. + </p> + </info:deffn> + <p> + The <pre>webid-oidc-client-service</pre> program can run a + server to serve these resources. It is invoked with the + following options: + </p> + <ul> + <li> + <pre>-h</pre>, or <pre>--help</pre> prints a summary of the + options and exit. + </li> + <li> + <pre>-v</pre>, or <pre>--version</pre> prints the version of + the program and exits. + </li> + <li> + <pre>-i <info:var>URI</info:var></pre>, or + <pre>--client-id=<info:var>URI</info:var></pre> sets the + global identitifier of the application, which is dereferenced + to a semantic resource. + </li> + <li> + <pre>-r <info:var>URI</info:var></pre>, or + <pre>--redirect-uri=<info:var>URI</info:var></pre> sets the + redirection URI. + </li> + <li> + <pre>-n <info:var>NAME</info:var></pre>, or + <pre>--client-name=<info:var>NAME</info:var></pre> sets the + name of your application, so that it is shown when the user + gets an authorization. The webid-oidc issuer program that + comes with this package does not display it, because it could + be dishonest, but other implementations might. + </li> + <li> + <pre>-u <info:var>URI</info:var></pre>, or + <pre>--client-uri=<info:var>URI</info:var></pre>, sets an URI + for the identity provider to learn more about your app. + </li> + <li> + <pre>-p <info:var>PORT</info:var></pre>, or + <pre>--port=<info:var>PORT</info:var></pre>, change the port + number used by the server. By default, it is set to 8080. + </li> + <li> + <pre>-l <info:var>FILE.log</info:var></pre>, or + <pre>--log-file=<info:var>FILE.log</info:var></pre> let the + server dump all its output to <info:var>FILE.log</info:var>. + </li> + <li> + <pre>-e <info:var>FILE.err</info:var></pre>, or + <pre>--error-file=<info:var>FILE.err</info:var></pre> let the + server dump all its errors to <info:var>FILE.err</info:var>. + </li> + </ul> + <p> + The program is sensitive to the environment variable + <emph>LANG</emph>, which influences how the program is + internationalized to the server administrator. This changes the + long form of the options, and the language in the log files. + </p> <h1 type="appendix">GNU Free Documentation License</h1> <info:gfdl /> diff --git a/guix/vkraus/packages/webid-oidc.scm b/guix/vkraus/packages/webid-oidc.scm index b195c33..372892e 100644 --- a/guix/vkraus/packages/webid-oidc.scm +++ b/guix/vkraus/packages/webid-oidc.scm @@ -67,7 +67,7 @@ (format #f "~a/bin/webid-oidc-~a" out program) `("GUILE_LOAD_PATH" ":" = ,mod-paths) `("GUILE_LOAD_COMPILED_PATH" ":" = ,go-paths))) - '(issuer reverse-proxy hello)))))))) + '(issuer reverse-proxy hello client-service)))))))) (native-inputs `(("pkg-config" ,pkg-config) ("guile" ,guile-3.0) diff --git a/guix/vkraus/services/webid-oidc.scm b/guix/vkraus/services/webid-oidc.scm index 33b4fae..e510ba9 100644 --- a/guix/vkraus/services/webid-oidc.scm +++ b/guix/vkraus/services/webid-oidc.scm @@ -57,6 +57,21 @@ webid-oidc-hello-configuration-extra-options (default '()))) +(define-record-type* <webid-oidc-client-service-configuration> + webid-oidc-client-service-configuration + make-webid-oidc-client-service-configuration + webid-oidc-client-service-configuration? + (webid-oidc webid-oidc-client-service-configuration-webid-oidc + (default webid-oidc)) + (client-id webid-oidc-client-service-configuration-client-id) + (redirect-uri webid-oidc-client-service-configuration-redirect-uri) + (client-name webid-oidc-client-service-configuration-client-name (default "Example Solid App")) + (client-uri webid-oidc-client-service-configuration-client-uri (default "https://webid-oidc.planete-kraus.eu/Running-a-client.html#Running-a-client")) + (port webid-oidc-client-service-configuration-port (default 8088)) + (extra-options + webid-oidc-client-service-configuration-extra-options + (default '()))) + (export <webid-oidc-issuer-configuration> webid-oidc-issuer-configuration make-webid-oidc-issuer-configuration @@ -87,7 +102,18 @@ webid-oidc-hello-configuration? webid-oidc-hello-configuration-webid-oidc webid-oidc-hello-configuration-port - webid-oidc-hello-configuration-extra-options) + webid-oidc-hello-configuration-extra-options + <webid-oidc-client-service-configuration> + webid-oidc-client-service-configuration + make-webid-oidc-client-service-configuration + webid-oidc-client-service-configuration? + webid-oidc-client-service-configuration-webid-oidc + webid-oidc-client-service-configuration-client-id + webid-oidc-client-service-configuration-redirect-uri + webid-oidc-client-service-configuration-client-name + webid-oidc-client-service-configuration-client-uri + webid-oidc-client-service-configuration-port + webid-oidc-client-service-configuration-extra-options) (define webid-oidc-issuer-shepherd-service (match-lambda @@ -223,6 +249,48 @@ "LANG=C")))) (stop #~(make-kill-destructor)))))))) +(define webid-oidc-client-service-shepherd-service + (match-lambda + (($ <webid-oidc-client-service-configuration> + webid-oidc client-id redirect-uri client-name client-uri port + extra-options) + (with-imported-modules + (source-module-closure + '((gnu build shepherd) + (gnu system file-systems))) + (list (shepherd-service + (provision '(webid-oidc-client-service)) + (documentation "Run a server for a Solid application.") + (requirement '(user-processes)) + (modules '((gnu build shepherd) + (gnu system file-systems))) + (start + #~(begin + (let* ((user (getpwnam "webid-oidc")) + (prepare-directory + (lambda (dir) + (mkdir-p dir) + (chown dir (passwd:uid user) (passwd:gid user)) + (chmod dir #o700)))) + (prepare-directory "/var/log/webid-oidc")) + (make-forkexec-constructor + (list + (string-append #$webid-oidc "/bin/webid-oidc-client-service") + "--client-id" #$client-id + "--redirect-uri" #$redirect-uri + "--client-name" #$client-name + "--client-uri" #$client-uri + "--port" (with-output-to-string (lambda () (display #$port))) + "--log-file" "client-service.log" + "--error-file" "client-service.err" + #$@extra-options) + #:user "webid-oidc" + #:group "webid-oidc" + #:directory "/var/log/webid-oidc" + #:environment-variables + `("LANG=C")))) + (stop #~(make-kill-destructor)))))))) + (define %webid-oidc-accounts (list (user-group (name "webid-oidc") (system? #t)) @@ -266,3 +334,14 @@ (service-extension shepherd-root-service-type webid-oidc-hello-shepherd-service))))) + +(define-public webid-oidc-client-service-service-type + (service-type + (name 'webid-oidc-client-service) + (extensions + (list + (service-extension account-service-type + (const %webid-oidc-accounts)) + (service-extension + shepherd-root-service-type + webid-oidc-client-service-shepherd-service))))) diff --git a/man/Makefile.am b/man/Makefile.am index 100d314..5a80f50 100644 --- a/man/Makefile.am +++ b/man/Makefile.am @@ -1,4 +1,4 @@ -dist_man8_MANS = webid-oidc-issuer.man webid-oidc-reverse-proxy.man +dist_man8_MANS = webid-oidc-issuer.man webid-oidc-reverse-proxy.man webid-oidc-client-service.man EXTRA_DIST = ./reset-env @@ -9,3 +9,7 @@ webid-oidc-issuer.man: ../src/scm/webid-oidc/identity-provider.scm ../configure. webid-oidc-reverse-proxy.man: ../src/scm/webid-oidc/reverse-proxy.scm ../configure.ac $(AM_V_GEN) ../pre-inst-env ./reset-env $(HELP2MAN) $(srcdir)/../src/webid-oidc-reverse-proxy > $@-t mv $@-t $(srcdir)/$@ + +webid-oidc-client-service.man: ../src/scm/webid-oidc/client.scm ../configure.ac + $(AM_V_GEN) ../pre-inst-env ./reset-env $(HELP2MAN) $(srcdir)/../src/webid-oidc-client-service > $@-t + mv $@-t $(srcdir)/$@ diff --git a/po/POTFILES.in b/po/POTFILES.in index 0115b93..dffc889 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -12,3 +12,4 @@ src/scm/webid-oidc/authorization-page-unsafe.scm src/scm/webid-oidc/resource-server.scm src/scm/webid-oidc/reverse-proxy.scm src/scm/webid-oidc/hello-world.scm +src/scm/webid-oidc/client.scm @@ -2,7 +2,7 @@ msgid "" msgstr "" "Project-Id-Version: webid-oidc 0.0.0\n" "Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n" -"POT-Creation-Date: 2021-05-10 23:06+0200\n" +"POT-Creation-Date: 2021-05-10 23:11+0200\n" "PO-Revision-Date: 2021-05-10 14:31+0200\n" "Last-Translator: Vivien Kraus <vivien@planete-kraus.eu>\n" "Language-Team: French <vivien@planete-kraus.eu>\n" @@ -740,12 +740,12 @@ msgstr "Attention : génération d'une nouvelle paire de clé." #: src/scm/webid-oidc/identity-provider.scm:147 #: src/scm/webid-oidc/reverse-proxy.scm:124 -#: src/scm/webid-oidc/hello-world.scm:32 +#: src/scm/webid-oidc/hello-world.scm:32 src/scm/webid-oidc/client.scm:606 msgid "command-line|version" msgstr "version" #: src/scm/webid-oidc/identity-provider.scm:149 -#: src/scm/webid-oidc/hello-world.scm:34 +#: src/scm/webid-oidc/hello-world.scm:34 src/scm/webid-oidc/client.scm:608 msgid "comand-line|help" msgstr "aide" @@ -778,17 +778,17 @@ msgid "comand-line|token-endpoint-uri" msgstr "uri-terminal-jeton" #: src/scm/webid-oidc/identity-provider.scm:165 -#: src/scm/webid-oidc/hello-world.scm:36 +#: src/scm/webid-oidc/hello-world.scm:36 src/scm/webid-oidc/client.scm:618 msgid "comand-line|port" msgstr "port" #: src/scm/webid-oidc/identity-provider.scm:167 -#: src/scm/webid-oidc/reverse-proxy.scm:136 +#: src/scm/webid-oidc/reverse-proxy.scm:136 src/scm/webid-oidc/client.scm:620 msgid "comand-line|log-file" msgstr "fichier-journal" #: src/scm/webid-oidc/identity-provider.scm:169 -#: src/scm/webid-oidc/reverse-proxy.scm:138 +#: src/scm/webid-oidc/reverse-proxy.scm:138 src/scm/webid-oidc/client.scm:622 msgid "comand-line|error-file" msgstr "fichier-erreur" @@ -940,7 +940,7 @@ msgstr "" #: src/scm/webid-oidc/identity-provider.scm:262 #: src/scm/webid-oidc/reverse-proxy.scm:207 -#: src/scm/webid-oidc/hello-world.scm:60 +#: src/scm/webid-oidc/hello-world.scm:60 src/scm/webid-oidc/client.scm:684 #, scheme-format msgid "~a version ~a\n" msgstr "~a version ~a\n" @@ -975,11 +975,12 @@ msgstr "Vous devez définir l'URI du terminal de jeton.\n" #: src/scm/webid-oidc/identity-provider.scm:322 #: src/scm/webid-oidc/reverse-proxy.scm:235 -#: src/scm/webid-oidc/hello-world.scm:71 +#: src/scm/webid-oidc/hello-world.scm:71 src/scm/webid-oidc/client.scm:722 msgid "The port should be a number between 0 and 65535.\n" msgstr "Le port doit être un nombre entre 0 et 65535.\n" #: src/scm/webid-oidc/identity-provider.scm:341 +#: src/scm/webid-oidc/client.scm:733 #, scheme-format msgid "~a: Internal server error: ~a\n" msgstr "~a : Erreur interne du serveur : ~a\n" @@ -1305,121 +1306,127 @@ msgstr "" " -p PORT, --port=8080 :\n" " définit le port à lier.\n" -#~ msgid "comand-line|client-id" -#~ msgstr "id-client" +#: src/scm/webid-oidc/client.scm:610 +msgid "comand-line|client-id" +msgstr "id-client" -#~ msgid "comand-line|redirect-uri" -#~ msgstr "uri-redirection" +#: src/scm/webid-oidc/client.scm:612 +msgid "comand-line|redirect-uri" +msgstr "uri-redirection" -#~ msgid "comand-line|client-name" -#~ msgstr "nom-client" +#: src/scm/webid-oidc/client.scm:614 +msgid "comand-line|client-name" +msgstr "nom-client" -#~ msgid "comand-line|client-uri" -#~ msgstr "uri-client" +#: src/scm/webid-oidc/client.scm:616 +msgid "comand-line|client-uri" +msgstr "uri-client" +#: src/scm/webid-oidc/client.scm:637 #, scheme-format -#~ msgid "" -#~ "Usage: ~a [OPTIONS]...\n" -#~ "\n" -#~ "Serve public pages for an application.\n" -#~ "\n" -#~ "Options:\n" -#~ " -h, --help:\n" -#~ " display this help message and exit.\n" -#~ " -v, --version:\n" -#~ " display the version information (~a) and exit.\n" -#~ " -i URI, --client-id=URI:\n" -#~ " set the webid of the client.\n" -#~ " -r FILE, --redirect-uri=URI:\n" -#~ " set the redirection URI where to get the authorization code.\n" -#~ " -n NAME, --client-name=NAME:\n" -#~ " set the name of the application.\n" -#~ " -u URI, --client-uri=URI:\n" -#~ " set the address of the application (informative).\n" -#~ " -p PORT, --port=PORT:\n" -#~ " set the port to bind (instead of 8080).\n" -#~ " -l FILE.log, --log-file=FILE.log:\n" -#~ " dump the standard output to that file.\n" -#~ " -e FILE.err, --error-file=FILE.err:\n" -#~ " dump the standard error to that file.\n" -#~ "\n" -#~ "Environment variables:\n" -#~ "\n" -#~ " LANG: set the locale of the sysadmin-facing interface, for log files\n" -#~ "and command-line interface. It is currently ~a.\n" -#~ "\n" -#~ "Example used in webid-oidc-demo.planete-kraus.eu (except it’s managed\n" -#~ "by shepherd in reality):\n" -#~ "\n" -#~ " export LANG=C\n" -#~ " webid-oidc-client-service \\\n" -#~ " --client-id https://webid-oidc-demo.planete-kraus.eu/example-" -#~ "application#id \\\n" -#~ " --redirect-uri https://webid-oidc-demo.planete-kraus.eu/authorized " -#~ "\\\n" -#~ " --client-name 'Example Solid Application' \\\n" -#~ " --client-uri 'https://webid-oidc.planete-kraus.eu/Running-a-client." -#~ "html#Running-a-client' \\\n" -#~ " --port $PORT\n" -#~ "\n" -#~ "If you find a bug, send a report to ~a.\n" -#~ msgstr "" -#~ "Utilisation : ~a [OPTIONS]...\n" -#~ "\n" -#~ "Sert les pages publiques d’une application.\n" -#~ "\n" -#~ "Options :\n" -#~ " -h, --aide :\n" -#~ " affiche ce message d’aide et quitte.\n" -#~ " -v, --version :\n" -#~ " affiche le numéro de version (~a) et quitte.\n" -#~ " -i URI, --id-client=URI :\n" -#~ " définit le webid du client.\n" -#~ " -r URI, --uri-redirection=URI :\n" -#~ " définit l’URI de redirection où obtenir le code d’autorisation.\n" -#~ " -n NOM, --nom-client=NOM :\n" -#~ " définit le nom de l’application.\n" -#~ " -u URI, --uri-client=URI :\n" -#~ " définit l’adresse de l’application (à titre informatif).\n" -#~ " -p PORT, --port=PORT :\n" -#~ " définit le port à lier (au lieu de 8080).\n" -#~ " -l FICHIER.log, --fichier-journal=FICHIER.log :\n" -#~ " déverser la sortie standard vers ce fichier.\n" -#~ " -e FICHIER.err, --fichier-erreur=FICHIER.err :\n" -#~ " déverser la sortie d’erreur vers ce fichier.\n" -#~ "\n" -#~ "Variables d’environnement :\n" -#~ "\n" -#~ " LANG : définit la locale de l’interface de l’administrateur système,\n" -#~ "pour les fichiers de journaux et l’interface en ligne de\n" -#~ "commande. Elle vaut actuellement ~a.\n" -#~ "\n" -#~ "Exemple utilisé pour webid-oidc-demo.planete-kraus.eu (sauf que le\n" -#~ "service est géré par shepherd en réalité, et les URI sont en\n" -#~ "anglais) :\n" -#~ "\n" -#~ " export LANG=fr_FR.UTF-8\n" -#~ " webid-oidc-client-service \\\n" -#~ " --id-client https://webid-oidc-demo.planete-kraus.eu/application-" -#~ "exemple#id \\\n" -#~ " --uri-redirection https://webid-oidc-demo.planete-kraus.eu/autorisé " -#~ "\\\n" -#~ " --nom-client 'Exemple d’application Solid' \\\n" -#~ " --uri-client 'https://webid-oidc.planete-kraus.eu/Running-a-client." -#~ "html#Running-a-client' \\\n" -#~ " --port $PORT\n" -#~ "\n" -#~ "Si vous trouvez une erreur dans le programme, envoyez-en un rapport à " -#~ "~a.\n" +msgid "" +"Usage: ~a [OPTIONS]...\n" +"\n" +"Serve public pages for an application.\n" +"\n" +"Options:\n" +" -h, --help:\n" +" display this help message and exit.\n" +" -v, --version:\n" +" display the version information (~a) and exit.\n" +" -i URI, --client-id=URI:\n" +" set the webid of the client.\n" +" -r FILE, --redirect-uri=URI:\n" +" set the redirection URI where to get the authorization code.\n" +" -n NAME, --client-name=NAME:\n" +" set the name of the application.\n" +" -u URI, --client-uri=URI:\n" +" set the address of the application (informative).\n" +" -p PORT, --port=PORT:\n" +" set the port to bind (instead of 8080).\n" +" -l FILE.log, --log-file=FILE.log:\n" +" dump the standard output to that file.\n" +" -e FILE.err, --error-file=FILE.err:\n" +" dump the standard error to that file.\n" +"\n" +"Environment variables:\n" +"\n" +" LANG: set the locale of the sysadmin-facing interface, for log files\n" +"and command-line interface. It is currently ~a.\n" +"\n" +"Example used in webid-oidc-demo.planete-kraus.eu (except it’s managed\n" +"by shepherd in reality):\n" +"\n" +" export LANG=C\n" +" webid-oidc-client-service \\\n" +" --client-id https://webid-oidc-demo.planete-kraus.eu/example-" +"application#id \\\n" +" --redirect-uri https://webid-oidc-demo.planete-kraus.eu/authorized \\\n" +" --client-name 'Example Solid Application' \\\n" +" --client-uri 'https://webid-oidc.planete-kraus.eu/Running-a-client." +"html#Running-a-client' \\\n" +" --port $PORT\n" +"\n" +"If you find a bug, send a report to ~a.\n" +msgstr "" +"Utilisation : ~a [OPTIONS]...\n" +"\n" +"Sert les pages publiques d’une application.\n" +"\n" +"Options :\n" +" -h, --aide :\n" +" affiche ce message d’aide et quitte.\n" +" -v, --version :\n" +" affiche le numéro de version (~a) et quitte.\n" +" -i URI, --id-client=URI :\n" +" définit le webid du client.\n" +" -r URI, --uri-redirection=URI :\n" +" définit l’URI de redirection où obtenir le code d’autorisation.\n" +" -n NOM, --nom-client=NOM :\n" +" définit le nom de l’application.\n" +" -u URI, --uri-client=URI :\n" +" définit l’adresse de l’application (à titre informatif).\n" +" -p PORT, --port=PORT :\n" +" définit le port à lier (au lieu de 8080).\n" +" -l FICHIER.log, --fichier-journal=FICHIER.log :\n" +" déverser la sortie standard vers ce fichier.\n" +" -e FICHIER.err, --fichier-erreur=FICHIER.err :\n" +" déverser la sortie d’erreur vers ce fichier.\n" +"\n" +"Variables d’environnement :\n" +"\n" +" LANG : définit la locale de l’interface de l’administrateur système,\n" +"pour les fichiers de journaux et l’interface en ligne de\n" +"commande. Elle vaut actuellement ~a.\n" +"\n" +"Exemple utilisé pour webid-oidc-demo.planete-kraus.eu (sauf que le\n" +"service est géré par shepherd en réalité, et les URI sont en\n" +"anglais) :\n" +"\n" +" export LANG=fr_FR.UTF-8\n" +" webid-oidc-client-service \\\n" +" --id-client https://webid-oidc-demo.planete-kraus.eu/application-" +"exemple#id \\\n" +" --uri-redirection https://webid-oidc-demo.planete-kraus.eu/autorisé " +"\\\n" +" --nom-client 'Exemple d’application Solid' \\\n" +" --uri-client 'https://webid-oidc.planete-kraus.eu/Running-a-client." +"html#Running-a-client' \\\n" +" --port $PORT\n" +"\n" +"Si vous trouvez une erreur dans le programme, envoyez-en un rapport à ~a.\n" -#~ msgid "You need to set the client ID as an URI.\n" -#~ msgstr "Vous devez définir l’identifiant du client comme URI.\n" +#: src/scm/webid-oidc/client.scm:707 +msgid "You need to set the client ID as an URI.\n" +msgstr "Vous devez définir l’identifiant du client comme URI.\n" -#~ msgid "You need to set the redirect URI.\n" -#~ msgstr "Vous devez définir l'URI de redirection.\n" +#: src/scm/webid-oidc/client.scm:711 +msgid "You need to set the redirect URI.\n" +msgstr "Vous devez définir l'URI de redirection.\n" -#~ msgid "The client URI should be an URI.\n" -#~ msgstr "L’URI du client doit être un URI.\n" +#: src/scm/webid-oidc/client.scm:715 +msgid "The client URI should be an URI.\n" +msgstr "L’URI du client doit être un URI.\n" #, scheme-format #~ msgid "~a.\t~a, certified by ~a;\n" diff --git a/po/webid-oidc.pot b/po/webid-oidc.pot index 0564bb9..63927e0 100644 --- a/po/webid-oidc.pot +++ b/po/webid-oidc.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: webid-oidc SNAPSHOT\n" "Report-Msgid-Bugs-To: vivien@planete-kraus.eu\n" -"POT-Creation-Date: 2021-05-10 23:06+0200\n" +"POT-Creation-Date: 2021-05-10 23:11+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" @@ -721,12 +721,12 @@ msgstr "" #: src/scm/webid-oidc/identity-provider.scm:147 #: src/scm/webid-oidc/reverse-proxy.scm:124 -#: src/scm/webid-oidc/hello-world.scm:32 +#: src/scm/webid-oidc/hello-world.scm:32 src/scm/webid-oidc/client.scm:606 msgid "command-line|version" msgstr "" #: src/scm/webid-oidc/identity-provider.scm:149 -#: src/scm/webid-oidc/hello-world.scm:34 +#: src/scm/webid-oidc/hello-world.scm:34 src/scm/webid-oidc/client.scm:608 msgid "comand-line|help" msgstr "" @@ -759,17 +759,17 @@ msgid "comand-line|token-endpoint-uri" msgstr "" #: src/scm/webid-oidc/identity-provider.scm:165 -#: src/scm/webid-oidc/hello-world.scm:36 +#: src/scm/webid-oidc/hello-world.scm:36 src/scm/webid-oidc/client.scm:618 msgid "comand-line|port" msgstr "" #: src/scm/webid-oidc/identity-provider.scm:167 -#: src/scm/webid-oidc/reverse-proxy.scm:136 +#: src/scm/webid-oidc/reverse-proxy.scm:136 src/scm/webid-oidc/client.scm:620 msgid "comand-line|log-file" msgstr "" #: src/scm/webid-oidc/identity-provider.scm:169 -#: src/scm/webid-oidc/reverse-proxy.scm:138 +#: src/scm/webid-oidc/reverse-proxy.scm:138 src/scm/webid-oidc/client.scm:622 msgid "comand-line|error-file" msgstr "" @@ -848,7 +848,7 @@ msgstr "" #: src/scm/webid-oidc/identity-provider.scm:262 #: src/scm/webid-oidc/reverse-proxy.scm:207 -#: src/scm/webid-oidc/hello-world.scm:60 +#: src/scm/webid-oidc/hello-world.scm:60 src/scm/webid-oidc/client.scm:684 #, scheme-format msgid "~a version ~a\n" msgstr "" @@ -883,11 +883,12 @@ msgstr "" #: src/scm/webid-oidc/identity-provider.scm:322 #: src/scm/webid-oidc/reverse-proxy.scm:235 -#: src/scm/webid-oidc/hello-world.scm:71 +#: src/scm/webid-oidc/hello-world.scm:71 src/scm/webid-oidc/client.scm:722 msgid "The port should be a number between 0 and 65535.\n" msgstr "" #: src/scm/webid-oidc/identity-provider.scm:341 +#: src/scm/webid-oidc/client.scm:733 #, scheme-format msgid "~a: Internal server error: ~a\n" msgstr "" @@ -1137,3 +1138,79 @@ msgid "" " -p PORT, --port=8080:\n" " set the port to bind.\n" msgstr "" + +#: src/scm/webid-oidc/client.scm:610 +msgid "comand-line|client-id" +msgstr "" + +#: src/scm/webid-oidc/client.scm:612 +msgid "comand-line|redirect-uri" +msgstr "" + +#: src/scm/webid-oidc/client.scm:614 +msgid "comand-line|client-name" +msgstr "" + +#: src/scm/webid-oidc/client.scm:616 +msgid "comand-line|client-uri" +msgstr "" + +#: src/scm/webid-oidc/client.scm:637 +#, scheme-format +msgid "" +"Usage: ~a [OPTIONS]...\n" +"\n" +"Serve public pages for an application.\n" +"\n" +"Options:\n" +" -h, --help:\n" +" display this help message and exit.\n" +" -v, --version:\n" +" display the version information (~a) and exit.\n" +" -i URI, --client-id=URI:\n" +" set the webid of the client.\n" +" -r FILE, --redirect-uri=URI:\n" +" set the redirection URI where to get the authorization code.\n" +" -n NAME, --client-name=NAME:\n" +" set the name of the application.\n" +" -u URI, --client-uri=URI:\n" +" set the address of the application (informative).\n" +" -p PORT, --port=PORT:\n" +" set the port to bind (instead of 8080).\n" +" -l FILE.log, --log-file=FILE.log:\n" +" dump the standard output to that file.\n" +" -e FILE.err, --error-file=FILE.err:\n" +" dump the standard error to that file.\n" +"\n" +"Environment variables:\n" +"\n" +" LANG: set the locale of the sysadmin-facing interface, for log files\n" +"and command-line interface. It is currently ~a.\n" +"\n" +"Example used in webid-oidc-demo.planete-kraus.eu (except it’s managed\n" +"by shepherd in reality):\n" +"\n" +" export LANG=C\n" +" webid-oidc-client-service \\\n" +" --client-id https://webid-oidc-demo.planete-kraus.eu/example-" +"application#id \\\n" +" --redirect-uri https://webid-oidc-demo.planete-kraus.eu/authorized \\\n" +" --client-name 'Example Solid Application' \\\n" +" --client-uri 'https://webid-oidc.planete-kraus.eu/Running-a-client." +"html#Running-a-client' \\\n" +" --port $PORT\n" +"\n" +"If you find a bug, send a report to ~a.\n" +msgstr "" + +#: src/scm/webid-oidc/client.scm:707 +msgid "You need to set the client ID as an URI.\n" +msgstr "" + +#: src/scm/webid-oidc/client.scm:711 +msgid "You need to set the redirect URI.\n" +msgstr "" + +#: src/scm/webid-oidc/client.scm:715 +msgid "The client URI should be an URI.\n" +msgstr "" diff --git a/src/Makefile.am b/src/Makefile.am index d990641..527f201 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,6 +1,6 @@ lib_LTLIBRARIES += %reldir%/libwebidoidc.la -dist_bin_SCRIPTS += %reldir%/webid-oidc-issuer %reldir%/webid-oidc-reverse-proxy %reldir%/webid-oidc-hello +dist_bin_SCRIPTS += %reldir%/webid-oidc-issuer %reldir%/webid-oidc-reverse-proxy %reldir%/webid-oidc-hello %reldir%/webid-oidc-client-service AM_CPPFLAGS += -I %reldir% -I $(srcdir)/%reldir% diff --git a/src/scm/webid-oidc/client.scm b/src/scm/webid-oidc/client.scm index e948981..4b12d67 100644 --- a/src/scm/webid-oidc/client.scm +++ b/src/scm/webid-oidc/client.scm @@ -7,15 +7,21 @@ #:use-module (webid-oidc jwk) #:use-module ((webid-oidc stubs) #:prefix stubs:) #:use-module ((webid-oidc refresh-token) #:prefix refresh:) + #:use-module ((webid-oidc config) #:prefix cfg:) #:use-module (web uri) #:use-module (web client) + #:use-module (web request) #:use-module (web response) #:use-module (web server) #:use-module (web http) #:use-module (ice-9 optargs) #:use-module (ice-9 receive) #:use-module (srfi srfi-19) - #:use-module (rnrs bytevectors)) + #:use-module (rnrs bytevectors) + #:use-module (ice-9 i18n) + #:use-module (ice-9 getopt-long) + #:use-module (ice-9 suspendable-ports) + #:use-module (sxml simple)) (define*-public (authorize host-or-webid #:key @@ -260,7 +266,7 @@ (when (thunk? dir) (set! dir (dir))) (let ((other-profiles (list-profiles #:dir dir))) - (call-with-output-file* + (stubs:call-with-output-file* (string-append dir "/profiles~") (lambda (port) (write @@ -485,3 +491,254 @@ (parse-args uri 'GET '() '() args)) (lambda (uri . args) (parse-http-request-args uri args))) + +(define*-public (serve-application id redirect-uri + #:key + (client-name "Example application") + (client-uri "https://webid-oidc-demo.planete-kraus.eu")) + (when (string? id) + (set! id (string->uri id))) + (when (string? redirect-uri) + (set! redirect-uri (string->uri redirect-uri))) + (when (string? client-uri) + (set! client-uri (string->uri client-uri))) + (let ((manifest + (format #f + "@prefix solid: <http://www.w3.org/ns/solid/terms#> . + +<~a> solid:oidcRegistration \"\"\"{ + \"client_id\" : \"~a\", + \"redirect_uris\" : [\"~a\"], + \"client_name\" : \"~a\", + \"client_uri\" : \"~a\", + \"grant_types\" : [\"refresh_token\", \"authorization_code\"], + \"response_types\" : [\"code\"] +}\"\"\" . +" + (uri->string id) + (uri->string id) + (uri->string redirect-uri) + client-name + (uri->string id)))) + (lambda (request request-body) + (let ((uri (request-uri request))) + (cond + ((equal? (uri-path uri) (uri-path id)) + (values + (build-response + #:headers `((content-type text/turtle) + (etag . (,(stubs:hash 'SHA-256 manifest) . #t)))) + manifest)) + ((equal? (uri-path uri) (uri-path redirect-uri)) + (let ((query-args + (map + (lambda (key=value) + (let ((splits + (map uri-decode (string-split key=value #\=)))) + (if (or (null? splits) (null? (cdr splits))) + splits + (cons (string->symbol (car splits)) (cdr splits))))) + (string-split (uri-query uri) #\&)))) + (let ((code (assq-ref query-args 'code))) + (if code + (values + (build-response + #: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 "en")) + (head + (title "Authorization")) + (body + (p "You have been authorized. Please paste the following code in the application:") + (p (strong ,code))))))))) + (values + (build-response + #:code 400 + #:reason-phrase "Invalid Request" + #: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 "en")) + (head + (title "Error")) + (body + (p "Your identity provider did not authorize you. :(")))))))))))) + (else + (values + (build-response + #:code 404 + #: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 "en")) + (head + (title "Not Found")) + (body + (p "This page does not exist on the server.")))))))))))))) + +(define (G_ text) + (let ((out (gettext text))) + (if (string=? out text) + ;; No translation, disambiguate + (car (reverse (string-split text #\|))) + out))) + +(define-public (main-server) + (setlocale LC_ALL "") + (bindtextdomain cfg:package cfg:localedir) + (textdomain cfg:package) + (let ((version-sym + (string->symbol (G_ "command-line|version"))) + (help-sym + (string->symbol (G_ "comand-line|help"))) + (client-id-sym + (string->symbol (G_ "comand-line|client-id"))) + (redirect-uri-sym + (string->symbol (G_ "comand-line|redirect-uri"))) + (client-name-sym + (string->symbol (G_ "comand-line|client-name"))) + (client-uri-sym + (string->symbol (G_ "comand-line|client-uri"))) + (port-sym + (string->symbol (G_ "comand-line|port"))) + (log-file-sym + (string->symbol (G_ "comand-line|log-file"))) + (error-file-sym + (string->symbol (G_ "comand-line|error-file")))) + (let ((options + (let ((option-spec + `((,version-sym (single-char #\v) (value #f)) + (,help-sym (single-char #\h) (value #f)) + (,client-id-sym (single-char #\i) (value #t)) + (,redirect-uri-sym (single-char #\r) (value #t)) + (,client-name-sym (single-char #\n) (value #t)) + (,client-uri-sym (single-char #\u) (value #t)) + (,port-sym (single-char #\p) (value #t)) + (,log-file-sym (single-char #\l) (value #t)) + (,error-file-sym (single-char #\e) (value #t))))) + (getopt-long (command-line) option-spec)))) + (cond + ((option-ref options help-sym #f) + (format #t (G_ "Usage: ~a [OPTIONS]... + +Serve public pages for an application. + +Options: + -h, --help: + display this help message and exit. + -v, --version: + display the version information (~a) and exit. + -i URI, --client-id=URI: + set the webid of the client. + -r FILE, --redirect-uri=URI: + set the redirection URI where to get the authorization code. + -n NAME, --client-name=NAME: + set the name of the application. + -u URI, --client-uri=URI: + set the address of the application (informative). + -p PORT, --port=PORT: + set the port to bind (instead of 8080). + -l FILE.log, --log-file=FILE.log: + dump the standard output to that file. + -e FILE.err, --error-file=FILE.err: + dump the standard error to that file. + +Environment variables: + + LANG: set the locale of the sysadmin-facing interface, for log files +and command-line interface. It is currently ~a. + +Example used in webid-oidc-demo.planete-kraus.eu (except it’s managed +by shepherd in reality): + + export LANG=C + webid-oidc-client-service \\ + --client-id https://webid-oidc-demo.planete-kraus.eu/example-application#id \\ + --redirect-uri https://webid-oidc-demo.planete-kraus.eu/authorized \\ + --client-name 'Example Solid Application' \\ + --client-uri 'https://webid-oidc.planete-kraus.eu/Running-a-client.html#Running-a-client' \\ + --port $PORT + +If you find a bug, send a report to ~a. +") + (car (command-line)) + cfg:version + (or (getenv "LANG") "") + cfg:package-bugreport)) + ((option-ref options version-sym #f) + (format #t (G_ "~a version ~a\n") + cfg:package cfg:version)) + (else + (let ((client-id (option-ref options client-id-sym #f)) + (redirect-uri (option-ref options redirect-uri-sym #f)) + (client-name (option-ref options client-name-sym "Example Solid App")) + (client-uri + (option-ref options client-uri-sym + "https://webid-oidc.planete-kraus.eu/Running-a-client.html#Running-a-client")) + (port-string + (option-ref options port-sym "8080")) + (log-file-string + (option-ref options log-file-sym #f)) + (error-file-string + (option-ref options error-file-sym #f))) + (when log-file-string + (set-current-output-port (stubs:open-output-file* log-file-string)) + (setvbuf (current-output-port) 'none)) + (when error-file-string + (set-current-error-port (stubs:open-output-file* error-file-string)) + (setvbuf (current-error-port) 'none)) + (unless (and client-id (string->uri client-id)) + (format (current-error-port) + (G_ "You need to set the client ID as an URI.\n")) + (exit 1)) + (unless (and redirect-uri (string->uri redirect-uri)) + (format (current-error-port) + (G_ "You need to set the redirect URI.\n")) + (exit 2)) + (unless (string->uri client-uri) + (format (current-error-port) + (G_ "The client URI should be an URI.\n")) + (exit 3)) + (unless (and (string->number port-string) + (integer? (string->number port-string)) + (>= (string->number port-string) 0) + (<= (string->number port-string) 65535)) + (format (current-error-port) + (G_ "The port should be a number between 0 and 65535.\n")) + (exit 1)) + (let ((handler + (serve-application client-id redirect-uri + #:client-name client-name + #:client-uri client-uri))) + (let ((handler-with-log + (lambda (request request-body) + (with-exception-handler + (lambda (error) + (format (current-error-port) + (G_ "~a: Internal server error: ~a\n") + (date->string (time-utc->date (current-time))) + (error->str error)) + (values + (build-response #:code 500 + #:reason-phrase "Internal Server Error") + "Sorry, there was an error.")) + (lambda () + (handler request request-body)) + #:unwind? #t)))) + (install-suspendable-ports!) + (run-server handler 'http + (list #:port (string->number port-string))))))))))) diff --git a/src/webid-oidc-client-service b/src/webid-oidc-client-service new file mode 100755 index 0000000..1139abd --- /dev/null +++ b/src/webid-oidc-client-service @@ -0,0 +1,7 @@ +#!/usr/local/bin/guile \ +--no-auto-compile -s +!# + +(use-modules (webid-oidc client)) + +(main-server) |