]> granicus.if.org Git - curl/commitdiff
httpauth: add support for Bearer tokens
authorLinus Lewandowski <linus@lew21.net>
Tue, 22 May 2018 10:28:41 +0000 (12:28 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 24 May 2018 18:39:49 +0000 (20:39 +0200)
Closes #2102

docs/libcurl/opts/CURLOPT_HTTPAUTH.3
docs/libcurl/opts/CURLOPT_XOAUTH2_BEARER.3
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/http.c
src/tool_getparam.c
tests/data/Makefile.inc
tests/data/test2074 [new file with mode: 0644]

index 09a9f996a61b78e5ea3c183972ccb8c3f1745956..7bb45506e7cc60fc42ef3828cb659242cc8e36a5 100644 (file)
@@ -56,6 +56,10 @@ defined in RFC2617 and is a more secure way to do authentication over public
 networks than the regular old-fashioned Basic method. The IE flavor is simply
 that libcurl will use a special "quirk" that IE is known to have used before
 version 7 and that some servers require the client to use.
+.IP CURLAUTH_BEARER
+HTTP Bearer token authentication, used primarily in OAuth 2.0 protocol.
+
+You can set the Bearer token to use with \fICURLOPT_XOAUTH2_BEARER(3)\fP.
 .IP CURLAUTH_NEGOTIATE
 HTTP Negotiate (SPNEGO) authentication. Negotiate authentication is defined
 in RFC 4559 and is the most secure way to perform authentication over HTTP.
index 262c637648e92132b9529633c5ce0fc9f17d1139..8f86ae9eef0f6d4cc71756edb6215a3afe24fd81 100644 (file)
@@ -29,11 +29,11 @@ CURLOPT_XOAUTH2_BEARER \- specify OAuth 2.0 access token
 CURLcode curl_easy_setopt(CURL *handle, CURLOPT_XOAUTH2_BEARER, char *token);
 .SH DESCRIPTION
 Pass a char * as parameter, which should point to the zero terminated OAuth
-2.0 Bearer Access Token for use with IMAP, POP3 and SMTP servers that support
-the OAuth 2.0 Authorization Framework.
+2.0 Bearer Access Token for use with HTTP, IMAP, POP3 and SMTP servers
+that support the OAuth 2.0 Authorization Framework.
 
-Note: The user name used to generate the Bearer Token should be supplied via
-the \fICURLOPT_USERNAME(3)\fP option.
+Note: For IMAP, POP3 and SMTP, the user name used to generate the Bearer Token
+should be supplied via the \fICURLOPT_USERNAME(3)\fP option.
 
 The application does not have to keep the string around after setting this
 option.
index 7df2d700c395bea65234d2885dcd5e9fadb189e7..f98609e1d88877e7d615bdc0b95d47fb8a39ccbb 100644 (file)
@@ -15,6 +15,7 @@
 CURLAUTH_ANY                    7.10.6
 CURLAUTH_ANYSAFE                7.10.6
 CURLAUTH_BASIC                  7.10.6
+CURLAUTH_BEARER                 7.61.0
 CURLAUTH_DIGEST                 7.10.6
 CURLAUTH_DIGEST_IE              7.19.3
 CURLAUTH_GSSAPI                 7.55.0
index 42dfc78bc12b8cbbb7892d7f8f0e5f51ca65fe0c..3ebaa019a7303c225fd0337393b6d1065e26c7e0 100644 (file)
@@ -691,6 +691,7 @@ typedef enum {
  * CURLAUTH_NTLM         - HTTP NTLM authentication
  * CURLAUTH_DIGEST_IE    - HTTP Digest authentication with IE flavour
  * CURLAUTH_NTLM_WB      - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_BEARER       - HTTP Bearer token authentication
  * CURLAUTH_ONLY         - Use together with a single other type to force no
  *                         authentication or just that single type
  * CURLAUTH_ANY          - All fine types set
@@ -708,6 +709,7 @@ typedef enum {
 #define CURLAUTH_NTLM         (((unsigned long)1)<<3)
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
+#define CURLAUTH_BEARER       (((unsigned long)1)<<6)
 #define CURLAUTH_ONLY         (((unsigned long)1)<<31)
 #define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
 #define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
index dac2b14177bc4817420af3a0d6ca50ccf569229b..0bcdf194d62be221af4f7f70e6ef83d1a5dda653 100644 (file)
@@ -310,6 +310,31 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
   return result;
 }
 
+/*
+ * http_output_bearer() sets up an Authorization: header
+ * for HTTP Bearer authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_bearer(struct connectdata *conn)
+{
+  char **userp;
+  CURLcode result = CURLE_OK;
+
+  userp = &conn->allocptr.userpwd;
+  free(*userp);
+  *userp = aprintf("Authorization: Bearer %s\r\n",
+                   conn->oauth_bearer);
+
+  if(!*userp) {
+    result = CURLE_OUT_OF_MEMORY;
+    goto fail;
+  }
+
+  fail:
+  return result;
+}
+
 /* pickoneauth() selects the most favourable authentication method from the
  * ones available and the ones we want.
  *
@@ -326,6 +351,8 @@ static bool pickoneauth(struct auth *pick)
      of preference in case of the existence of multiple accepted types. */
   if(avail & CURLAUTH_NEGOTIATE)
     pick->picked = CURLAUTH_NEGOTIATE;
+  else if(avail & CURLAUTH_BEARER)
+    pick->picked = CURLAUTH_BEARER;
   else if(avail & CURLAUTH_DIGEST)
     pick->picked = CURLAUTH_DIGEST;
   else if(avail & CURLAUTH_NTLM)
@@ -628,6 +655,20 @@ output_auth_headers(struct connectdata *conn,
        functions work that way */
     authstatus->done = TRUE;
   }
+  if(authstatus->picked == CURLAUTH_BEARER) {
+    /* Bearer */
+    if((!proxy && conn->oauth_bearer &&
+        !Curl_checkheaders(conn, "Authorization:"))) {
+      auth = "Bearer";
+      result = http_output_bearer(conn);
+      if(result)
+        return result;
+    }
+
+    /* NOTE: this function should set 'done' TRUE, as the other auth
+       functions work that way */
+    authstatus->done = TRUE;
+  }
 
   if(auth) {
     infof(data, "%s auth using %s with user '%s'\n",
@@ -674,7 +715,7 @@ Curl_http_output_auth(struct connectdata *conn,
   authproxy = &data->state.authproxy;
 
   if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
-     conn->bits.user_passwd)
+     conn->bits.user_passwd || conn->oauth_bearer)
     /* continue please */;
   else {
     authhost->done = TRUE;
@@ -883,6 +924,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
               data->state.authproblem = TRUE;
             }
           }
+          else
+            if(checkprefix("Bearer", auth)) {
+              *availp |= CURLAUTH_BEARER;
+              authp->avail |= CURLAUTH_BEARER;
+              if(authp->picked == CURLAUTH_BEARER) {
+                /* We asked for Bearer authentication but got a 40X back
+                  anyway, which basically means our token isn't valid. */
+                authp->avail = CURLAUTH_NONE;
+                infof(data, "Authentication problem. Ignoring this.\n");
+                data->state.authproblem = TRUE;
+              }
+            }
 
     /* there may be multiple methods on one line, so keep reading */
     while(*auth && *auth != ',') /* read up to the next comma */
index 4b9ae0653da5c40cb8666a1f14bd0bf248823a5b..e83373c37552f2c2e04889404dfc3494b3628a03 100644 (file)
@@ -601,6 +601,7 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
         break;
       case 'B': /* OAuth 2.0 bearer token */
         GetStr(&config->oauth_bearer, nextarg);
+        config->authtype |= CURLAUTH_BEARER;
         break;
       case 'c': /* connect-timeout */
         err = str2udouble(&config->connecttimeout, nextarg,
index 2d811694dd623075ac88b1e746e970314b0def25..bce8c979826877a7e1664c88d1e80e810ab52d95 100644 (file)
@@ -196,5 +196,6 @@ test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \
 test2064 test2065 test2066 test2067 test2068 test2069 \
 \
 test2070 test2071 test2072 test2073 \
+test2074 \
 \
 test3000 test3001
diff --git a/tests/data/test2074 b/tests/data/test2074
new file mode 100644 (file)
index 0000000..ecff8fe
--- /dev/null
@@ -0,0 +1,57 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+AUTH OAUTHBEARER
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data>
+HTTP/1.1 200 OK
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+Accept-Ranges: bytes
+Content-Length: 6
+Connection: close
+Content-Type: text/html
+Funny-head: yesyes
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+HTTP GET
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/2074 --oauth2-bearer mF_9.B5f-4.1JqM
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /2074 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Authorization: Bearer mF_9.B5f-4.1JqM\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>