summaryrefslogtreecommitdiff
path: root/src/scm/webid-oidc/resource-server.scm
diff options
context:
space:
mode:
Diffstat (limited to 'src/scm/webid-oidc/resource-server.scm')
-rw-r--r--src/scm/webid-oidc/resource-server.scm175
1 files changed, 175 insertions, 0 deletions
diff --git a/src/scm/webid-oidc/resource-server.scm b/src/scm/webid-oidc/resource-server.scm
index cef6a0c..c69bc51 100644
--- a/src/scm/webid-oidc/resource-server.scm
+++ b/src/scm/webid-oidc/resource-server.scm
@@ -4,6 +4,12 @@
#:use-module (webid-oidc provider-confirmation)
#:use-module (webid-oidc jwk)
#:use-module (webid-oidc dpop-proof)
+ #:use-module (webid-oidc server create)
+ #:use-module (webid-oidc server read)
+ #:use-module (webid-oidc server update)
+ #:use-module (webid-oidc server delete)
+ #:use-module (webid-oidc server precondition)
+ #:use-module (webid-oidc http-link)
#:use-module ((webid-oidc config) #:prefix cfg:)
#:use-module (webid-oidc jti)
#:use-module (webid-oidc access-token)
@@ -17,6 +23,7 @@
#:use-module (ice-9 i18n)
#:use-module (ice-9 getopt-long)
#:use-module (ice-9 suspendable-ports)
+ #:use-module (ice-9 control)
#:use-module (sxml simple)
#:use-module (srfi srfi-19))
@@ -84,3 +91,171 @@
(confirm-provider subject issuer #:http-get http-get)
subject)))
#:unwind? #t))))))
+
+(define (handle-errors f g)
+ (call/ec
+ (lambda (do-return)
+ (define (return . args)
+ (apply do-return args))
+ (with-exception-handler
+ (lambda (error)
+ (g return error))
+ (lambda ()
+ (f return))))))
+
+(define*-public (make-resource-server
+ #:key
+ (server-uri #f)
+ (owner #f)
+ (authenticator #f)
+ (current-time current-time)
+ (http-get http-get))
+ (unless owner
+ (error "The owner is not defined."))
+ (declare-link-header!)
+ (unless authenticator
+ (set! authenticator
+ (make-authenticator (make-jti-list)
+ #:server-uri server-uri
+ #:current-time current-time
+ #:http-get http-get)))
+ (lambda (request request-body)
+ (let ((user (authenticator request request-body)))
+ (handle-errors
+ (lambda (return)
+ (let ((method (request-method request)))
+ (case method
+ ((GET HEAD OPTIONS)
+ (receive (headers content)
+ (read server-uri owner user
+ (uri-path (request-uri request))
+ #:http-get http-get)
+ (with-exception-handler
+ (lambda (error)
+ (return
+ (build-response
+ #:headers headers)
+ (if (eq? method 'GET)
+ content
+ "")))
+ (lambda ()
+ (unless (or (request-if-match request)
+ (request-if-none-match request))
+ ;; Act as if the precondition failed
+ (raise-exception
+ (make-precondition-failed
+ (uri-path (request-uri request))
+ (request-if-match request)
+ (request-if-none-match request)
+ (car (assq-ref headers 'etag)))))
+ (check-precondition
+ (uri-path (request-uri request))
+ (request-if-match request)
+ (request-if-none-match request)
+ (car (assq-ref headers 'etag)))
+ (return
+ (build-response
+ #:code 304
+ #:reason-phrase "Not Modified"
+ #:headers headers)
+ "")))))
+ ((PUT)
+ (return
+ (build-response
+ #:headers
+ `((etag . (,(update server-uri owner user
+ (uri-path (request-uri request))
+ (request-if-match request)
+ (request-if-none-match request)
+ (request-content-type request)
+ request-body
+ #:http-get http-get)
+ . #f))))
+ ""))
+ ((POST)
+ (let ((types
+ (map car
+ (filter
+ (lambda (link)
+ (equal? (assq-ref link 'rel) "type"))
+ (request-links request)))))
+ (return
+ (build-response
+ #:headers
+ `((location . ,(create server-uri owner user
+ (uri-path (request-uri request))
+ types
+ (assq-ref (request-headers request) 'slug)
+ (request-content-type request)
+ request-body
+ #:http-get http-get))))
+ "")))
+ ((DELETE)
+ (delete server-uri owner user
+ (uri-path (request-uri request))
+ (request-if-match request)
+ (request-if-none-match request)
+ #:http-get http-get)
+ (return
+ (build-response)
+ "")))))
+ (lambda (return error)
+ (if (cannot-fetch-group? error)
+ (format (current-error-port) (G_ "Warning: ~a\n")
+ (error->str error))
+ (begin
+ (format (current-error-port) (G_ "Error: ~a\n")
+ (error->str error))
+ (cond
+ ((uri-slash-semantics-error? error)
+ (return
+ (build-response
+ #:code 301
+ #:reason-phrase "Found"
+ #:headers
+ `((location
+ . ,(build-uri
+ (uri-scheme server-uri)
+ #:userinfo (uri-userinfo server-uri)
+ #:host (uri-host server-uri)
+ #:port (uri-port server-uri)
+ #:path (uri-slash-semantics-error-expected-path error)))))
+ ""))
+ ((or (path-not-found? error)
+ (auxiliary-resource-absent? error)
+ (forbidden? error))
+ (if user
+ ;; That’s a forbidden
+ (return
+ (build-response #:code 403 #:reason-phrase "Forbidden")
+ "")
+ (return
+ (build-response #:code 401 #:reason-phrase "Unauthorized"
+ #:headers `((www-authenticate . ((DPoP)))))
+ "")))
+ ((or (cannot-delete-root? error))
+ (return
+ (build-response
+ #:code 405
+ #:reason-phrase "Method Not Allowed")
+ ""))
+ ((or (container-not-empty? error)
+ (incorrect-containment-triples? error)
+ (path-is-auxiliary? error))
+ (return
+ (build-response
+ #:code 409
+ #:reason-phrase "Conflict")
+ ""))
+ ((unsupported-media-type? error)
+ (return
+ (build-response
+ #:code 415
+ #:reason-phrase "Unsupported Media Type")
+ ""))
+ ((precondition-failed? error)
+ (return
+ (build-response
+ #:code 412
+ #:reason-phrase "Precondition Failed")
+ ""))))))))))