Skip to content

Commit ca8ce45

Browse files
authored
Add support for aws-sigv4 authentication (#401)
Closes #392
1 parent f56f767 commit ca8ce45

File tree

7 files changed

+82
-1
lines changed

7 files changed

+82
-1
lines changed

Cargo.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,8 @@ required-features = ["ssl"]
6464
name = "ssl_cert_blob"
6565
path = "examples/ssl_cert_blob.rs"
6666
required-features = ["ssl"]
67+
68+
[[example]]
69+
name = "aws_sigv4"
70+
path = "examples/aws_sigv4.rs"
71+
required-features = ["static-curl", "ssl"]

curl-sys/build.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ fn main() {
109109
.include("curl/lib")
110110
.include("curl/include")
111111
.define("BUILDING_LIBCURL", None)
112-
.define("CURL_DISABLE_CRYPTO_AUTH", None)
113112
.define("CURL_DISABLE_DICT", None)
114113
.define("CURL_DISABLE_GOPHER", None)
115114
.define("CURL_DISABLE_IMAP", None)
@@ -127,6 +126,7 @@ fn main() {
127126
.define("HAVE_ASSERT_H", None)
128127
.define("OS", "\"unknown\"") // TODO
129128
.define("HAVE_ZLIB_H", None)
129+
.define("HAVE_LONGLONG", None)
130130
.define("HAVE_LIBZ", None)
131131
.define("HAVE_BOOL_T", None)
132132
.define("HAVE_STDBOOL_H", None)
@@ -154,19 +154,23 @@ fn main() {
154154
.file("curl/lib/getenv.c")
155155
.file("curl/lib/getinfo.c")
156156
.file("curl/lib/hash.c")
157+
.file("curl/lib/hmac.c")
157158
.file("curl/lib/hostasyn.c")
158159
.file("curl/lib/hostcheck.c")
159160
.file("curl/lib/hostip.c")
160161
.file("curl/lib/hostip6.c")
161162
.file("curl/lib/hsts.c")
162163
.file("curl/lib/http.c")
163164
.file("curl/lib/http2.c")
165+
.file("curl/lib/http_aws_sigv4.c")
164166
.file("curl/lib/http_chunks.c")
167+
.file("curl/lib/http_digest.c")
165168
.file("curl/lib/http_proxy.c")
166169
.file("curl/lib/if2ip.c")
167170
.file("curl/lib/inet_ntop.c")
168171
.file("curl/lib/inet_pton.c")
169172
.file("curl/lib/llist.c")
173+
.file("curl/lib/md5.c")
170174
.file("curl/lib/mime.c")
171175
.file("curl/lib/mprintf.c")
172176
.file("curl/lib/mqtt.c")
@@ -180,6 +184,7 @@ fn main() {
180184
.file("curl/lib/select.c")
181185
.file("curl/lib/sendf.c")
182186
.file("curl/lib/setopt.c")
187+
.file("curl/lib/sha256.c")
183188
.file("curl/lib/share.c")
184189
.file("curl/lib/slist.c")
185190
.file("curl/lib/socks.c")
@@ -196,6 +201,7 @@ fn main() {
196201
.file("curl/lib/url.c")
197202
.file("curl/lib/urlapi.c")
198203
.file("curl/lib/version.c")
204+
.file("curl/lib/vauth/digest.c")
199205
.file("curl/lib/vtls/keylog.c")
200206
.file("curl/lib/vtls/vtls.c")
201207
.file("curl/lib/warnless.c")
@@ -253,11 +259,16 @@ fn main() {
253259
}
254260
} else if cfg!(feature = "ssl") {
255261
if windows {
262+
// For windows, spnego feature is auto on in case ssl feature is on.
263+
// Please see definition of USE_SPNEGO in curl_setup.h for more info.
256264
cfg.define("USE_WINDOWS_SSPI", None)
257265
.define("USE_SCHANNEL", None)
266+
.file("curl/lib/http_negotiate.c")
258267
.file("curl/lib/x509asn1.c")
259268
.file("curl/lib/curl_sspi.c")
260269
.file("curl/lib/socks_sspi.c")
270+
.file("curl/lib/vauth/spnego_sspi.c")
271+
.file("curl/lib/vauth/vauth.c")
261272
.file("curl/lib/vtls/schannel.c")
262273
.file("curl/lib/vtls/schannel_verify.c");
263274
} else if target.contains("-apple-") {
@@ -287,8 +298,10 @@ fn main() {
287298
.define("USE_THREADS_WIN32", None)
288299
.define("HAVE_IOCTLSOCKET_FIONBIO", None)
289300
.define("USE_WINSOCK", None)
301+
.file("curl/lib/bufref.c")
290302
.file("curl/lib/system_win32.c")
291303
.file("curl/lib/version_win32.c")
304+
.file("curl/lib/vauth/digest_sspi.c")
292305
.file("curl/lib/curl_multibyte.c");
293306

294307
if cfg!(feature = "spnego") {

curl-sys/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ pub const CURLAUTH_GSSNEGOTIATE: c_ulong = 1 << 2;
310310
pub const CURLAUTH_NTLM: c_ulong = 1 << 3;
311311
pub const CURLAUTH_DIGEST_IE: c_ulong = 1 << 4;
312312
pub const CURLAUTH_NTLM_WB: c_ulong = 1 << 5;
313+
pub const CURLAUTH_AWS_SIGV4: c_ulong = 1 << 7;
313314
// pub const CURLAUTH_ONLY: c_ulong = 1 << 31;
314315
pub const CURLAUTH_ANY: c_ulong = !CURLAUTH_DIGEST_IE;
315316
pub const CURLAUTH_ANYSAFE: c_ulong = !(CURLAUTH_BASIC | CURLAUTH_DIGEST_IE);
@@ -602,6 +603,8 @@ pub const CURLOPT_PROXY_SSLCERT_BLOB: CURLoption = CURLOPTTYPE_BLOB + 293;
602603
pub const CURLOPT_PROXY_SSLKEY_BLOB: CURLoption = CURLOPTTYPE_BLOB + 294;
603604
pub const CURLOPT_ISSUERCERT_BLOB: CURLoption = CURLOPTTYPE_BLOB + 295;
604605

606+
pub const CURLOPT_AWS_SIGV4: CURLoption = CURLOPTTYPE_OBJECTPOINT + 305;
607+
605608
pub const CURL_IPRESOLVE_WHATEVER: c_int = 0;
606609
pub const CURL_IPRESOLVE_V4: c_int = 1;
607610
pub const CURL_IPRESOLVE_V6: c_int = 2;

examples/aws_sigv4.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use anyhow::Result;
2+
3+
use curl::easy::Easy;
4+
5+
fn main() -> Result<()> {
6+
let mut handle = Easy::new();
7+
handle.verbose(true)?;
8+
handle.url("https://ec2.us-east-1.amazonaws.com/?Action=DescribeRegions&Version=2013-10-15")?;
9+
handle.aws_sigv4("aws:amz")?;
10+
handle.username("myAccessKeyId")?;
11+
handle.password("mySecretAccessKey")?;
12+
handle.perform()?;
13+
Ok(())
14+
}

src/easy/handle.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,11 @@ impl Easy {
696696
self.inner.http_auth(auth)
697697
}
698698

699+
/// Same as [`Easy2::aws_sigv4`](struct.Easy2.html#method.aws_sigv4)
700+
pub fn aws_sigv4(&mut self, param: &str) -> Result<(), Error> {
701+
self.inner.aws_sigv4(param)
702+
}
703+
699704
/// Same as [`Easy2::proxy_username`](struct.Easy2.html#method.proxy_username)
700705
pub fn proxy_username(&mut self, user: &str) -> Result<(), Error> {
701706
self.inner.proxy_username(user)

src/easy/handler.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,33 @@ impl<H> Easy2<H> {
11531153
self.setopt_long(curl_sys::CURLOPT_HTTPAUTH, auth.bits)
11541154
}
11551155

1156+
/// Provides AWS V4 signature authentication on HTTP(S) header.
1157+
///
1158+
/// `param` is used to create outgoing authentication headers.
1159+
/// Its format is `provider1[:provider2[:region[:service]]]`.
1160+
/// `provider1,\ provider2"` are used for generating auth parameters
1161+
/// such as "Algorithm", "date", "request type" and "signed headers".
1162+
/// `region` is the geographic area of a resources collection. It is
1163+
/// extracted from the host name specified in the URL if omitted.
1164+
/// `service` is a function provided by a cloud. It is extracted
1165+
/// from the host name specified in the URL if omitted.
1166+
///
1167+
/// Example with "Test:Try", when curl will do the algorithm, it will
1168+
/// generate "TEST-HMAC-SHA256" for "Algorithm", "x-try-date" and
1169+
/// "X-Try-Date" for "date", "test4_request" for "request type", and
1170+
/// "SignedHeaders=content-type;host;x-try-date" for "signed headers".
1171+
/// If you use just "test", instead of "test:try", test will be use
1172+
/// for every strings generated.
1173+
///
1174+
/// This is a special auth type that can't be combined with the others.
1175+
/// It will override the other auth types you might have set.
1176+
///
1177+
/// By default this is not set and corresponds to `CURLOPT_AWS_SIGV4`.
1178+
pub fn aws_sigv4(&mut self, param: &str) -> Result<(), Error> {
1179+
let param = CString::new(param)?;
1180+
self.setopt_str(curl_sys::CURLOPT_AWS_SIGV4, &param)
1181+
}
1182+
11561183
/// Configures the proxy username to pass as authentication for this
11571184
/// connection.
11581185
///
@@ -3385,6 +3412,17 @@ impl Auth {
33853412
self.flag(curl_sys::CURLAUTH_NTLM_WB, on)
33863413
}
33873414

3415+
/// HTTP AWS V4 signature authentication.
3416+
///
3417+
/// This is a special auth type that can't be combined with the others.
3418+
/// It will override the other auth types you might have set.
3419+
///
3420+
/// Enabling this auth type is the same as using "aws:amz" as param in
3421+
/// [`Easy2::aws_sigv4`](struct.Easy2.html#method.aws_sigv4) method.
3422+
pub fn aws_sigv4(&mut self, on: bool) -> &mut Auth {
3423+
self.flag(curl_sys::CURLAUTH_AWS_SIGV4, on)
3424+
}
3425+
33883426
fn flag(&mut self, bit: c_ulong, on: bool) -> &mut Auth {
33893427
if on {
33903428
self.bits |= bit as c_long;
@@ -3408,6 +3446,7 @@ impl fmt::Debug for Auth {
34083446
)
34093447
.field("ntlm", &(bits & curl_sys::CURLAUTH_NTLM != 0))
34103448
.field("ntlm_wb", &(bits & curl_sys::CURLAUTH_NTLM_WB != 0))
3449+
.field("aws_sigv4", &(bits & curl_sys::CURLAUTH_AWS_SIGV4 != 0))
34113450
.finish()
34123451
}
34133452
}

systest/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ fn main() {
7878
}
7979
if version < 75 {
8080
match s {
81+
"CURLAUTH_AWS_SIGV4" => return true,
82+
"CURLOPT_AWS_SIGV4" => return true,
8183
"CURLVERSION_NINTH" => return true,
8284
_ => {}
8385
}

0 commit comments

Comments
 (0)