public IDockerClient GetClient(IAuthHandler auth) { var host = auth.GetRegistryHost(config.IgnoreInternalAlias); if (string.IsNullOrEmpty(config.RegistryRoot)) { /* this is convoluted. The local client needs to call back to the remote client to fetch layers or other blobs as needed, but the remote client needs to call down * to the local client to actually load data, interperet manifests, etc. So, a circular dependency exists. Still waiting on an epiphany to make it cleaner. */ var httpClient = new HttpClient(new AuthenticatedParameterizedHttpClientHandler(ClientTokenCallback(auth))) { BaseAddress = new Uri(RegistryCredentials.HostToEndpoint(host)) }; var service = RestService.For <IDockerDistribution>(httpClient); var localClient = new LocalDockerClient(config, indexer, extractor, auth, loggerFactory.CreateLogger <LocalDockerClient>()) { RegistryRoot = config.RegistryCache, Host = host }; var remoteClient = new RemoteDockerClient(config, auth, service, localClient, cacheFactory) { Host = host }; localClient.RecurseClient = remoteClient; var cachedClient = new CachedDockerClient(config, remoteClient, cacheFactory, auth) { Host = host, CacheLocalData = config.LocalCache }; return(cachedClient); } else if (config.LocalCache) { var localClient = new LocalDockerClient(config, indexer, extractor, auth, loggerFactory.CreateLogger <LocalDockerClient>()) { RegistryRoot = config.RegistryRoot }; var cachedClient = new CachedDockerClient(config, localClient, cacheFactory, auth) { Host = host, CacheLocalData = config.LocalCache }; return(cachedClient); } else { return(new LocalDockerClient(config, indexer, extractor, auth, loggerFactory.CreateLogger <LocalDockerClient>()) { RegistryRoot = config.RegistryRoot }); } }
public override async Task DoRequestAsync(ScanRequest request) { try { RegistryCredentials credentials = null; // if the request was submitted by a user, it must have auth info included if (!string.IsNullOrEmpty(request.Authorization)) { var authResult = authDecoder.AuthenticateAsync(request.Authorization).Result; if (authResult.Succeeded) { credentials = authResult.Principal.ToRegistryCredentials(); } } // if the request came via an event sink, there is no auth provided, and we need to have a default user configured else { credentials = config.GetCatalogCredentials() ?? throw new ArgumentException("The indexing request had no included authorization, and no default catalog user is configured."); } if (credentials == null) { logger.LogError("Authorization failed for the work item. A token may have expired since it was first submitted."); } else { await authHandler.LoginAsync(credentials); var scope = authHandler.RepoPullScope(request.TargetRepo); if (await authHandler.AuthorizeAsync(scope)) { var proxyAuth = authHandler.TokensRequired ? $"Bearer {(await authHandler.GetAuthorizationAsync(scope)).Parameter}" : string.Empty; var client = clientFactory.GetClient(authHandler); var imageSet = await client.GetImageSetAsync(request.TargetRepo, request.TargetDigest); if ((imageSet?.Images?.Count() ?? 0) != 1) { throw new Exception($"Couldn't find a valid image for {request.TargetRepo}:{request.TargetDigest}"); } var scanResult = scanner.GetScan(imageSet.Images.First()); if (scanResult == null) { if (request.Submitted) { // we've already submitted this one to the scanner, just sleep on it for a few seconds Thread.Sleep(2000); } else { var host = authHandler.GetRegistryHost(); scanner.RequestScan(request.TargetRepo, imageSet.Images.First(), host, proxyAuth); logger.LogInformation($"Submitted {request.TargetRepo}:{request.TargetDigest} to {scanner.GetType().Name} for analysis."); request.Submitted = true; } queue.Push(request); } else { logger.LogInformation($"Got latest {scanner.GetType().Name} scan for {request.TargetRepo}:{request.TargetDigest}"); } } else { logger.LogError($"Failed to get pull authorization for {request.TargetRepo}"); } } } catch (Exception ex) { logger.LogError(ex, $"Processing failed for work item\n {Newtonsoft.Json.JsonConvert.SerializeObject(request)}"); } }