summaryrefslogtreecommitdiff
path: root/imap
diff options
context:
space:
mode:
authorEduardo Chappa <chappa@washington.edu>2020-06-26 12:19:56 -0600
committerEduardo Chappa <chappa@washington.edu>2020-06-26 12:19:56 -0600
commit354674406ed866dffbcab71455f796275a63df36 (patch)
tree6cb79243d5c72f569a9a7c944558251ea4af6464 /imap
parent9a21decd8d4528c36870a86f631c754b0b63411f (diff)
downloadalpine-354674406ed866dffbcab71455f796275a63df36.tar.xz
* Expansion of the configuration screen for XOAUTH2 to include
username, and tenant. * If a user has more than one client-id for a service, Alpine tries to asks the user which client-id to use and associates that client-id to the credentials in the XOAUTH2 configuration screen.
Diffstat (limited to 'imap')
-rw-r--r--imap/src/c-client/auth_bea.c21
-rw-r--r--imap/src/c-client/auth_oa2.c14
-rw-r--r--imap/src/c-client/http.h1
-rw-r--r--imap/src/c-client/mail.h14
-rw-r--r--imap/src/c-client/oauth2_aux.c132
-rw-r--r--imap/src/osdep/nt/makefile.nt2
6 files changed, 137 insertions, 47 deletions
diff --git a/imap/src/c-client/auth_bea.c b/imap/src/c-client/auth_bea.c
index bf5c9c1e..66604a35 100644
--- a/imap/src/c-client/auth_bea.c
+++ b/imap/src/c-client/auth_bea.c
@@ -121,21 +121,9 @@ long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder
+ strlen(BEARER_HOST) + strlen(mb->orighost) + 1
+ strlen(BEARER_PORT) + strlen(ports) + 1
+ strlen(OAUTH2_BEARER) + strlen(oauth2.access_token) + 2;
- t = response = (char *) fs_get (rlen);
- for (u = BEARER_ACCOUNT; *u; *t++ = *u++);
- for (u = user; *u; *t++ = *u++);
- *t++ = ',';
- *t++ = '\001'; /* delimiting ^A */
- for (u = BEARER_HOST; *u; *t++ = *u++);
- for (u = mb->orighost; *u; *t++ = *u++);
- *t++ = '\001'; /* delimiting ^A */
- for (u = BEARER_PORT; *u; *t++ = *u++);
- for (u = ports; *u; *t++ = *u++);
- *t++ = '\001'; /* delimiting ^A */
- for (u = OAUTH2_BEARER; *u; *t++ = *u++);
- for (u = oauth2.access_token; *u; *t++ = *u++);
- *t++ = '\001'; /* delimiting ^A */
- *t++ = '\001'; /* delimiting ^A */
+ response = (char *) fs_get (rlen+1);
+ sprintf(response, "%s%s,\001%s%s\001%s%s\001%s%s\001\001", BEARER_ACCOUNT, user,
+ BEARER_HOST, mb->orighost, BEARER_PORT, ports, OAUTH2_BEARER, oauth2.access_token);
if ((*responder) (stream,base,response,rlen)) {
if ((challenge = (*challenger) (stream,&clen)) != NULL)
fs_give ((void **) &challenge);
@@ -159,6 +147,9 @@ long auth_oauthbearer_client (authchallenge_t challenger,authrespond_t responder
fs_give ((void **) &response);
}
}
+ if(oauth2.param[OA2_Id].value) fs_give((void **) &oauth2.param[OA2_Id].value);
+ if(oauth2.param[OA2_Secret].value) fs_give((void **) &oauth2.param[OA2_Secret].value);
+ if(oauth2.param[OA2_Tenant].value) fs_give((void **) &oauth2.param[OA2_Tenant].value);
if (!ret || !oauth2.name)
*trial = 65535; /* don't retry if bad protocol */
return ret;
diff --git a/imap/src/c-client/auth_oa2.c b/imap/src/c-client/auth_oa2.c
index 69987559..f5345bfa 100644
--- a/imap/src/c-client/auth_oa2.c
+++ b/imap/src/c-client/auth_oa2.c
@@ -140,15 +140,8 @@ long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, cha
else {
unsigned long rlen = strlen(OAUTH2_USER) + strlen(user)
+ strlen(OAUTH2_BEARER) + strlen(oauth2.access_token) + 1 + 2;
- char *response = (char *) fs_get (rlen);
- char *t = response; /* copy authorization id */
- for (u = OAUTH2_USER; *u; *t++ = *u++);
- for (u = user; *u; *t++ = *u++);
- *t++ = '\001'; /* delimiting ^A */
- for (u = OAUTH2_BEARER; *u; *t++ = *u++);
- for (u = oauth2.access_token; *u; *t++ = *u++);
- *t++ = '\001'; /* delimiting ^A */
- *t++ = '\001'; /* delimiting ^A */
+ char *response = (char *) fs_get (rlen + 1);
+ sprintf(response, "%s%s\001%s%s\001\001", OAUTH2_USER, user, OAUTH2_BEARER, oauth2.access_token);
if ((*responder) (stream,base,response,rlen)) {
if ((challenge = (*challenger) (stream,&clen)) != NULL)
fs_give ((void **) &challenge);
@@ -172,6 +165,9 @@ long auth_oauth2_client (authchallenge_t challenger,authrespond_t responder, cha
fs_give ((void **) &response);
}
}
+ if(oauth2.param[OA2_Id].value) fs_give((void **) &oauth2.param[OA2_Id].value);
+ if(oauth2.param[OA2_Secret].value) fs_give((void **) &oauth2.param[OA2_Secret].value);
+ if(oauth2.param[OA2_Tenant].value) fs_give((void **) &oauth2.param[OA2_Tenant].value);
if (!ret || !oauth2.name)
*trial = 65535; /* don't retry if bad protocol */
return ret;
diff --git a/imap/src/c-client/http.h b/imap/src/c-client/http.h
index 621e7c48..41b16842 100644
--- a/imap/src/c-client/http.h
+++ b/imap/src/c-client/http.h
@@ -73,6 +73,7 @@ typedef struct http_header_data_s {
#define HTTP_1_1_VERSION "HTTP/1.1"
#define HTTP_OK 200
#define HTTP_BAD 400
+#define HTTP_UNAUTHORIZED 401
#define GET_HTTPPORT (long) 490
#define SET_HTTPPORT (long) 491
diff --git a/imap/src/c-client/mail.h b/imap/src/c-client/mail.h
index f74d889d..eb8f0139 100644
--- a/imap/src/c-client/mail.h
+++ b/imap/src/c-client/mail.h
@@ -1929,6 +1929,7 @@ int PFLUSH (void);
typedef enum {OA2_Id = 0,
OA2_Secret,
+ OA2_Tenant,
OA2_Code,
OA2_RefreshToken,
OA2_Scope,
@@ -1986,10 +1987,21 @@ typedef struct deviceproc_s {
char code_wait; /* code to say keep waiting */
} OAUTH2_DEVICEPROC_S;
+typedef struct xoauth_default_s {
+ unsigned char *name;
+ char *client_id;
+ char *client_secret;
+ char *tenant;
+ char *users;
+} XOAUTH2_INFO_S;
+
/* Supporting external functions for XOAUTH2 and OAUTHBEARER */
typedef char *(*oauth2getaccesscode_t) (unsigned char *, char *, OAUTH2_S *, int *);
-typedef void (*oauth2clientinfo_t)(unsigned char *name, char **id, char **secret);
+typedef XOAUTH2_INFO_S *(*oauth2clientinfo_t)(unsigned char *name, char *user);
typedef void (*oauth2deviceinfo_t)(OAUTH2_S *, char *method);
void mm_login_oauth2_c_client_method (NETMBX *, char *, char *, OAUTH2_S *, unsigned long, int *);
char *oauth2_generate_state(void);
void oauth2deviceinfo_get_accesscode(void *, void *);
+XOAUTH2_INFO_S *new_xoauth2_info(void);
+void free_xoauth2_info(XOAUTH2_INFO_S **);
+XOAUTH2_INFO_S *copy_xoauth2_info(XOAUTH2_INFO_S *);
diff --git a/imap/src/c-client/oauth2_aux.c b/imap/src/c-client/oauth2_aux.c
index a23f7c28..88ee52a6 100644
--- a/imap/src/c-client/oauth2_aux.c
+++ b/imap/src/c-client/oauth2_aux.c
@@ -53,6 +53,7 @@ char *oauth2_generate_state(void)
JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S, OAUTH2_S *, int *);
+char *xoauth2_server(char *, char *);
#define LOAD_HTTP_PARAMS(X, Y) { \
int i; \
@@ -64,20 +65,60 @@ JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S, OAUTH2_S *, int *);
(Y)[i].name = (Y)[i].value = NULL; \
}
+char *xoauth2_server(char *server, char *tenant)
+{
+ char *rv = NULL;
+ char *s;
+
+ if (server == NULL) return NULL;
+
+ s = cpystr(server);
+ if(tenant){
+ char *t = s, *u;
+ int i;
+ for(i = 0; t != NULL; i++){
+ t = strchr(t, '\001');
+ if(t != NULL) t++;
+ }
+ rv = fs_get((strlen(s) + i*(strlen(tenant)-1) + 1)*sizeof(char));
+ *rv = '\0';
+ for(u = t = s; t != NULL; i++){
+ t = strchr(t, '\001');
+ if (t != NULL) *t = '\0';
+ strcat(rv, u);
+ if(t != NULL){
+ strcat(rv, tenant);
+ *t++ = '\001';
+ }
+ u = t;
+ }
+
+ }
+ else
+ rv = cpystr(server);
+
+ return rv;
+}
+
JSON_S *oauth2_json_reply(OAUTH2_SERVER_METHOD_S RefreshMethod, OAUTH2_S *oauth2, int *status)
{
JSON_S *json = NULL;
HTTP_PARAM_S params[OAUTH2_PARAM_NUMBER];
unsigned char *s;
+ char *server = NULL;
LOAD_HTTP_PARAMS(RefreshMethod, params);
*status = 0;
+ server = xoauth2_server(RefreshMethod.urlserver, oauth2->param[OA2_Tenant].value);
if(strcmp(RefreshMethod.name, "POST") == 0
- && ((s = http_post_param(RefreshMethod.urlserver, params, status)) != NULL)){
+ && ((s = http_post_param(server, params, status)) != NULL)){
unsigned char *u = s;
json = json_parse(&u);
fs_give((void **) &s);
}
+ if(server)
+ fs_give((void **) &server);
+
return json;
}
@@ -92,11 +133,16 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method,
if(oauth2->param[OA2_Id].value == NULL
|| (oauth2->require_secret && oauth2->param[OA2_Secret].value == NULL)){
+ XOAUTH2_INFO_S *x;
oauth2clientinfo_t ogci =
(oauth2clientinfo_t) mail_parameters (NIL, GET_OA2CLIENTINFO, NIL);
- if(ogci) (*ogci)(oauth2->name, &oauth2->param[OA2_Id].value,
- &oauth2->param[OA2_Secret].value);
+ if(ogci && (x = (*ogci)(oauth2->name, user)) != NULL){
+ oauth2->param[OA2_Id].value = cpystr(x->client_id);
+ oauth2->param[OA2_Secret].value = x->client_secret ? cpystr(x->client_secret) : NULL;
+ oauth2->param[OA2_Tenant].value = x->tenant ? cpystr(x->tenant) : NULL;
+ free_xoauth2_info(&x);
+ }
}
if(oauth2->param[OA2_Id].value == NULL
@@ -157,24 +203,34 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method,
/* else check if we have a refresh token, and in that case use it */
if(oauth2->param[OA2_RefreshToken].value){
-
json = oauth2_json_reply(oauth2->server_mthd[OA2_GetAccessTokenFromRefreshToken], oauth2, &status);
if(json != NULL){
JSON_X *jx;
- jx = json_body_value(json, "access_token");
- if(jx && jx->jtype == JString)
- oauth2->access_token = cpystr((char *) jx->value);
+ switch(status){
+ case HTTP_UNAUTHORIZED:
+ mm_log("Client not authorized (wrong client-id?)", ERROR);
+ break;
+ case HTTP_OK: jx = json_body_value(json, "access_token");
+ if(jx && jx->jtype == JString)
+ oauth2->access_token = cpystr((char *) jx->value);
- if((jx = json_body_value(json, "expires_in")) != NULL)
- switch(jx->jtype){
- case JString: oauth2->expiration = time(0) + atol((char *) jx->value);
- break;
- case JLong : oauth2->expiration = time(0) + *(long *) jx->value;
- break;
- }
+ if((jx = json_body_value(json, "expires_in")) != NULL)
+ switch(jx->jtype){
+ case JString: oauth2->expiration = time(0) + atol((char *) jx->value);
+ break;
+ case JLong : oauth2->expiration = time(0) + *(long *) jx->value;
+ break;
+ }
+ break;
+ default : { char tmp[100];
+ sprintf(tmp, "Oauth2 client Received Code %d", status);
+ mm_log (tmp, ERROR);
+ }
+ break;
+ }
json_free(&json);
}
return;
@@ -190,12 +246,15 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method,
LOAD_HTTP_PARAMS(RefreshMethod, params);
if(strcmp(RefreshMethod.name, "GET") == 0){
- char *url = http_get_param_url(RefreshMethod.urlserver, params);
+ char *server = xoauth2_server(RefreshMethod.urlserver, oauth2->param[OA2_Tenant].value);
+ char *url = http_get_param_url(server, params);
oauth2getaccesscode_t ogac =
(oauth2getaccesscode_t) mail_parameters (NIL, GET_OA2CLIENTGETACCESSCODE, NIL);
if(ogac)
oauth2->param[OA2_Code].value = (*ogac)(url, method, oauth2, tryanother);
+
+ if(server) fs_give((void **) &server);
}
if(oauth2->param[OA2_Code].value){
@@ -230,7 +289,7 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method,
case HTTP_BAD : break;
default : { char tmp[100];
- sprintf(tmp, "Oauth Client Received Code %d", status);
+ sprintf(tmp, "Oauth2 Client Received Code %d", status);
fatal (tmp);
}
}
@@ -240,8 +299,6 @@ mm_login_oauth2_c_client_method (NETMBX *mb, char *user, char *method,
}
return;
}
-
- /* Else, does this server use the /devicecode method? */
}
void oauth2deviceinfo_get_accesscode(void *inp, void *outp)
@@ -304,9 +361,9 @@ void oauth2deviceinfo_get_accesscode(void *inp, void *outp)
break;
default : { char tmp[100];
- sprintf(tmp, "Oauth device Received Code %d", status);
- fatal (tmp);
- }
+ sprintf(tmp, "Oauth device Received Code %d", status);
+ mm_log (tmp, ERROR);
+ }
}
json_free(&json);
@@ -314,3 +371,36 @@ void oauth2deviceinfo_get_accesscode(void *inp, void *outp)
*(int *)outp = rv;
}
+
+XOAUTH2_INFO_S *new_xoauth2_info(void)
+{
+ XOAUTH2_INFO_S *rv = fs_get(sizeof(XOAUTH2_INFO_S));
+ memset((void *) rv, 0, sizeof(XOAUTH2_INFO_S));
+ return rv;
+}
+
+void free_xoauth2_info(XOAUTH2_INFO_S **xp)
+{
+ if(xp == NULL || *xp == NULL) return;
+
+ if((*xp)->name) fs_give((void **) &(*xp)->name);
+ if((*xp)->client_id) fs_give((void **) &(*xp)->client_id);
+ if((*xp)->client_secret) fs_give((void **) &(*xp)->client_secret);
+ if((*xp)->tenant) fs_give((void **) &(*xp)->tenant);
+ if((*xp)->users) fs_give((void **) &(*xp)->users);
+ fs_give((void **) xp);
+}
+
+XOAUTH2_INFO_S *copy_xoauth2_info(XOAUTH2_INFO_S *x)
+{
+ XOAUTH2_INFO_S *y;
+
+ if(x == NULL) return NULL;
+ y = new_xoauth2_info();
+ if(x->name) y->name = cpystr(x->name);
+ if(x->client_id) y->client_id = cpystr(x->client_id);
+ if(x->client_secret) y->client_secret = cpystr(x->client_secret);
+ if(x->tenant) y->tenant = cpystr(x->tenant);
+ if(x->users) y->users = cpystr(x->users);
+ return y;
+}
diff --git a/imap/src/osdep/nt/makefile.nt b/imap/src/osdep/nt/makefile.nt
index 83e74826..283d86a7 100644
--- a/imap/src/osdep/nt/makefile.nt
+++ b/imap/src/osdep/nt/makefile.nt
@@ -29,7 +29,7 @@
EXTRAAUTHENTICATORS =
EXTRADRIVERS =
EXTRACFLAGS =
-AUTHENTICATORS = ext md5 pla bea oa2 log
+AUTHENTICATORS = ext md5 pla log bea oa2
DRIVERS = imap nntp pop3 mbx mtx tenex unix
CREATEDRIVER = mbx
APPENDDRIVER = unix