]> granicus.if.org Git - curl/commitdiff
oauth2: Support OAUTHBEARER failures sent as continuation responses
authorSteve Holme <steve_holme@hotmail.com>
Sat, 5 Sep 2015 17:35:47 +0000 (18:35 +0100)
committerSteve Holme <steve_holme@hotmail.com>
Sun, 15 Nov 2015 20:11:53 +0000 (20:11 +0000)
According to RFC7628 a failure message may be sent by the server in a
base64 encoded JSON string as a continuation response.

Currently only implemented for OAUTHBEARER and not XAUTH2.

lib/curl_sasl.c
lib/curl_sasl.h

index 956801b7182d199ab60463a8998824117f4d7004..05b201a141f860756175245a031c5f186143d08a 100644 (file)
@@ -1346,6 +1346,7 @@ static void state(struct SASL *sasl, struct connectdata *conn,
     "GSSAPI_TOKEN",
     "GSSAPI_NO_DATA",
     "OAUTH2",
+    "OAUTH2_RESP",
     "CANCEL",
     "FINAL",
     /* LAST */
@@ -1459,6 +1460,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
     if((enabledmechs & SASL_MECH_OAUTHBEARER) && conn->oauth_bearer) {
       mech = SASL_MECH_STRING_OAUTHBEARER;
       state1 = SASL_OAUTH2;
+      state2 = SASL_OAUTH2_RESP;
       sasl->authused = SASL_MECH_OAUTHBEARER;
 
       if(force_ir || data->set.sasl_ir)
@@ -1549,7 +1551,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     return result;
   }
 
-  if(sasl->state != SASL_CANCEL && code != sasl->params->contcode) {
+  if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
+     code != sasl->params->contcode) {
     *progress = SASL_DONE;
     state(sasl, conn, SASL_STOP);
     return CURLE_LOGIN_DENIED;
@@ -1654,18 +1657,43 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 
   case SASL_OAUTH2:
     /* Create the authorisation message */
-    if(sasl->authused == SASL_MECH_OAUTHBEARER)
+    if(sasl->authused == SASL_MECH_OAUTHBEARER) {
       result = sasl_create_oauth_bearer_message(data, conn->user,
                                                 conn->host.name,
                                                 conn->port,
                                                 conn->oauth_bearer,
                                                 &resp, &len);
+
+      /* Failures maybe sent by the server as continuations for OAUTHBEARER */
+      newstate = SASL_OAUTH2_RESP;
+    }
     else
       result = sasl_create_oauth_bearer_message(data, conn->user,
                                                 NULL, 0,
                                                 conn->oauth_bearer,
                                                 &resp, &len);
     break;
+
+  case SASL_OAUTH2_RESP:
+    /* The continuation is optional so check the response code */
+    if (code == sasl->params->finalcode) {
+      /* Final response was received so we are done */
+      *progress = SASL_DONE;
+      state(sasl, conn, SASL_STOP);
+      return result;
+    }
+    else if (code == sasl->params->contcode) {
+      /* Acknowledge the continuation by sending a 0x01 response base64 encoded */
+      if (!(resp = strdup("AQ==")))
+        result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    else {
+      *progress = SASL_DONE;
+      state(sasl, conn, SASL_STOP);
+      return CURLE_LOGIN_DENIED;
+    }
+
   case SASL_CANCEL:
     /* Remove the offending mechanism from the supported list */
     sasl->authmechs ^= sasl->authused;
index fb44ac265edd7669f95f7c13fe0c411db62bddc7..2a8cc35c7071273ef86371300eb0aa000ca27227 100644 (file)
@@ -92,6 +92,7 @@ typedef enum {
   SASL_GSSAPI_TOKEN,
   SASL_GSSAPI_NO_DATA,
   SASL_OAUTH2,
+  SASL_OAUTH2_RESP,
   SASL_CANCEL,
   SASL_FINAL
 } saslstate;