From 5417727912422ac3d58f3cc3fd78c75b2a060fe3 Mon Sep 17 00:00:00 2001 From: Eduardo Chappa Date: Fri, 12 Jun 2020 20:33:58 -0600 Subject: * Additional addition of doucmentation for XOAUTH2, some fixes in the documentation, fixes in the configuration screen, and documentation on what is needed in each structure defining each service. --- alpine/imap.c | 57 ++++++++++++++++++++++-------------------- alpine/xoauth2.h | 2 +- alpine/xoauth2conf.c | 28 +++++++++++---------- imap/src/c-client/mail.h | 23 +++++++++++------ imap/src/c-client/oauth2_aux.c | 6 +++-- pith/pine.hlp | 46 ++++++++++++++-------------------- 6 files changed, 85 insertions(+), 77 deletions(-) diff --git a/alpine/imap.c b/alpine/imap.c index 54a58c68..78861728 100644 --- a/alpine/imap.c +++ b/alpine/imap.c @@ -145,7 +145,7 @@ OAUTH2_S alpine_oauth2_list[] = {"imap.gmail.com", "smtp.gmail.com", NULL, NULL}, {{"client_id", NULL}, {"client_secret", NULL}, - {"code", NULL}, + {"code", NULL}, /* not used */ {"refresh_token", NULL}, {"scope", "https://mail.google.com/"}, {"redirect_uri", "urn:ietf:wg:oauth:2.0:oob"}, @@ -153,48 +153,51 @@ OAUTH2_S alpine_oauth2_list[] = {"grant_type", "refresh_token"}, {"response_type", "code"}, {"state", NULL}, - {"prompt", NULL}, - {"device_code", NULL} + {"device_code", NULL} /* not used */ }, - {{"GET", "https://accounts.google.com/o/oauth2/auth", + {{"GET", "https://accounts.google.com/o/oauth2/auth", /* authorization address, get access code */ {OA2_Id, OA2_Scope, OA2_Redirect, OA2_Response, OA2_End, OA2_End, OA2_End}}, - {"POST", "https://accounts.google.com/o/oauth2/token", + {NULL, NULL, {OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}}, /* Device Info information, not used */ + {"POST", "https://accounts.google.com/o/oauth2/token", /* Address to get refresh token from access code */ {OA2_Id, OA2_Secret, OA2_Redirect, OA2_GrantTypeforAccessToken, OA2_Code, OA2_End, OA2_End}}, - {"POST", "https://accounts.google.com/o/oauth2/token", - {OA2_Id, OA2_Secret, OA2_RefreshToken, OA2_GrantTypefromRefreshToken, OA2_End, OA2_End, OA2_End}}, - {NULL, NULL, {OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}} + {"POST", "https://accounts.google.com/o/oauth2/token", /* access token from refresh token */ + {OA2_Id, OA2_Secret, OA2_RefreshToken, OA2_GrantTypefromRefreshToken, OA2_End, OA2_End, OA2_End}} }, - {NULL, NULL, NULL, 0, 0, NULL}, /* devicecode info */ - NULL, 0, 0 + {NULL, NULL, NULL, 0, 0, NULL}, /* device_code information */ + NULL, /* access token */ + 0, /* expiration time */ + 0, /* first time indicator */ + 1 /* client secret required */ }, {"Outlook", {"outlook.office365.com", "smtp.office365.com", NULL, NULL}, {{"client_id", NULL}, - {"client_secret", NULL}, - {"code", NULL}, + {"client_secret", NULL}, /* not used, but needed */ + {"code", NULL}, /* not used, not needed */ {"refresh_token", NULL}, {"scope", "offline_access https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/SMTP.Send"}, {"grant_type", "urn:ietf:params:oauth:grant-type:device_code"}, - {"scope", "https://graph.microsoft.com/mail.read"}, + {"scope", NULL}, /* not used */ {"grant_type", "refresh_token"}, - {"response_type", "code"}, - {"state", NULL}, - {"prompt", "login"}, - {"device_code", NULL} + {"response_type", "code"}, /* not used */ + {"state", NULL}, /* not used */ + {"device_code", NULL} /* only used for frst time set up */ }, - {{"GET", "https://login.microsoftonline.com/common/oauth2/authorize", - {OA2_Id, OA2_Scope, OA2_Redirect, OA2_Response, OA2_State, OA2_Prompt, OA2_End}}, - {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", + {{NULL, NULL, {OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}}, /* Get Access Code, Not used */ + {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode", /* first time use and get device code information */ + {OA2_Id, OA2_Scope, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}}, + {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", /* Get first Refresh Token and Access token */ {OA2_Id, OA2_Redirect, OA2_DeviceCode, OA2_End, OA2_End, OA2_End}}, - {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", - {OA2_Id, OA2_RefreshToken, OA2_Scope, OA2_GrantTypefromRefreshToken, OA2_End, OA2_End, OA2_End}}, - {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/devicecode", - {OA2_Id, OA2_Scope, OA2_End, OA2_End, OA2_End, OA2_End, OA2_End}} + {"POST", "https://login.microsoftonline.com/common/oauth2/v2.0/token", /* Get access token from refresh token */ + {OA2_Id, OA2_RefreshToken, OA2_Scope, OA2_GrantTypefromRefreshToken, OA2_End, OA2_End, OA2_End}} }, - {NULL, NULL, NULL, 0, 0, NULL}, - NULL, 0, 0 + {NULL, NULL, NULL, 0, 0, NULL}, /* device_code information */ + NULL, /* access token */ + 0, /* expiration time */ + 0, /* first time indicator */ + 0 /* client secret required */ }, - { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0}, + { NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0}, }; typedef struct auth_code_s { diff --git a/alpine/xoauth2.h b/alpine/xoauth2.h index 8a3fc3f7..f3896e86 100644 --- a/alpine/xoauth2.h +++ b/alpine/xoauth2.h @@ -27,6 +27,6 @@ typedef struct xoauth_default_s { #define OUTLOOK_NAME "Outlook" #define OUTLOOK_ID "f21dcaf2-8020-469b-8135-343bfc35d046" -#define OUTLOOK_SECRET "lIE42T4kZ2ZrN-2-AVNYSZ~8i_Co2WG4m." +#define OUTLOOK_SECRET NULL #endif /* ALPINE_XOAUTH2_INCLUDED */ diff --git a/alpine/xoauth2conf.c b/alpine/xoauth2conf.c index 4a69eb9c..0e898061 100644 --- a/alpine/xoauth2conf.c +++ b/alpine/xoauth2conf.c @@ -333,22 +333,24 @@ alpine_xoauth2_configuration(struct pine *ps, int edit_exceptions) varlist[l]->name = cpystr(XOAUTH2_CLIENT_SECRET); varlist[l]->is_used = 1; varlist[l]->is_user = 1; - varlist[l]->main_user_val.p = strcmp(secret, secret_def) ? cpystr(secret) : NULL; - varlist[l]->global_val.p = cpystr(secret_def); + varlist[l]->main_user_val.p = secret && secret_def && strcmp(secret, secret_def) ? cpystr(secret) : NULL; + varlist[l]->global_val.p = secret_def ? cpystr(secret_def) : NULL; set_current_val(varlist[l], FALSE, FALSE); /* Write client-secret variable */ - new_confline(&ctmpa)->var = varlist[l]; - utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_CLIENT_SECRET); - tmp[sizeof(tmp)-1] = '\0'; - ctmpa->varname = cpystr(tmp); - ctmpa->varmem = l++; - ctmpa->valoffset = ln + 3 + 3; - ctmpa->value = pretty_value(ps, ctmpa); - ctmpa->keymenu = &config_text_keymenu; - ctmpa->help = h_config_xoauth2_client_secret; - ctmpa->tool = text_tool; - ctmpa->varnamep = ctmpb; + if(secret){ + new_confline(&ctmpa)->var = varlist[l]; + utf8_snprintf(tmp, sizeof(tmp), " %-*.100w =", ln, XOAUTH2_CLIENT_SECRET); + tmp[sizeof(tmp)-1] = '\0'; + ctmpa->varname = cpystr(tmp); + ctmpa->varmem = l++; + ctmpa->valoffset = ln + 3 + 3; + ctmpa->value = pretty_value(ps, ctmpa); + ctmpa->keymenu = &config_text_keymenu; + ctmpa->help = h_config_xoauth2_client_secret; + ctmpa->tool = text_tool; + ctmpa->varnamep = ctmpb; + } /* Separate servers with a blank line */ new_confline(&ctmpa); diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h index 174fb9e3..f74d889d 100644 --- a/imap/src/c-client/mail.h +++ b/imap/src/c-client/mail.h @@ -1927,15 +1927,23 @@ int PFLUSH (void); #define OAUTH2_TOT_EQUIV (OAUTH2_MAX_EQUIV + 2) #define OAUTH2_PARAM_NUMBER (7) -typedef enum {OA2_Id = 0, OA2_Secret, OA2_Code, OA2_RefreshToken, - OA2_Scope, OA2_Redirect, - OA2_GrantTypeforAccessToken, OA2_GrantTypefromRefreshToken, - OA2_Response, OA2_State, OA2_Prompt, OA2_DeviceCode, OA2_End} OA2_type; - -typedef enum {OA2_GetAccessCode = 0, +typedef enum {OA2_Id = 0, + OA2_Secret, + OA2_Code, + OA2_RefreshToken, + OA2_Scope, + OA2_Redirect, + OA2_GrantTypeforAccessToken, + OA2_GrantTypefromRefreshToken, + OA2_Response, + OA2_State, + OA2_DeviceCode, + OA2_End} OA2_type; + +typedef enum {OA2_GetAccessCode = 0, /* define this to get access code */ + OA2_GetDeviceCode, /* define this if server uses device */ OA2_GetAccessTokenFromAccessCode, OA2_GetAccessTokenFromRefreshToken, - OA2_GetDeviceCode, OA2_GetEnd} OA2_function; typedef struct OA2_param_s { @@ -1968,6 +1976,7 @@ typedef struct oauth2_s { char *access_token; unsigned long expiration; unsigned int first_time:1; /* this is the first time we get credentials for this account */ + unsigned int require_secret:1; /* this server requires a client-secret */ } OAUTH2_S; typedef struct deviceproc_s { diff --git a/imap/src/c-client/oauth2_aux.c b/imap/src/c-client/oauth2_aux.c index 9ff14174..a23f7c28 100644 --- a/imap/src/c-client/oauth2_aux.c +++ b/imap/src/c-client/oauth2_aux.c @@ -90,7 +90,8 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, char *s = NULL; JSON_S *json = NULL; - if(oauth2->param[OA2_Id].value == NULL || oauth2->param[OA2_Secret].value == NULL){ + if(oauth2->param[OA2_Id].value == NULL + || (oauth2->require_secret && oauth2->param[OA2_Secret].value == NULL)){ oauth2clientinfo_t ogci = (oauth2clientinfo_t) mail_parameters (NIL, GET_OA2CLIENTINFO, NIL); @@ -98,7 +99,8 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method, &oauth2->param[OA2_Secret].value); } - if (oauth2->param[OA2_Id].value == NULL || oauth2->param[OA2_Secret].value == NULL) + if(oauth2->param[OA2_Id].value == NULL + || (oauth2->require_secret && oauth2->param[OA2_Secret].value == NULL)) return; /* Do we have a method to execute? */ diff --git a/pith/pine.hlp b/pith/pine.hlp index 9b3e55d3..912dcef4 100644 --- a/pith/pine.hlp +++ b/pith/pine.hlp @@ -140,7 +140,7 @@ with help text for the config screen and the composer that didn't have any reasonable place to be called from. Dummy change to get revision in pine.hlp ============= h_revision ================= -Alpine Commit 443 2020-06-12 02:21:54 +Alpine Commit 444 2020-06-12 20:33:43 ============= h_news ================= @@ -1594,9 +1594,9 @@ program.

At the beginning of this process, the developer of the email program registers the email program with the email service provider (Gmail, -Outlook, etc.) In return, the email service provider creates an id and -secret for the email program, which the email program will use in the -future. Since Alpine is an open source program, these values are part +Outlook, etc.) In return, the email service provider creates a client-id. +In addition, some services provice a client-secret. +Since Alpine is an open source program, these values are part of the source code, and are known to everyone, and cannot be obfuscated.

@@ -16011,22 +16011,15 @@ Nickname: field.

Client-Id Explained

-If you have registered Alpine with your service provider to use the -XOAUTH2 authenticator, or someone has shared a client-id with you, use this -field to input this value. Remember that in order to use the XOAUTH2 authentication -method, you must have a pair of client-id and client-secret. You must have -both in order for this authenticator to work. - +If you have registered Alpine with your service provider to use the XOAUTH2 authenticator, or +someone has shared a client-id and client-secret with you, use this field to input the +client-id.

The Client-Id field is a string that your provider generates for the program being registered. However, some providers allow different users to register the same program. Users of the Mutt email program already do this to use XOAUTH2 authentication in Gmail. -

-Some providers generate an extremely long client-id string. If this is your -case, you might have to divide that string into pieces and paste each of those -pieces into this field.

<End of help on this topic> @@ -16039,19 +16032,18 @@ pieces into this field.

Client-Secret Explained

-If you have registered Alpine with your service provider to use the -XOAUTH2 authenticator, or someone has shared a client-secret with you, use this -field to input this value. Remember that in order to use the XOAUTH2 authentication -method, you must have a pair of client-id and client-secret. You must have -both in order for this authenticator to work. - -

The client-secret field is supposed to be kept secret, that is not -shared with any of the users, but due to the open source nature of Alpine, -it is not possible to keep it secret in any meaningful way. The intention -of this field is so that only the coders of an app can use the codes given -to them and authenticate their users to the services they are requesting. -This means that other coders would not be able to impresonate that app, -and use it to steal data from those users. In the case of Alpine this is +If you have registered Alpine with your service provider to use the XOAUTH2 authenticator, or +someone has shared a client-id and client-secret with you, use this field to input the +client-secret. Some servers require both a client-id and a client-secret, some other servers do +not require a client-secret. If a client-secret is required, use this field to add one. + +

The client-secret field is supposed to be kept secret, that is, not +shared with any of the users, but due to the open source nature of Alpine, +it is not possible to keep it secret in any meaningful way. The intention +of this field is so that only the coders of an app can use the codes given +to them and authenticate their users to the services they are requesting. +This means that other coders would not be able to impresonate that app, +and use it to steal data from those users. In the case of Alpine this is not possible, as Alpine does not steal data from its users, so users are safe sharing client-secrets. Just make sure you obtain your copy of Alpine from a reputable provider or compile the source code by yourself. The official -- cgit v1.2.3-70-g09d2