From b66a2ed0f027985a1b81ec6604534dc639ea22d7 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 4 Oct 2021 17:37:41 -0400 Subject: [PATCH] Initial implementation of OAuth client callback (Issue #100) --- CHANGES.md | 1 + cups/auth.c | 47 ++++++++++++++++++++++++++++++++++++--------- cups/cups-private.h | 3 +++ cups/cups.h | 8 ++++++++ cups/usersys.c | 37 +++++++++++++++++++++++++++++++++++ cups/versioning.h | 3 +++ 6 files changed, 90 insertions(+), 9 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 30012b3ea1..7d1f214724 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -5,6 +5,7 @@ CUPS v2.4-b1 (Pending) ---------------------- - Added support for CUPS running in a Snapcraft snap. +- Added basic OAuth 2.0 client support (Issue #100) - Added support for AirPrint and Mopria clients (Issue #105) - Added configure support for specifying systemd dependencies in the CUPS service file (Issue #144) diff --git a/cups/auth.c b/cups/auth.c index d70622ca5f..177eec8ce3 100644 --- a/cups/auth.c +++ b/cups/auth.c @@ -1,13 +1,15 @@ /* * Authentication functions for CUPS. * - * Copyright 2007-2019 by Apple Inc. - * Copyright 1997-2007 by Easy Software Products. + * Copyright © 2021 by OpenPrinting. + * Copyright © 2007-2019 by Apple Inc. + * Copyright © 1997-2007 by Easy Software Products. * * This file contains Kerberos support code, copyright 2006 by * Jelmer Vernooij. * - * Licensed under Apache License v2.0. See the file "LICENSE" for more information. + * Licensed under Apache License v2.0. See the file "LICENSE" for more + * information. */ /* @@ -115,7 +117,7 @@ cupsDoAuthentication( char scheme[256], /* Scheme name */ prompt[1024]; /* Prompt for user */ int localauth; /* Local authentication result */ - _cups_globals_t *cg; /* Global data */ + _cups_globals_t *cg = _cupsGlobals(); /* Global data */ DEBUG_printf(("cupsDoAuthentication(http=%p, method=\"%s\", resource=\"%s\")", (void *)http, method, resource)); @@ -202,9 +204,38 @@ cupsDoAuthentication( } else #endif /* HAVE_GSSAPI */ - if (_cups_strcasecmp(scheme, "Basic") && - _cups_strcasecmp(scheme, "Digest") && - _cups_strcasecmp(scheme, "Negotiate")) + if (!_cups_strcasecmp(scheme, "Bearer")) + { + // OAuth 2.0 (Bearer) authentication... + const char *bearer = NULL; /* Bearer token string, if any */ + + if (cg->oauth_cb) + { + // Try callback... + char scope[HTTP_MAX_VALUE]; /* scope="xyz" string */ + + cups_auth_param(schemedata, "realm", http->realm, sizeof(http->realm)); + + if (cups_auth_param(schemedata, "scope", scope, sizeof(scope))) + bearer = (cg->oauth_cb)(http, http->realm, scope, resource, cg->oauth_data); + else + bearer = (cg->oauth_cb)(http, http->realm, NULL, resource, cg->oauth_data); + } + + if (bearer) + { + // Use this access token... + httpSetAuthString(http, "Bearer", bearer); + break; + } + else + { + // No access token, try the next scheme... + DEBUG_puts("2cupsDoAuthentication: No OAuth access token to provide."); + continue; + } + } + else if (_cups_strcasecmp(scheme, "Basic") && _cups_strcasecmp(scheme, "Digest") && _cups_strcasecmp(scheme, "Negotiate")) { /* * Other schemes not yet supported... @@ -227,8 +258,6 @@ cupsDoAuthentication( char default_username[HTTP_MAX_VALUE]; /* Default username */ - cg = _cupsGlobals(); - if (!cg->lang_default) cg->lang_default = cupsLangDefault(); diff --git a/cups/cups-private.h b/cups/cups-private.h index 97734a539b..cf2559d958 100644 --- a/cups/cups-private.h +++ b/cups/cups-private.h @@ -1,6 +1,7 @@ /* * Private definitions for CUPS. * + * Copyright © 2021 by OpenPrinting. * Copyright © 2007-2019 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products, all rights reserved. * @@ -172,6 +173,8 @@ typedef struct _cups_globals_s /**** CUPS global state data ****/ server[256], /* Server address */ servername[256],/* Server hostname */ password[128]; /* Password for default callback */ + cups_oauth_cb_t oauth_cb; /* OAuth callback */ + void *oauth_data; /* OAuth user data */ cups_password_cb2_t password_cb; /* Password callback */ void *password_data; /* Password user data */ http_tls_credentials_t tls_credentials; diff --git a/cups/cups.h b/cups/cups.h index 760a1a01c0..9949e2ee76 100644 --- a/cups/cups.h +++ b/cups/cups.h @@ -1,6 +1,7 @@ /* * API definitions for CUPS. * + * Copyright © 2021 by OpenPrinting. * Copyright © 2007-2020 by Apple Inc. * Copyright © 1997-2007 by Easy Software Products. * @@ -309,6 +310,9 @@ typedef int (^cups_dest_block_t)(unsigned flags, cups_dest_t *dest); * @exclude all@ */ # endif /* __BLOCKS__ */ +typedef const char *(*cups_oauth_cb_t)(http_t *http, const char *realm, const char *scope, const char *resource, void *user_data); + /* OAuth callback @since CUPS 2.4@ */ + typedef const char *(*cups_password_cb_t)(const char *prompt); /* Password callback @exclude all@ */ @@ -604,6 +608,10 @@ extern const char *cupsHashString(const unsigned char *hash, size_t hashsize, ch extern int cupsAddDestMediaOptions(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, cups_size_t *size, int num_options, cups_option_t **options) _CUPS_API_2_3; extern ipp_attribute_t *cupsEncodeOption(ipp_t *ipp, ipp_tag_t group_tag, const char *name, const char *value) _CUPS_API_2_3; +/* New in CUPS 2.4 */ +extern void cupsSetOAuthCB(cups_oauth_cb_t cb, void *data) _CUPS_API_2_4; + + # ifdef __cplusplus } # endif /* __cplusplus */ diff --git a/cups/usersys.c b/cups/usersys.c index a5553ad44c..a9386e7f10 100644 --- a/cups/usersys.c +++ b/cups/usersys.c @@ -309,6 +309,43 @@ cupsSetEncryption(http_encryption_t e) /* I - New encryption preference */ } +/* + * 'cupsSetOAuthCB()' - Set the OAuth 2.0 callback for CUPS. + * + * This function sets the OAuth 2.0 callback for the various CUPS APIs that + * send HTTP requests. Pass @code NULL@ to restore the default (console-based) + * callback. + * + * The OAuth callback receives the HTTP connection, realm name, scope name (if + * any), resource path, and the "user_data" pointer for each request that + * requires an OAuth access token. The function then returns either the Bearer + * token string or `NULL` if no authorization could be obtained. + * + * Beyond reusing the Bearer token for subsequent requests on the same HTTP + * connection, no caching of the token is done by the CUPS library. The + * callback can determine whether to refresh a cached token by examining any + * existing token returned by the @link httpGetAuthString@ function. + * + * Note: The current OAuth callback is tracked separately for each thread in a + * program. Multi-threaded programs that override the callback need to do so in + * each thread for the same callback to be used. + * + * @since CUPS 2.4@ + */ + +void +cupsSetOAuthCB( + cups_oauth_cb_t cb, /* I - Callback function */ + void *user_data) /* I - User data pointer */ +{ + _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ + + + cg->oauth_cb = cb; + cg->oauth_data = user_data; +} + + /* * 'cupsSetPasswordCB()' - Set the password callback for CUPS. * diff --git a/cups/versioning.h b/cups/versioning.h index 2ad9879f92..ad398ed8b1 100644 --- a/cups/versioning.h +++ b/cups/versioning.h @@ -1,6 +1,7 @@ /* * API versioning definitions for CUPS. * + * Copyright © 2021 by OpenPrinting. * Copyright © 2007-2019 by Apple Inc. * * Licensed under Apache License v2.0. See the file "LICENSE" for more @@ -129,6 +130,7 @@ # define _CUPS_API_2_2_4 _CUPS_API_AVAILABLE(macos(10.13), ios(12.0)) _CUPS_PUBLIC # define _CUPS_API_2_2_7 _CUPS_API_AVAILABLE(macos(10.14), ios(13.0)) _CUPS_PUBLIC # define _CUPS_API_2_3 _CUPS_API_AVAILABLE(macos(10.14), ios(13.0)) _CUPS_PUBLIC +# define _CUPS_API_2_4 _CUPS_PUBLIC # else # define _CUPS_API_1_1_19 _CUPS_PUBLIC # define _CUPS_API_1_1_20 _CUPS_PUBLIC @@ -144,6 +146,7 @@ # define _CUPS_API_2_2_4 _CUPS_PUBLIC # define _CUPS_API_2_2_7 _CUPS_PUBLIC # define _CUPS_API_2_3 _CUPS_PUBLIC +# define _CUPS_API_2_4 _CUPS_PUBLIC # endif /* __APPLE__ && !_CUPS_SOURCE */ -- 2.47.2