From f468808646a7bb8733f2f912c13c6bd166277193 Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Thu, 11 Nov 2021 16:08:51 +0000 Subject: Client API: also bind the account class. --- src/client/Disfluid-0.h | 143 ++++++++++++++++++++++++ src/client/disfluid-0-custom.vala | 4 + src/client/libwebidoidc-client.c | 164 +++++++++++++++++++++++++++- src/scm/webid-oidc/client/reverse-stubs.scm | 56 ++++++++++ 4 files changed, 361 insertions(+), 6 deletions(-) diff --git a/src/client/Disfluid-0.h b/src/client/Disfluid-0.h index 1344836..b4833c4 100644 --- a/src/client/Disfluid-0.h +++ b/src/client/Disfluid-0.h @@ -122,4 +122,147 @@ size_t disfluid_client_get_key_pair (const DisfluidClient * client, const DisfluidApi * api, size_t start, size_t max, char *jwk); +/** + * DisfluidAccount: + * + * An accounts is an ID, issuer, a key pair, and some optional tokens + * (ID, access and refresh tokens). + */ +struct DisfluidAccount; +typedef struct DisfluidAccount DisfluidAccount; + +/** + * disfluid_api_make_account_full: + * @api: the context loaded with @disfluid_init. + * @account: (out) (transfer full): where to store the allocated account. + * @subject: the URI serving the webid. + * @issuer: the identity provider URI. + * @key_pair: the key pair encoded as a JWK. + * @id_token_header: (nullable): the ID token header, or NULL. + * @id_token: (nullable): the ID token payload, or NULL. + * @access_token: (nullable): the encoded access token, or NULL. + * @refresh_token: (nullable): the refresh token, or NULL. + * + * Create a new account. + */ +void disfluid_api_make_account_full (const DisfluidApi * api, + DisfluidAccount ** account, + const char *subject, + const char *issuer, + const char *key_pair, + const char *id_token_header, + const char *id_token, + const char *access_token, + const char *refresh_token); + +/** + * disfluid_account_free: + * @account: the account to free. + * + * Delete @account. + */ +void disfluid_account_free (DisfluidAccount * account); + +/** + * disfluid_account_get_subject: + * @account: the account whose subject to lookup. + * @api: the context API. + * @start: how many URL prefix bytes to skip. + * @max: how many URL bytes to copy after the skipped prefix. + * @subject: (array length=max) (element-type char): where to copy the URL bytes. + * Returns: the total number of bytes in the URL. + */ +size_t disfluid_account_get_subject (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, char *subject); + +/** + * disfluid_account_get_issuer: + * @account: the account whose issuer to lookup. + * @api: the context API. + * @start: how many URL prefix bytes to skip. + * @max: how many URL bytes to copy after the skipped prefix. + * @issuer: (array length=max) (element-type char): where to copy the URL bytes. + * Returns: the total number of bytes in the URL. + */ +size_t disfluid_account_get_issuer (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, char *issuer); + +/** + * disfluid_account_get_key_pair: + * @account: the account whose key pair to dump. + * @api: the context API. + * @start: how many JWK prefix bytes to skip. + * @max: how many JWK bytes to copy after the skipped prefix. + * @jwk: (array length=max) (element-type char): where to copy the JWK bytes. + * Returns: the total number of bytes in the JWK. + */ +size_t disfluid_account_get_key_pair (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, char *jwk); + +/** + * disfluid_account_get_id_token_header: + * @account: the account whose ID token to lookup. + * @api: the context API. + * @start: how many JSON prefix bytes to skip. + * @max: how many JSON bytes to copy after the skipped prefix. + * @header: (array length=max) (element-type char): where to copy the JSON bytes. + * Returns: the total number of bytes in the JSON. + * + * If the account does not have a valid ID token, 0 is returned. + */ +size_t disfluid_account_get_id_token_header (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, + char *header); + +/** + * disfluid_account_get_id_token: + * @account: the account whose ID token to lookup. + * @api: the context API. + * @start: how many JSON prefix bytes to skip. + * @max: how many JSON bytes to copy after the skipped prefix. + * @token: (array length=max) (element-type char): where to copy the JSON bytes. + * Returns: the total number of bytes in the JSON. + * + * If the account does not have a valid ID token, 0 is returned. + */ +size_t disfluid_account_get_id_token (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, char *token); + +/** + * disfluid_account_get_access_token: + * @account: the account whose access token to lookup. + * @api: the context API. + * @start: how many JWT prefix bytes to skip. + * @max: how many JWT bytes to copy after the skipped prefix. + * @token: (array length=max) (element-type char): where to copy the JWT bytes. + * Returns: the total number of bytes in the JWT. + * + * If the account does not have a valid access token, 0 is returned. + */ +size_t disfluid_account_get_access_token (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, + char *token); + +/** + * disfluid_account_get_refresh_token: + * @account: the account whose refresh token to lookup. + * @api: the context API. + * @start: how many prefix bytes to skip. + * @max: how many bytes to copy after the skipped prefix. + * @token: (array length=max) (element-type char): where to copy the refresh token bytes. + * Returns: the total number of bytes in the refresh token. + * + * If the account does not have a valid refresh token, 0 is returned. + */ +size_t disfluid_account_get_refresh_token (const DisfluidAccount * account, + const DisfluidApi * api, + size_t start, size_t max, + char *token); + #endif diff --git a/src/client/disfluid-0-custom.vala b/src/client/disfluid-0-custom.vala index 295c67c..b3227ad 100644 --- a/src/client/disfluid-0-custom.vala +++ b/src/client/disfluid-0-custom.vala @@ -18,4 +18,8 @@ namespace Disfluid { [CCode (free_function = "disfluid_client_free")] [Compact] public class Client { } + + [CCode (free_function = "disfluid_account_free")] + [Compact] + public class Account { } } \ No newline at end of file diff --git a/src/client/libwebidoidc-client.c b/src/client/libwebidoidc-client.c index fbe2343..46deecc 100644 --- a/src/client/libwebidoidc-client.c +++ b/src/client/libwebidoidc-client.c @@ -24,6 +24,14 @@ struct DisfluidApi SCM scm_get_client_id; SCM scm_get_key_pair; SCM scm_get_redirect_uri; + SCM scm_make_account_full; + SCM scm_get_account_subject; + SCM scm_get_account_issuer; + SCM scm_get_account_key_pair; + SCM scm_get_account_id_token_header; + SCM scm_get_account_id_token; + SCM scm_get_account_access_token; + SCM scm_get_account_refresh_token; }; struct user_code @@ -45,6 +53,29 @@ inner_guile (void *data) scm_c_public_ref ("webid-oidc client reverse-stubs", "get-key-pair"); api.scm_get_redirect_uri = scm_c_public_ref ("webid-oidc client reverse-stubs", "get-redirect-uri"); + api.scm_make_account_full = + scm_c_public_ref ("webid-oidc client reverse-stubs", "make-account-full"); + api.scm_get_account_subject = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-subject"); + api.scm_get_account_issuer = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-issuer"); + api.scm_get_account_key_pair = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-key-pair"); + api.scm_get_account_id_token_header = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-id-token-header"); + api.scm_get_account_id_token = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-id-token"); + api.scm_get_account_access_token = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-access-token"); + api.scm_get_account_refresh_token = + scm_c_public_ref ("webid-oidc client reverse-stubs", + "get-account-refresh-token"); return user->func (&api, user->data); } @@ -63,10 +94,10 @@ struct DisfluidClient }; void -disfluid_client_make (const struct DisfluidApi *api, - struct DisfluidClient **client, - const char *client_id, - const char *redirect_uri, const char *jwk) +disfluid_api_make_client (const struct DisfluidApi *api, + struct DisfluidClient **client, + const char *client_id, + const char *redirect_uri, const char *jwk) { SCM scm_client_id = scm_from_utf8_string (client_id); SCM scm_redirect_uri = scm_from_utf8_string (redirect_uri); @@ -100,8 +131,12 @@ copy_scm_string (SCM string, size_t start, size_t max, char *dest) { size_t total_length = 0; scm_dynwind_begin (0); - char *all_bytes = scm_to_utf8_stringn (string, &total_length); - scm_dynwind_free (all_bytes); + char *all_bytes = NULL; + if (scm_is_true (string)) + { + all_bytes = scm_to_utf8_stringn (string, &total_length); + scm_dynwind_free (all_bytes); + } const size_t requested_length = max; const size_t available_length = total_length - start; size_t copied_length = requested_length; @@ -145,3 +180,120 @@ disfluid_client_get_redirect_uri (const struct DisfluidClient *client, SCM scm_uri = scm_call_1 (api->scm_get_redirect_uri, client->object); return copy_scm_string (scm_uri, start, max, redirect_uri); } + +struct DisfluidAccount +{ + SCM object; +}; + +void +disfluid_api_make_account (const struct DisfluidApi *api, + struct DisfluidAccount **account, + const char *subject, + const char *issuer, + const char *key_pair, + const char *id_token_header, + const char *id_token, + const char *access_token, + const char *refresh_token) +{ + SCM scm_subject = scm_from_utf8_string (subject); + SCM scm_issuer = scm_from_utf8_string (issuer); + SCM scm_key_pair = scm_from_utf8_string (key_pair); + SCM scm_id_token_header = SCM_BOOL_F; + SCM scm_id_token = SCM_BOOL_F; + SCM scm_access_token = SCM_BOOL_F; + SCM scm_refresh_token = SCM_BOOL_F; + if (id_token_header) + { + scm_id_token_header = scm_from_utf8_string (id_token_header); + } + if (id_token) + { + scm_id_token = scm_from_utf8_string (id_token); + } + if (access_token) + { + scm_access_token = scm_from_utf8_string (access_token); + } + if (refresh_token) + { + scm_refresh_token = scm_from_utf8_string (refresh_token); + } +} + +void +disfluid_account_free (struct DisfluidAccount *account) +{ + if (account) + { + scm_gc_unprotect_object (account->object); + } + free (account); +} + +size_t +disfluid_account_get_subject (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *subject) +{ + SCM scm_id = scm_call_1 (api->scm_get_account_subject, account->object); + return copy_scm_string (scm_id, start, max, subject); +} + +size_t +disfluid_account_get_issuer (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *issuer) +{ + SCM scm_id = scm_call_1 (api->scm_get_account_issuer, account->object); + return copy_scm_string (scm_id, start, max, issuer); +} + +size_t +disfluid_account_get_key_pair (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *jwk) +{ + SCM scm_id = scm_call_1 (api->scm_get_account_key_pair, account->object); + return copy_scm_string (scm_id, start, max, jwk); +} + +size_t +disfluid_account_get_id_token_header (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *header) +{ + SCM scm_id = + scm_call_1 (api->scm_get_account_id_token_header, account->object); + return copy_scm_string (scm_id, start, max, header); +} + +size_t +disfluid_account_get_id_token (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *token) +{ + SCM scm_id = scm_call_1 (api->scm_get_account_id_token, account->object); + return copy_scm_string (scm_id, start, max, token); +} + +size_t +disfluid_account_get_access_token (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *token) +{ + SCM scm_id = + scm_call_1 (api->scm_get_account_access_token, account->object); + return copy_scm_string (scm_id, start, max, token); +} + +size_t +disfluid_account_get_refresh_token (const struct DisfluidAccount *account, + const struct DisfluidApi *api, + size_t start, size_t max, char *token) +{ + SCM scm_id = + scm_call_1 (api->scm_get_account_refresh_token, account->object); + return copy_scm_string (scm_id, start, max, token); +} diff --git a/src/scm/webid-oidc/client/reverse-stubs.scm b/src/scm/webid-oidc/client/reverse-stubs.scm index faecf83..a87eb68 100644 --- a/src/scm/webid-oidc/client/reverse-stubs.scm +++ b/src/scm/webid-oidc/client/reverse-stubs.scm @@ -19,6 +19,7 @@ #:use-module (webid-oidc client accounts) #:use-module (webid-oidc client application) #:use-module (webid-oidc jwk) + #:use-module (webid-oidc oidc-id-token) #:use-module ((webid-oidc stubs) #:prefix stubs:) #:duplicates (merge-generics) #:declarative? #t @@ -28,6 +29,15 @@ get-client-id get-client-jwk get-client-redirect-uri + + make-account-full + get-account-subject + get-account-issuer + get-account-key-pair + get-account-id-token-header + get-account-id-token + get-account-access-token + get-account-refresh-token )) (define (make-client client-id jwk redirect-uri) @@ -48,3 +58,49 @@ (define (get-redirect-uri client) (uri->string (redirect-uri client))) + +(define (make-account-full subject issuer key-pair id-token-header id-token access-token refresh-token) + (make + #:subject (string->uri subject) + #:issuer (string->uri issuer) + #:key-pair (jwk->key (stubs:json-string->scm key-pair)) + #:id-token + (and id-token-header id-token + (make + #:jwt-header (stubs:json-string->scm id-token-header) + #:jwt-payload (stubs:json-string->scm id-token))) + #:access-token access-token + #:refresh-token refresh-token)) + +(define (get-account-subject account) + (uri->string (subject account))) + +(define (get-account-issuer account) + (uri->string (issuer account))) + +(define (get-account-key-pair account) + (stubs:scm->json-string (key->jwk (key-pair account)))) + +(define (get-account-id-token-header account) + (receive (id-token-header id-token) + (let ((id (id-token account))) + (if id + (token->jwt id) + (values #f #f))) + (and id-token-header + (stubs:scm->json-string id-token-header)))) + +(define (get-account-id-token account) + (receive (id-token-header id-token) + (let ((id (id-token account))) + (if id + (token->jwt id) + (values #f #f))) + (and id-token + (stubs:scm->json-string id-token)))) + +(define (get-account-access-token account) + (access-token account)) + +(define (get-account-refresh-token account) + (refresh-token account)) -- cgit v1.2.3