diff --git a/storage/src/backend/registry.rs b/storage/src/backend/registry.rs index 4c5b66b0720..6631c0708b4 100644 --- a/storage/src/backend/registry.rs +++ b/storage/src/backend/registry.rs @@ -144,7 +144,6 @@ struct BearerAuth { realm: String, service: String, scope: String, - header: Option, } #[derive(Debug)] @@ -255,8 +254,8 @@ impl RegistryState { } else { match self.get_token_with_post(&auth, connection) { Ok(resp) => resp, - Err(err) => { - warn!("retry http GET method to get auth token: {}", err); + Err(_) => { + warn!("retry http GET method to get auth token"); let resp = self.get_token_with_get(&auth, connection)?; // Cache http method for next use. self.cached_auth_using_http_get.set(self.host.clone(), true); @@ -301,18 +300,22 @@ impl RegistryState { form.insert("passward".to_string(), self.password.clone()); form.insert("client_id".to_string(), REGISTRY_CLIENT_ID.to_string()); - let mut headers = HeaderMap::new(); - let token_resp = connection .call::<&[u8]>( Method::POST, auth.realm.as_str(), None, Some(ReqBody::Form(form)), - &mut headers, + &mut HeaderMap::new(), true, ) - .map_err(|e| einval!(format!("registry auth server request failed {:?}", e)))?; + .map_err(|e| { + warn!( + "failed to request registry auth server by POST method: {:?}", + e + ); + einval!() + })?; Ok(token_resp) } @@ -334,6 +337,16 @@ impl RegistryState { let mut headers = HeaderMap::new(); + // Insert the basic auth header to ensure the compatibility (e.g. Harbor registry) + // of fetching token by HTTP GET method. + // This refers containerd implementation: https://github.com/containerd/containerd/blob/dc7dba9c20f7210c38e8255487fc0ee12692149d/remotes/docker/auth/fetch.go#L187 + if let Some(auth) = &self.auth { + headers.insert( + HEADER_AUTHORIZATION, + format!("Basic {}", auth).parse().unwrap(), + ); + } + let token_resp = connection .call::<&[u8]>( Method::GET, @@ -343,7 +356,13 @@ impl RegistryState { &mut headers, true, ) - .map_err(|e| einval!(format!("registry auth server request failed {:?}", e)))?; + .map_err(|e| { + warn!( + "failed to request registry auth server by GET method: {:?}", + e + ); + einval!() + })?; Ok(token_resp) } @@ -364,7 +383,7 @@ impl RegistryState { /// Parse `www-authenticate` response header respond from registry server /// The header format like: `Bearer realm="https://auth.my-registry.com/token",service="my-registry.com",scope="repository:test/repo:pull,push"` - fn parse_auth(source: &HeaderValue, auth: &Option) -> Option { + fn parse_auth(source: &HeaderValue) -> Option { let source = source.to_str().unwrap(); let source: Vec<&str> = source.splitn(2, ' ').collect(); if source.len() < 2 { @@ -401,15 +420,10 @@ impl RegistryState { return None; } - let header = auth - .as_ref() - .map(|auth| HeaderValue::from_str(&format!("Basic {}", auth)).unwrap()); - Some(Auth::Bearer(BearerAuth { realm: (*paras.get("realm").unwrap()).to_string(), service: (*paras.get("service").unwrap()).to_string(), scope: (*paras.get("scope").unwrap()).to_string(), - header, })) } _ => None, @@ -571,7 +585,7 @@ impl RegistryReader { if let Some(resp_auth_header) = resp.headers().get(HEADER_WWW_AUTHENTICATE) { // Get token from registry authorization server - if let Some(auth) = RegistryState::parse_auth(resp_auth_header, &self.state.auth) { + if let Some(auth) = RegistryState::parse_auth(resp_auth_header) { let auth_header = self .state .get_auth_header(auth, &self.connection) @@ -1066,7 +1080,7 @@ mod tests { fn test_parse_auth() { let str = "Bearer realm=\"https://auth.my-registry.com/token\",service=\"my-registry.com\",scope=\"repository:test/repo:pull,push\""; let header = HeaderValue::from_str(str).unwrap(); - let auth = RegistryState::parse_auth(&header, &None).unwrap(); + let auth = RegistryState::parse_auth(&header).unwrap(); match auth { Auth::Bearer(auth) => { assert_eq!(&auth.realm, "https://auth.my-registry.com/token"); @@ -1078,7 +1092,7 @@ mod tests { let str = "Basic realm=\"https://auth.my-registry.com/token\""; let header = HeaderValue::from_str(str).unwrap(); - let auth = RegistryState::parse_auth(&header, &None).unwrap(); + let auth = RegistryState::parse_auth(&header).unwrap(); match auth { Auth::Basic(auth) => assert_eq!(&auth.realm, "https://auth.my-registry.com/token"), _ => panic!("failed to pase `Bearer` authentication header"), @@ -1086,7 +1100,7 @@ mod tests { let str = "Base realm=\"https://auth.my-registry.com/token\""; let header = HeaderValue::from_str(str).unwrap(); - assert!(RegistryState::parse_auth(&header, &None).is_none()); + assert!(RegistryState::parse_auth(&header).is_none()); } #[test]