summaryrefslogtreecommitdiff
path: root/tests/client-workflow.scm
diff options
context:
space:
mode:
Diffstat (limited to 'tests/client-workflow.scm')
-rw-r--r--tests/client-workflow.scm140
1 files changed, 140 insertions, 0 deletions
diff --git a/tests/client-workflow.scm b/tests/client-workflow.scm
new file mode 100644
index 0000000..04a4455
--- /dev/null
+++ b/tests/client-workflow.scm
@@ -0,0 +1,140 @@
+;; webid-oidc, 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/>.
+
+(use-modules ((webid-oidc client) #:prefix client:)
+ ((webid-oidc client accounts) #:prefix client:)
+ ((webid-oidc jwk) #:prefix jwk:)
+ (webid-oidc testing)
+ ((webid-oidc stubs) #:prefix stubs:)
+ ((webid-oidc refresh-token) #:prefix refresh:)
+ ((webid-oidc simulation) #:prefix sim:)
+ ((webid-oidc parameters) #:prefix p:)
+ (web uri)
+ (web request)
+ (web response)
+ (srfi srfi-19)
+ (srfi srfi-26)
+ (ice-9 optargs)
+ (ice-9 receive)
+ (ice-9 hash-table)
+ (ice-9 match))
+
+;; In this example, a user firsts requests an account, then logs in
+;; with a refresh token, then logs out, but we can still revive per
+;; account, then the refresh token gets banned.
+
+(define (display-log simulation)
+ (format (current-error-port) "Log:\n")
+ (for-each
+ (match-lambda
+ ((request request-body response response-body)
+ (format (current-error-port) "~s ~s (~s): ~s ~s\n"
+ (request-method request)
+ (uri->string (request-uri request))
+ request-body
+ (response-code response)
+ (response-reason-phrase response))))
+ (sim:simulation-scroll-log! simulation))
+ (exit 42))
+
+(with-test-environment
+ "client-workflow"
+ (lambda ()
+ (let ((simulation (sim:make-simulation)))
+ (sim:add-server! simulation
+ (string->uri "https://server@client-workflow.scm")
+ (string->uri "https://server@client-workflow.scm/alice#me"))
+ (sim:add-client! simulation
+ (string->uri "https://client@client-workflow.scm")
+ (string->uri "https://client@client-workflow.scm/id")
+ (string->uri "https://client@client-workflow.scm/authorized")
+ "Client workflow test"
+ (string->uri "https://client@client-workflow.scm/about"))
+ (let ((client (client:make-client
+ (string->uri "https://client@client-workflow.scm/id")
+ (jwk:generate-key #:n-size 2048)
+ (string->uri "https://client@client-workflow.scm/authorized"))))
+ (parameterize ((p:current-date 0)
+ (client:authorization-process
+ (lambda* (uri #:key issuer)
+ (sim:grant-authorization simulation uri))))
+ (receive (response response-body)
+ (let ((handler
+ (client:request client #f
+ (string->uri "https://server@client-workflow.scm")
+ #:http-request (cute sim:request simulation <...>))))
+ (handler (build-request (string->uri "https://server@client-workflow.scm/"))
+ #f))
+ (unless (eqv? (response-code response) 200)
+ ;; Only Alice can read that resource.
+ (exit 3)))
+ (match (sim:simulation-scroll-log! simulation)
+ ;; 1. The client gets the oidc configuration of the
+ ;; server.
+
+ ;; 2. The browser gets redirected to the authorization
+ ;; URI and POSTs the authorization form. The server makes
+ ;; a request to the client ID, which replies first.
+
+ ;; 3. The authorization request completes.
+
+ ;; 4. The client exchanges the authorization code for a
+ ;; refresh token.
+
+ ;; 5. and 6. The client decodes the ID token and requests
+ ;; the server keys.
+
+ ;; 7. and 8. While the client is waiting for the final response to
+ ;; complete, the server checks the access token validity by
+ ;; querying the identity provider for its key.
+
+ ;; 9. The client sends the signed request to the / URI of
+ ;; the server.
+ (((get-oidc-config-request _ get-oidc-config-response _)
+ (get-client-id-request _ get-client-id-response _)
+ (authorization-request _ authorization-response _)
+ (token-request _ token-response _)
+ _ _ ;; the client gets the key
+ _ _ ;; the resource server gets the key
+ (final-request _ final-response _))
+ (unless
+ (and
+ ;; 1. Get the authorization endpoint.
+ (equal? (request-uri get-oidc-config-request)
+ (string->uri "https://server@client-workflow.scm/.well-known/openid-configuration"))
+ (eqv? (response-code get-oidc-config-response) 200)
+ ;; 2. The server checks the client ID.
+ (equal? (request-uri get-client-id-request)
+ (string->uri "https://client@client-workflow.scm/id"))
+ (eqv? (response-code get-client-id-response) 200)
+ ;; 3. The authorization request completes.
+ (string-prefix?
+ "https://server@client-workflow.scm/authorize?"
+ (uri->string (request-uri authorization-request)))
+ (eq? (request-method authorization-request) 'POST)
+ (eqv? (response-code authorization-response) 302)
+ (string-prefix?
+ "https://client@client-workflow.scm/authorized?"
+ (uri->string (response-location authorization-response)))
+ ;; 4. Token negociation.
+ (equal? (request-uri token-request)
+ (string->uri "https://server@client-workflow.scm/token"))
+ (eqv? (response-code token-response) 200)
+ ;; 5. The final request.
+ (equal? (request-uri final-request)
+ (string->uri "https://server@client-workflow.scm/"))
+ (eqv? (response-code final-response) 200))
+ (exit 4)))))))))