curl-rust icon indicating copy to clipboard operation
curl-rust copied to clipboard

Returning error on second request on using authentication 'auto'

Open BerryJansen opened this issue 1 year ago • 0 comments

Hi guys,

Running into a error response which i can not explain. I'm using the curl library to send a POST towards an API. It works on my ubuntu server with the command

curl http://84.246.19.6:12088/api/v1/app/control/sensors/network_alarm -v --anyauth -u xxxx:xxxx -X POST -H "Content-Type: application/json" -d @/home/admin01/tmp_file.json > /home/admin01/output.txt

which pretty much just send

{ "network_alarm": { "version": "1.0", "state": "off", "channel": 0, "data": "whatever" } }

which results in curl verbose output

  • Trying 84.246.19.6:12088...
  • Connected to 84.246.19.6 (84.246.19.6) port 12088 (#465
  • POST /api/v1/app/control/sensors/network_alarm HTTP/1.1
  • Host: 84.246.19.6:12088
  • User-Agent: curl/7.81.0
  • Accept: /
  • Content-Type: application/json
  • Content-Length: 141
  • [141 bytes data]
  • Mark bundle as not supporting multiuse
  • HTTP/1.1 401 Unauthorized
  • Server: httpd/x.x.x (banner_disabled)
  • Date: Thu, 18 Jul 2024 13:47:53 GMT
  • Last-Modified: Thu, 18 Jul 2024 13:47:53 GMT
  • WWW-Authenticate: Digest realm="NVR WEB SERVER", qop="auth,auth-int", nonce="c73f811406eddc161602dd3baa46274e", opaque="799d51968be0c859890305713c8b80ee", algorithm=SHA-256
  • Ignoring duplicate digest auth header.
  • WWW-Authenticate: Digest realm="NVR WEB SERVER", qop="auth,auth-int", nonce="c73f811406eddc161602dd3baa46274e", opaque="dc23c9e509ca1a2e6d24b59fa56aba2d", algorithm=MD5
  • Content-Type: text/html
  • Content-Length: 289
  • Connection: close
  • Closing connection 0
  • Issue another request to this URL: 'http://84.246.19.6:12088/api/v1/app/control/sensors/network_alarm'
  • Hostname 84.246.19.6 was found in DNS cache
  • Trying 84.246.19.6:12088...
  • Connected to 84.246.19.6 (84.246.19.6) port 12088 (#1)
  • Server auth using Digest with user 'vaibs'
  • POST /api/v1/app/control/sensors/network_alarm HTTP/1.1
  • Host: 84.246.19.6:12088
  • Authorization: Digest username="vaibs", realm="NVR WEB SERVER", nonce="c73f811406eddc161602dd3baa46274e", uri="/api/v1/app/control/sensors/network_alarm", cnonce="Zjk0ZTlhYzgwMTI2NWMwMTk1OTZkZjRlODlmMDBlMWE=", nc=00000001, qop=auth, response="c95f7b5c453606cefbc1a8fa15ec9880bc1f63296047b54998fa74f1b890b2da", opaque="799d51968be0c859890305713c8b80ee", algorithm=SHA-256
  • User-Agent: curl/7.81.0
  • Accept: /
  • Content-Type: application/json
  • Content-Length: 141
  • Mark bundle as not supporting multiuse
  • HTTP/1.1 200 OK
  • Content-Type: application/json
  • Content-Length: 39
  • Cache-Control: no-cache
  • Connection: close

Works like a charm.

Now im trying the same in the Rust-curl library

use core::time;
use reqwest::StatusCode;

use log::{info, error};
use serde::{Deserialize, Serialize};
use curl::easy::{Easy, Auth, List};

use crate::VaibsSettings;
use crate::util;
use crate::{APP_NAME, APP_ORGANIZATION, APP_QUALIFER};

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]  // Deserialize is needed for post requests
pub struct ExternalHttpAlert {
    /// License plate number
    pub network_alarm: ExternalNetworkAlarm,   
}

#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)]  // Deserialize is needed for post requests
pub struct ExternalNetworkAlarm {
    /// Version is always 1.0
    pub version: String,
    /// State : "on" or "off"
    pub state : String,
    /// Channel : 0 = default
    pub channel: i64,
    /// data description
    pub data: String,   
}

pub async fn http_post_alert() -> (StatusCode, String) {
    
    let alarm = create_alarm(true, 0, String::from("Intrusion alert")); 
    info!("Created alarm : {:?}", alarm);     
    let body = serde_json::to_string_pretty(&alarm).unwrap();
    let data = body.as_bytes();

    let settings = VaibsSettings::pull();
    let mut handle = Easy::new();
    let url = util::build_http_url(settings.api_http_server_address, settings.api_http_server_port, settings.api_http_server_prefix);
    info!("Sending CURL POST to {}", url); 
    handle.url(&url).unwrap();
    handle.post(true).unwrap();
    handle.post_field_size(data.len() as u64).unwrap();
    handle.post_fields_copy(data).unwrap();
    handle.http_auth(Auth::new().auto(true)).unwrap();
    info!("Username : {}", settings.api_http_server_username); 
    handle.username(settings.api_http_server_username.as_str()).unwrap();
    info!("Password : {}", settings.api_http_server_password); 
    handle.password(settings.api_http_server_password.as_str()).unwrap();
    let mut headers = List::new();
    headers.append("Content-Type: application/json").unwrap();
    handle.http_headers(headers).unwrap();
    info!("Added headers"); 
    handle.timeout(time::Duration::from_secs(settings.api_http_server_timeout.into())).unwrap();
    //handle.transfer_encoding(false).unwrap();
    //handle.http_version(curl::easy::HttpVersion::V11).unwrap();
    //handle.http_content_decoding(false).unwrap();
    //handle.http_transfer_decoding(false).unwrap();
    //handle.ssl_verify_peer(false).unwrap();
    //handle.ssl_verify_host(false).unwrap();
    handle.verbose(true).unwrap();
    match handle.perform() {
        Ok(_) => info!("Sending CURL POST succesfull"), 
        Err(err) => error!("Sending CURL POST failed : {}", err),
    }
    (StatusCode::OK, String::from("Alert send"))
}

pub fn create_alarm(on: bool, channel : i64, data : String) -> ExternalHttpAlert {
    let state;
    if on {
        state =String::from("on");
    } else {
        state =String::from("off");        
    }
    let example = ExternalHttpAlert {
        network_alarm : ExternalNetworkAlarm {
        version : String::from("1.0"), 
        state :  state,
        channel : channel, 
        data: data           
        }
    };
    example
}

I'm getting this in return

  • Trying 84.246.19.6:12088...
  • Connected to 84.246.19.6 (84.246.19.6) port 12088
  • POST /api/v1/app/control/sensors/network_alarm HTTP/1.1
  • Host: 84.246.19.6:12088
  • Accept: /
  • Content-Type: application/json
  • Content-Length: 117
  • HTTP/1.1 401 Unauthorized
  • Server: httpd/x.x.x (banner_disabled)
  • Date: Thu, 18 Jul 2024 13:38:06 GMT
  • Last-Modified: Thu, 18 Jul 2024 13:38:06 GMT
  • WWW-Authenticate: Digest realm="NVR WEB SERVER", qop="auth,auth-int", nonce="d3d84a5b47bb37c5bbf2030b256c30b0", opaque="799d51968be0c859890305713c8b80ee", algorithm=SHA-256
  • Ignoring duplicate digest auth header.
  • WWW-Authenticate: Digest realm="NVR WEB SERVER", qop="auth,auth-int", nonce="d3d84a5b47bb37c5bbf2030b256c30b0", opaque="dc23c9e509ca1a2e6d24b59fa56aba2d", algorithm=MD5
  • Content-Type: text/html
  • Content-Length: 289
  • Connection: close
  • Need to rewind upload for next request
  • Closing connection
  • Issue another request to this URL: 'http://84.246.19.6:12088/api/v1/app/control/sensors/network_alarm'
  • Hostname 84.246.19.6 was found in DNS cache
  • Trying 84.246.19.6:12088...
  • Connected to 84.246.19.6 (84.246.19.6) port 12088
  • schannel: InitializeSecurityContext failed: SEC_E_QOP_NOT_SUPPORTED (0x8009030A) - De kwaliteit van bescherming per bericht wordt niet ondersteund door het beveiligingspakket
  • Connection #1 to host 84.246.19.6 left intact
  • Sending CURL POST failed : [94] An authentication function returned an error

It seems to go correctly the first request, but second issued request it doesnt seem to understand it should use Digest Auth.

The problem is the API does not support direct digest authentication, it only works if i use the --anyauth in the curl command.

Any suggestions?

BerryJansen avatar Jul 18 '24 14:07 BerryJansen