From a44aaacceb75cb828a0c35ca20b3ff5248073cf2 Mon Sep 17 00:00:00 2001
From: kylehuff <code@curetheitch.com>
Date: Sun, 25 Aug 2013 13:17:01 -0400
Subject: [PATCH 1/5] curllib: add basic SASL XOAUTH2 support

Adds the ability to specify an XOAUTH2 bearer token [RFC6750] via
the option CURLOPT_XOAUTH2_BEARER for authentication using RFC6749
"OAuth 2.0 Authorization Framework".

The Bearer token is expected to be valid for the user specified in
conn->user. If CURLOPT_XOAUTH2_BEARER is defined and the connec-
tion has an advertised auth mechanism of "XOAUTH2", the user and
access token are formatted as a base64 encoded string and sent to
the server as "AUTH XOAUTH2 <bearer token>".

The generated base64 encoded token contains:
"user=<username>^Aauth=Bearer <bearer token>^A^A"
---
 include/curl/curl.h          |    3 +++
 include/curl/typecheck-gcc.h |    1 +
 lib/curl_sasl.c              |   35 +++++++++++++++++++++++++++++++++++
 lib/curl_sasl.h              |    8 ++++++++
 lib/url.c                    |   15 +++++++++++++++
 lib/urldata.h                |    4 ++++
 6 files changed, 66 insertions(+), 0 deletions(-)

diff --git a/include/curl/curl.h b/include/curl/curl.h
index 0fb00e8..ed536d1 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -1553,6 +1553,9 @@ typedef enum {
    * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */
   CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219),
 
+  /* The XOAUTH2 bearer token */
+  CINIT(XOAUTH2_BEARER, OBJECTPOINT, 220),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h
index f8917e8..a9fee0c 100644
--- a/include/curl/typecheck-gcc.h
+++ b/include/curl/typecheck-gcc.h
@@ -264,6 +264,7 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
    (option) == CURLOPT_RTSP_SESSION_ID ||                                     \
    (option) == CURLOPT_RTSP_STREAM_URI ||                                     \
    (option) == CURLOPT_RTSP_TRANSPORT ||                                      \
+   (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
    0)
 
 /* evaluates to true if option takes a curl_write_callback argument */
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index 924be4b..ae8e9ea 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -22,6 +22,7 @@
  * RFC2831 DIGEST-MD5 authentication
  * RFC4422 Simple Authentication and Security Layer (SASL)
  * RFC4616 PLAIN authentication
+ * RFC6749 OAuth 2.0 Authorization Framework
  *
  ***************************************************************************/
 
@@ -161,6 +162,40 @@ CURLcode Curl_sasl_create_login_message(struct SessionHandle *data,
   return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
 }
 
+/*
+ * Curl_sasl_create_xoauth2_message()
+ *
+ * This is used to generate an already encoded XOAUTH2 message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data    [in]     - The session handle.
+ * user    [in]     - The user name.
+ * bearer  [in]     - The XOAUTH Bearer token.
+ * outptr  [in/out] - The address where a pointer to newly allocated memory
+ *                    holding the result will be stored upon completion.
+ * outlen  [out]    - The length of the output message.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
+                                          const char *user,
+                                          const char *bearer,
+                                          char **outptr, size_t *outlen)
+{
+  char *xoauth;
+
+  xoauth = aprintf("user=%s\1auth=Bearer %s\1\1", user, bearer);
+
+  if(!xoauth)
+    return CURLE_OUT_OF_MEMORY;
+
+  /* Base64 encode the reply */
+  return Curl_base64_encode(data, xoauth, strlen(xoauth), outptr,
+                            outlen);
+}
+
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 /*
  * Curl_sasl_create_cram_md5_message()
diff --git a/lib/curl_sasl.h b/lib/curl_sasl.h
index 22dcf80..964e94c 100644
--- a/lib/curl_sasl.h
+++ b/lib/curl_sasl.h
@@ -32,6 +32,7 @@
 #define SASL_MECH_GSSAPI        (1 << 4)
 #define SASL_MECH_EXTERNAL      (1 << 5)
 #define SASL_MECH_NTLM          (1 << 6)
+#define SASL_MECH_XOAUTH2       (1 << 7)
 
 /* Authentication mechanism values */
 #define SASL_AUTH_NONE          0
@@ -85,6 +86,13 @@ CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
 
 #endif /* USE_NTLM */
 
+/* This is used to generate a base64 encoded XOAUTH2 authentication message
+   containing the user name and bearer token */
+CURLcode Curl_sasl_create_xoauth2_message(struct SessionHandle *data,
+                                          const char *user,
+                                          const char *bearer,
+                                          char **outptr, size_t *outlen);
+
 /* This is used to cleanup any libraries or curl modules used by the sasl
    functions */
 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
diff --git a/lib/url.c b/lib/url.c
index 657681d..25b2d95 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -1569,6 +1569,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
     result = setstropt(&data->set.str[STRING_PASSWORD],
                        va_arg(param, char *));
     break;
+  case CURLOPT_XOAUTH2_BEARER:
+    /*
+     * XOAUTH2 bearer token to use in the operation
+     */
+    result = setstropt(&data->set.str[STRING_BEARER],
+                       va_arg(param, char *));
+    break;
   case CURLOPT_POSTQUOTE:
     /*
      * List of RAW FTP commands to use after a transfer
@@ -2488,6 +2495,7 @@ static void conn_free(struct connectdata *conn)
 
   Curl_safefree(conn->user);
   Curl_safefree(conn->passwd);
+  Curl_safefree(conn->xoauth2_bearer);
   Curl_safefree(conn->options);
   Curl_safefree(conn->proxyuser);
   Curl_safefree(conn->proxypasswd);
@@ -5181,6 +5189,13 @@ static CURLcode create_conn(struct SessionHandle *data,
     }
   }
 
+  if(data->set.str[STRING_BEARER]) {
+    conn->xoauth2_bearer = strdup(data->set.str[STRING_BEARER]);
+    if(!conn->xoauth2_bearer) {
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+
 #ifndef CURL_DISABLE_PROXY
   /*************************************************************
    * Extract the user and password from the authentication string
diff --git a/lib/urldata.h b/lib/urldata.h
index be139ef..85d6bda 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -876,6 +876,8 @@ struct connectdata {
   char *passwd;  /* password string, allocated */
   char *options; /* options string, allocated */
 
+  char *xoauth2_bearer; /* bearer token for xoauth2, allocated */
+
   char *proxyuser;    /* proxy user name string, allocated */
   char *proxypasswd;  /* proxy password string, allocated */
   curl_proxytype proxytype; /* what kind of proxy that is in use */
@@ -1367,6 +1369,8 @@ enum dupstring {
   STRING_TLSAUTH_PASSWORD,     /* TLS auth <password> */
 #endif
 
+  STRING_BEARER,          /* <bearer>, if used */
+
   /* -- end of strings -- */
   STRING_LAST /* not used, just an end-of-list marker */
 };
-- 
1.7.5.4

