@@ -51,6 +51,7 @@ using namespace photon::net::http;
5151static const estring kDockerRegistryAuthChallengeKeyValuePrefix = " www-authenticate" ;
5252static const estring kAuthHeaderKey = " Authorization" ;
5353static const estring kBearerAuthPrefix = " Bearer " ;
54+ static const estring kBasicAuthPrefix = " Basic " ;
5455static const uint64_t kMinimalTokenLife = 30L * 1000 * 1000 ; // token lives atleast 30s
5556static const uint64_t kMinimalAUrlLife = 300L * 1000 * 1000 ; // actual_url lives atleast 300s
5657static const uint64_t kMinimalMetaLife = 300L * 1000 * 1000 ; // actual_url lives atleast 300s
@@ -84,6 +85,13 @@ struct UrlInfo {
8485 estring info;
8586};
8687
88+ enum class AuthType {
89+ Unknown,
90+ None,
91+ Basic,
92+ Bearer
93+ };
94+
8795class RegistryFSImpl_v2 : public RegistryFS {
8896public:
8997 UNIMPLEMENTED_POINTER (IFile *creat (const char *, mode_t ) override );
@@ -197,10 +205,12 @@ class RegistryFSImpl_v2 : public RegistryFS {
197205 Timeout tmo (timeout);
198206 estring authurl, scope;
199207 estring *token = nullptr ;
200- if (get_scope_auth (url, &authurl, &scope, tmo.timeout ()) < 0 )
208+
209+ auto authtype = get_scope_auth (url, &authurl, &scope, tmo.timeout ());
210+ if (authtype == AuthType::Unknown)
201211 return nullptr ;
202212
203- if (!scope.empty ()) {
213+ if (authtype == AuthType::Bearer && !scope.empty ()) {
204214 token = m_scope_token.acquire (scope, [&]() -> estring * {
205215 estring *token = new estring ();
206216 if (get_token (url, authurl, *token, tmo.timeout ()) < 0 ) {
@@ -217,9 +227,15 @@ class RegistryFSImpl_v2 : public RegistryFS {
217227 HTTP_OP op (m_client, Verb::GET, url);
218228 op.follow = 0 ;
219229 op.retry = 0 ;
220- if (token && !token->empty ()) {
230+ if (authtype == AuthType::Bearer && token && !token->empty ()) {
221231 op.req .headers .insert (kAuthHeaderKey , " Bearer " );
222232 op.req .headers .value_append (*token);
233+ } else if (authtype == AuthType::Basic) {
234+ auto auth = m_callback (url.data ());
235+ estring userpwd_b64;
236+ photon::net::Base64Encode (estring ().appends (auth.first , " :" , auth.second ), userpwd_b64);
237+ op.req .headers .insert (kAuthHeaderKey , " Basic " );
238+ op.req .headers .value_append (userpwd_b64);
223239 }
224240 op.timeout = tmo.timeout ();
225241 op.call ();
@@ -236,8 +252,15 @@ class RegistryFSImpl_v2 : public RegistryFS {
236252 }
237253 if (code == 200 ) {
238254 UrlInfo *info = new UrlInfo{UrlMode::Self, " " };
239- if (token && !token->empty ())
255+ if (authtype == AuthType::Bearer && token && !token->empty ())
240256 info->info = kBearerAuthPrefix + *token;
257+ else if (authtype == AuthType::Basic) {
258+ auto auth = m_callback (url.data ());
259+ estring userpwd_b64;
260+ photon::net::Base64Encode (estring ().appends (auth.first , " :" , auth.second ), userpwd_b64);
261+ info->info = kBasicAuthPrefix + userpwd_b64;
262+ }
263+
241264 if (!scope.empty ())
242265 m_scope_token.release (scope);
243266 return info;
@@ -268,8 +291,11 @@ class RegistryFSImpl_v2 : public RegistryFS {
268291 int refresh_token (const estring &url, estring &token) {
269292 estring authurl, scope;
270293 Timeout tmo (m_timeout);
271- if (get_scope_auth (url, &authurl, &scope, tmo.timeout (), true ) < 0 )
294+ auto authtype = get_scope_auth (url, &authurl, &scope, tmo.timeout (), true );
295+ if (authtype == AuthType::Unknown)
272296 return -1 ;
297+ if (authtype == AuthType::Basic || authtype == AuthType::None)
298+ return 0 ;
273299 if (!scope.empty ()) {
274300 get_token (url, authurl, token, tmo.timeout ());
275301 if (token.empty ()) {
@@ -290,7 +316,7 @@ class RegistryFSImpl_v2 : public RegistryFS {
290316 ObjectCache<estring, estring *> m_scope_token;
291317 ObjectCache<estring, UrlInfo *> m_url_info;
292318
293- int get_scope_auth (const estring &url, estring *authurl, estring *scope, uint64_t timeout,
319+ AuthType get_scope_auth (const estring &url, estring *authurl, estring *scope, uint64_t timeout,
294320 bool push = false ) {
295321 Timeout tmo (timeout);
296322 auto verb = push ? Verb::POST : Verb::GET;
@@ -305,32 +331,40 @@ class RegistryFSImpl_v2 : public RegistryFS {
305331 op.timeout = tmo.timeout ();
306332 op.call ();
307333 if (op.status_code == -1 )
308- LOG_ERROR_RETURN (ENOENT, - 1 , " connection failed" );
334+ LOG_ERROR_RETURN (ENOENT, AuthType::Unknown , " connection failed" );
309335
310336 // going to challenge
311337 if (op.status_code != 401 && op.status_code != 403 ) {
312338 // no token request accepted, seems token not need;
313- return 0 ;
339+ return AuthType::None ;
314340 }
315341
316342 auto it = op.resp .headers .find (kDockerRegistryAuthChallengeKeyValuePrefix );
317343 if (it == op.resp .headers .end ())
318- LOG_ERROR_RETURN (EINVAL, - 1 , " no auth header in response" );
344+ LOG_ERROR_RETURN (EINVAL, AuthType::Unknown , " no auth header in response" );
319345 estring challengeLine = it.second ();
320- if (!challengeLine.starts_with (kBearerAuthPrefix ))
321- LOG_ERROR_RETURN (EINVAL, -1 , " auth string shows not bearer auth, " ,
346+
347+ estring prefix = " " ;
348+
349+ if (challengeLine.starts_with (kBearerAuthPrefix ))
350+ prefix = kBearerAuthPrefix ;
351+ else if (challengeLine.starts_with (kBasicAuthPrefix ))
352+ return AuthType::Basic;
353+ else
354+ LOG_ERROR_RETURN (EINVAL, AuthType::Unknown, " auth string shows not bearer or basic auth, " ,
322355 VALUE (challengeLine));
323- challengeLine = challengeLine.substr (kBearerAuthPrefix .length ());
356+
357+ challengeLine = challengeLine.substr (prefix.length ());
324358 auto kv = str_to_kvmap (challengeLine);
325359 if (kv.find (" realm" ) == kv.end () || kv.find (" service" ) == kv.end () ||
326360 kv.find (" scope" ) == kv.end ()) {
327- LOG_ERROR_RETURN (EINVAL, - 1 , " authentication challenge failed with `" ,
361+ LOG_ERROR_RETURN (EINVAL, AuthType::Unknown , " authentication challenge failed with `" ,
328362 challengeLine);
329363 }
330364 *scope = estring (kv[" scope" ]);
331365 *authurl = estring ().appends (kv[" realm" ], " ?service=" , kv[" service" ],
332366 " &scope=" , kv[" scope" ]);
333- return 0 ;
367+ return AuthType::Bearer ;
334368 }
335369
336370 int parse_token (const estring &jsonStr, estring *token) {
0 commit comments