Moved OAuth code to mailimap_oauth2.[ch]
parent
2d8c31e0b2
commit
9c8a0a5f3f
Binary file not shown.
@ -0,0 +1,142 @@
|
||||
#include "mailimap_oauth2.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "base64.h"
|
||||
#include "mailimap_sender.h"
|
||||
#include "mailimap.h"
|
||||
|
||||
int mailimap_oauth2_authenticate_send(mailimap * session,
|
||||
const char * auth_user,
|
||||
const char * access_token);
|
||||
|
||||
LIBETPAN_EXPORT
|
||||
int mailimap_oauth2_authenticate(mailimap * session, const char *auth_user, const char * access_token)
|
||||
{
|
||||
struct mailimap_response * response;
|
||||
int r;
|
||||
int error_code;
|
||||
|
||||
if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED)
|
||||
return MAILIMAP_ERROR_BAD_STATE;
|
||||
|
||||
mailstream_set_privacy(session->imap_stream, 0);
|
||||
r = mailimap_send_current_tag(session);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
mailstream_set_privacy(session->imap_stream, 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = mailimap_oauth2_authenticate_send(session, auth_user, access_token);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
mailstream_set_privacy(session->imap_stream, 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
r = mailimap_crlf_send(session->imap_stream);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
mailstream_set_privacy(session->imap_stream, 1);
|
||||
return r;
|
||||
}
|
||||
|
||||
if (mailstream_flush(session->imap_stream) == -1) {
|
||||
mailstream_set_privacy(session->imap_stream, 1);
|
||||
return MAILIMAP_ERROR_STREAM;
|
||||
}
|
||||
mailstream_set_privacy(session->imap_stream, 1);
|
||||
|
||||
if (mailimap_read_line(session) == NULL)
|
||||
return MAILIMAP_ERROR_STREAM;
|
||||
|
||||
r = mailimap_parse_response(session, &response);
|
||||
if (r != MAILIMAP_NO_ERROR)
|
||||
return r;
|
||||
|
||||
error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type;
|
||||
|
||||
mailimap_response_free(response);
|
||||
|
||||
switch (error_code) {
|
||||
case MAILIMAP_RESP_COND_STATE_OK:
|
||||
session->imap_state = MAILIMAP_STATE_AUTHENTICATED;
|
||||
return MAILIMAP_NO_ERROR;
|
||||
|
||||
default:
|
||||
return MAILIMAP_ERROR_LOGIN;
|
||||
}
|
||||
}
|
||||
|
||||
int mailimap_oauth2_authenticate_send(mailimap * session,
|
||||
const char * auth_user,
|
||||
const char * access_token)
|
||||
{
|
||||
int r;
|
||||
char * ptr;
|
||||
char * full_auth_string;
|
||||
char * full_auth_string_b64;
|
||||
int auth_user_len;
|
||||
int access_token_len;
|
||||
int full_auth_string_len;
|
||||
int res;
|
||||
|
||||
full_auth_string = NULL;
|
||||
full_auth_string_b64 = NULL;
|
||||
|
||||
/* Build client response string */
|
||||
auth_user_len = strlen(auth_user);
|
||||
access_token_len = strlen(access_token);
|
||||
full_auth_string_len = 5 + auth_user_len + 1 + 12 + access_token_len + 2;
|
||||
full_auth_string = malloc(full_auth_string_len + 1);
|
||||
if (full_auth_string == NULL) {
|
||||
res = MAILIMAP_ERROR_MEMORY;
|
||||
goto free;
|
||||
}
|
||||
|
||||
ptr = memcpy(full_auth_string, "user=", 5);
|
||||
ptr = memcpy(ptr + 5, auth_user, auth_user_len);
|
||||
ptr = memcpy(ptr + auth_user_len, "\1auth=Bearer ", 13);
|
||||
ptr = memcpy(ptr + 13, access_token, access_token_len);
|
||||
ptr = memcpy(ptr + access_token_len, "\1\1\0", 3);
|
||||
|
||||
/* Convert to base64 */
|
||||
full_auth_string_b64 = encode_base64(full_auth_string, full_auth_string_len);
|
||||
if (full_auth_string_b64 == NULL) {
|
||||
res = MAILIMAP_ERROR_MEMORY;
|
||||
goto free;
|
||||
}
|
||||
|
||||
r = mailimap_token_send(session->imap_stream, "AUTHENTICATE");
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
res = r;
|
||||
goto free;
|
||||
}
|
||||
r = mailimap_space_send(session->imap_stream);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
res = r;
|
||||
goto free;
|
||||
}
|
||||
r = mailimap_token_send(session->imap_stream, "XOAUTH2");
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
res = r;
|
||||
goto free;
|
||||
}
|
||||
r = mailimap_space_send(session->imap_stream);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
res = r;
|
||||
goto free;
|
||||
}
|
||||
r = mailimap_astring_send(session->imap_stream, full_auth_string_b64);
|
||||
if (r != MAILIMAP_NO_ERROR) {
|
||||
res = r;
|
||||
goto free;
|
||||
}
|
||||
|
||||
res = MAILIMAP_NO_ERROR;
|
||||
|
||||
free:
|
||||
free(full_auth_string);
|
||||
free(full_auth_string_b64);
|
||||
return res;
|
||||
}
|
||||
|
@ -0,0 +1,61 @@
|
||||
#ifndef MAILIMAP_OAUTH2_H
|
||||
|
||||
#define MAILIMAP_OAUTH2_H
|
||||
|
||||
#include <libetpan/mailimap_types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
mailimap_oauth2_authenticate()
|
||||
Authenticates the client using using an oauth2 token.
|
||||
To gather a deeper understanding of the OAuth2 aunthentication
|
||||
process refer to: https://developers.google.com/gmail/xoauth2_protocol
|
||||
For a quick start you may follow this brief set of steps:
|
||||
1. Set up a profile for your app in the Google
|
||||
API Console: https://code.google.com/apis/console
|
||||
2. With your recently obtained client_id and secret
|
||||
load the following URL (everything goes ina single line):
|
||||
https://accounts.google.com/o/oauth2/auth?client_id=[YOUR_CLIENT_ID]&
|
||||
redirect_uri=urn%3Aietf%3Awg%3Aoauth%3A2.0%3Aoob&
|
||||
response_type=code&scope=https%3A%2F%2Fmail.google.com%2F&
|
||||
login_hint=[USER_EMAIL_ADDRESS]&access_type=offline
|
||||
3. The user most follow instructions to authorize application access
|
||||
to Gmail.
|
||||
4. After the user hits the "Accept" button it will be redirected to another
|
||||
page where the access token will be issued.
|
||||
5. Now from the app we need and authorization token, to get one we issue a POST request
|
||||
the following URL: https://accounts.google.com/o/oauth2/token using these parameters:
|
||||
client_id: This is the client id we got from step 1
|
||||
client_secret: Client secret as we got it from step 1
|
||||
code: This is the code we received in step 4
|
||||
redirect_uri: This is a redirect URI where the access token will be sent, for non
|
||||
web applications this is usually urn:ietf:wg:oauth:2.0:oob (as we got from step 1)
|
||||
grant_type: Always use the authorization_code parameter to retrieve an access and refresh tokens
|
||||
6. After step 5 completes we receive a JSON object similar to:
|
||||
{
|
||||
"access_token":"1/fFAGRNJru1FTz70BzhT3Zg",
|
||||
"refresh_token":"1/fFAGRNJrufoiWEGIWEFJFJF",
|
||||
"expires_in":3920,
|
||||
"token_type":"Bearer"
|
||||
}
|
||||
The access token is what we need to authenticate via XOAuth2 with Gmail.
|
||||
@param session IMAP session
|
||||
@param session Authentication user (tipically an e-mail address, depends on server)
|
||||
@param access_token OAuth2 access token
|
||||
@return the return code is one of MAILIMAP_ERROR_XXX or
|
||||
MAILIMAP_NO_ERROR codes
|
||||
*/
|
||||
|
||||
LIBETPAN_EXPORT
|
||||
int mailimap_oauth2_authenticate(mailimap * session, const char * auth_user,
|
||||
const char * access_token);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue