Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

S3 HEAD request 403 error #868

Closed
wlandau opened this issue Jan 2, 2025 · 7 comments · Fixed by #870
Closed

S3 HEAD request 403 error #868

wlandau opened this issue Jan 2, 2025 · 7 comments · Fixed by #870
Labels
bug 🐞 Something isn't working

Comments

@wlandau
Copy link

wlandau commented Jan 2, 2025

The following reprex runs without error in the current CRAN versions of paws.common and paws.storage (0.7.7 and 0.7.0) but throws an error using the development versions (0.8.0 for both).

library(paws.common)
library(paws.storage)
print(packageVersion("paws.common"))
#> [1] '0.8.0'
print(packageVersion("paws.storage"))
#> [1] '0.8.0'
print(packageDescription("paws.common")$GithubSHA1)
#> [1] "91ac7519189ff4026b0559689b0ad8d01c4945b3"
print(packageDescription("paws.storage")$GithubSHA1)
#> [1] "91ac7519189ff4026b0559689b0ad8d01c4945b3"
client <- s3()
bucket <- "test-paws-common-partial-matches-11"
response <- client$create_bucket(Bucket = bucket)
response <- client$put_object(
  Bucket = bucket,
  Key = "x",
  Body = charToRaw("abcde")
)
options(warnPartialMatchArgs = TRUE)
response <- client$head_object(Bucket = bucket, Key = "x")
#> Error: SignatureDoesNotMatch (HTTP 403). The request signature we calculated does not match the signature you provided. Check your key and signing method.

Created on 2025-01-02 with reprex v2.1.1

Session info
sessioninfo::session_info()
#> ─ Session info ───────────────────────────────────────────────────────────────
#>  setting  value
#>  version  R version 4.4.0 (2024-04-24)
#>  os       macOS 15.2
#>  system   aarch64, darwin20
#>  ui       X11
#>  language (EN)
#>  collate  en_US.UTF-8
#>  ctype    en_US.UTF-8
#>  tz       America/Indiana/Indianapolis
#>  date     2025-01-02
#>  pandoc   3.2 @ /Applications/RStudio.app/Contents/Resources/app/quarto/bin/tools/aarch64/ (via rmarkdown)
#> 
#> ─ Packages ───────────────────────────────────────────────────────────────────
#>  package      * version  date (UTC) lib source
#>  base64enc      0.1-3    2015-07-28 [1] CRAN (R 4.4.0)
#>  cli            3.6.3    2024-06-21 [1] CRAN (R 4.4.0)
#>  crayon         1.5.3    2024-06-20 [1] CRAN (R 4.4.0)
#>  curl           6.0.1    2024-11-14 [1] CRAN (R 4.4.1)
#>  digest         0.6.37   2024-08-19 [1] CRAN (R 4.4.1)
#>  evaluate       1.0.1    2024-10-10 [1] CRAN (R 4.4.1)
#>  fastmap        1.2.0    2024-05-15 [1] CRAN (R 4.4.0)
#>  fs             1.6.4    2024-04-25 [1] CRAN (R 4.4.0)
#>  glue           1.8.0    2024-09-30 [1] CRAN (R 4.4.0)
#>  htmltools      0.5.8.1  2024-04-04 [1] CRAN (R 4.4.0)
#>  httr2          1.0.7    2024-11-26 [1] CRAN (R 4.4.1)
#>  knitr          1.48     2024-07-07 [1] CRAN (R 4.4.0)
#>  lifecycle      1.0.4    2023-11-07 [1] CRAN (R 4.4.0)
#>  magrittr       2.0.3    2022-03-30 [1] CRAN (R 4.4.0)
#>  paws.common  * 0.8.0    2025-01-02 [1] Github (paws-r/paws@91ac751)
#>  paws.storage * 0.8.0    2025-01-02 [1] Github (paws-r/paws@91ac751)
#>  R6             2.5.1    2021-08-19 [1] CRAN (R 4.4.0)
#>  rappdirs       0.3.3    2021-01-31 [1] CRAN (R 4.4.0)
#>  Rcpp           1.0.13-1 2024-11-02 [1] CRAN (R 4.4.1)
#>  reprex         2.1.1    2024-07-06 [1] CRAN (R 4.4.0)
#>  rlang          1.1.4    2024-06-04 [1] CRAN (R 4.4.0)
#>  rmarkdown      2.28     2024-08-17 [1] CRAN (R 4.4.0)
#>  rstudioapi     0.16.0   2024-03-24 [1] CRAN (R 4.4.0)
#>  sessioninfo    1.2.2    2021-12-06 [1] CRAN (R 4.4.0)
#>  withr          3.0.2    2024-10-28 [1] CRAN (R 4.4.1)
#>  xfun           0.49     2024-10-31 [1] CRAN (R 4.4.1)
#>  xml2           1.3.6    2023-12-04 [1] CRAN (R 4.4.0)
#>  yaml           2.3.10   2024-07-26 [1] CRAN (R 4.4.0)
#> 
#>  [1] /Library/Frameworks/R.framework/Versions/4.4-arm64/Resources/library
#> 
#> ──────────────────────────────────────────────────────────────────────────────
@DyfanJones DyfanJones added the bug 🐞 Something isn't working label Jan 2, 2025
@DyfanJones
Copy link
Member

Ah thanks for identify the issue before it goes live :) I will look into it.

@DyfanJones
Copy link
Member

Interesting this appears to be happening due to httr2. When I switched back to httr (but kept all the other changes) it worked. I must be doing something wrong with the heads within httr2.

@DyfanJones
Copy link
Member

DyfanJones commented Jan 3, 2025

So when i comment out all the httr2 and replace with httr. The connection works fine.

request_aws <- function(url, http_request) {
  # req <- httr2::request(url)
  # req$method <- http_request$method
  # req$headers <- http_request$header
  # req$policies$error_is_error <- function(resp) FALSE
  # if (!is.null(http_request$body)) {
  #   req$body <- list(data = http_request$body, type = "raw", content_type = "", params = list())
  # }
  # req <- req_options(
  #   .req = req,
  #   timeout_ms = http_request$timeout * 1000,
  #   connecttimeout = http_request$connect_timeout,
  #   debugfunction = paws_debug,
  #   verbose = isTRUE(getOption("paws.log_level") >= 3L)
  # )
  # if (http_request$stream_api) {
  #   return(req_perform_connection(req))
  # } else {
    dest <- NULL
    if (!is.null(http_request$dest)) {
      dest <- httr::write_disk(http_request$dest, TRUE)
    }
    timeout_config <- Filter(
      Negate(is.null),
      list(connecttimeout = http_request$connect_timeout, timeout = http_request$timeout)
    )
    timeout <- do.call(httr::config, timeout_config)
    httr::VERB(
      http_request$method,
      url = url,
      config = c(httr::add_headers(.headers = unlist(http_request$header)), dest),
      body = http_request$body,
      httr::verbose(),
      timeout
    )
    # return(req_perform(req, path = http_request$dest))
  # }
}

@DyfanJones
Copy link
Member

DyfanJones commented Jan 3, 2025

library(paws)
 
client <- s3(config(credentials(profile = "paws")))

bucket <- "test-paws-common-head-bucket-1"

response <- client$head_object(
   Bucket = bucket,
   Key = "x"
)
# -> HEAD /x HTTP/1.1
# -> Host: test-paws-common-head-bucket-1.s3.amazonaws.com
# -> Accept-Encoding: deflate, gzip
# -> Accept: application/json, text/xml, application/xml, */*
# -> User-Agent: paws/0.8.0 (R4.4.2; darwin20; aarch64)
# -> Content-Length: 0
# -> X-Amz-Date: 20250103T124113Z
# -> X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
# -> Authorization: AWS4-HMAC-SHA256 Credential=DUMMY/20250103/us-east-1/s3/aws4_request, SignedHeaders=content-length;host;x-amz-content-sha256;x-amz-date, Signature=986495378caa6eb14a543e497582e2a8050c0fd6117856c5050306201c7f2905
# -> 
# <- HTTP/1.1 200 OK
# <- x-amz-id-2: 1dnQkiY4Xns0f2wz/0M25mbRPHeK7i/BqqJaeiepk94TX1bb5OI9mvk0DRcsRJDc48cPilyOyGE=
# <- x-amz-request-id: J7MGZKN4JPWQ23H0
# <- Date: Fri, 03 Jan 2025 12:41:15 GMT
# <- Last-Modified: Thu, 02 Jan 2025 16:50:50 GMT
# <- ETag: "ab56b4d92b40713acc5af89985d4b786"
# <- x-amz-server-side-encryption: AES256
# <- Accept-Ranges: bytes
# <- Content-Type: binary/octet-stream
# <- Content-Length: 5
# <- Server: AmazonS3
# <- 

@DyfanJones
Copy link
Member

Oh hang on it looks like httr2 is using "POST" method instead of HEAD

DEBUG [2025-01-03 13:18:50.158]: -> POST /x HTTP/1.1
-> Host: test-paws-common-head-bucket-1.s3.amazonaws.com
-> Accept: */*
-> Accept-Encoding: deflate, gzip
-> User-Agent: paws/0.8.0 (R4.4.2; darwin20; aarch64)
-> Content-Length: 0
-> X-Amz-Date: 20250103T131157Z
-> X-Amz-Content-Sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
-> Authorization: AWS4-HMAC-SHA256 Credential= DUMMY/20250103/us-east-1/s3/aws4_request, SignedHeaders=content-length;host;x-amz-content-sha256;x-amz-date, Signature=ee02777c2bbd78a9d3a6fbb3427ddd7b9e44c3c97d796b175eb162c8211374ef
-> 

@DyfanJones
Copy link
Member

DyfanJones commented Jan 3, 2025

I think I have found the issue.

if (!is.null(http_request$body)) {
   req$body <- list(data = http_request$body, type = "raw", content_type = "", params = list())
}

This will add a body regardless. So if we add a check on the method as well this should ensure we send an empty body for HEAD calls.

if (!is.null(http_request$body) && http_request$method != "HEAD") {
  req$body <- list(data = http_request$body, type = "raw", content_type = "", params = list())
}

@wlandau
Copy link
Author

wlandau commented Jan 3, 2025

Thanks! #870 fixes it for me.

@DyfanJones DyfanJones added this to the Paws 0.8.0 cran release milestone Jan 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐞 Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants