diff --git a/lib/config.go b/lib/config.go index dd60fec..3b8d1c2 100644 --- a/lib/config.go +++ b/lib/config.go @@ -33,6 +33,7 @@ type Config struct { credentials RegistryCredentials pageSize uint maxConcurrentRequests uint + basicAuth bool } func (u *urlValue) String() string { @@ -45,6 +46,7 @@ func (c *Config) BindToFlags(flags *flag.FlagSet) { flags.Var((*urlValue)(&c.registryUrl), "registry", "registry URL") flags.UintVar(&c.pageSize, "page-size", c.pageSize, "page size for paginated requests") flags.UintVar(&c.maxConcurrentRequests, "max-requests", c.maxConcurrentRequests, "concurrent API request limit") + flags.BoolVar(&c.basicAuth, "basic-auth", c.basicAuth, "use basic auth instead of token auth") c.credentials.BindToFlags(flags) } @@ -62,5 +64,6 @@ func NewConfig() Config { registryUrl: DEFAULT_REGISTRY_URL, pageSize: 100, maxConcurrentRequests: 5, + basicAuth: false, } } diff --git a/lib/connector/basic_auth_connector.go b/lib/connector/basic_auth_connector.go new file mode 100644 index 0000000..8ef8ed9 --- /dev/null +++ b/lib/connector/basic_auth_connector.go @@ -0,0 +1,57 @@ +package connector + +import ( + "net/http" + "net/url" + "strings" +) + +type basicAuthConnector struct { + cfg Config + httpClient *http.Client + semaphore semaphore + stat *statistics +} + +func (r *basicAuthConnector) Delete(url *url.URL, hint string) (*http.Response, error) { + return r.Request("DELETE", url, hint) +} + +func (r *basicAuthConnector) Get(url *url.URL, hint string) (*http.Response, error) { + return r.Request("GET", url, hint) +} + +func (r *basicAuthConnector) GetStatistics() Statistics { + return r.stat +} + +func (r *basicAuthConnector) Request(method string, url *url.URL, hint string) (response *http.Response, err error) { + r.semaphore.Lock() + defer r.semaphore.Unlock() + + r.stat.Request() + + request, err := http.NewRequest(method, url.String(), strings.NewReader("")) + + if err != nil { + return + } + + credentials := r.cfg.Credentials() + if credentials.Password() != "" || credentials.User() != "" { + request.SetBasicAuth(credentials.User(), credentials.Password()) + } + + response, err = r.httpClient.Do(request) + + return +} + +func NewBasicAuthConnector(cfg Config) Connector { + return &basicAuthConnector{ + cfg: cfg, + httpClient: http.DefaultClient, + semaphore: newSemaphore(cfg.MaxConcurrentRequests()), + stat: new(statistics), + } +} diff --git a/lib/connector/semaphore.go b/lib/connector/semaphore.go new file mode 100644 index 0000000..398897d --- /dev/null +++ b/lib/connector/semaphore.go @@ -0,0 +1,19 @@ +package connector + +type semaphore chan int + +func (s semaphore) Lock() { + s <- 1 +} + +func (s semaphore) Unlock() { + _ = <-s +} + +func newSemaphore(limit uint) semaphore { + if limit == 0 { + limit = 1 + } + + return semaphore(make(chan int, limit)) +} diff --git a/lib/connector/token_auth_config.go b/lib/connector/token_auth_config.go index eb16d69..1c30a7e 100644 --- a/lib/connector/token_auth_config.go +++ b/lib/connector/token_auth_config.go @@ -4,7 +4,7 @@ import ( "git.mayflower.de/vaillant-team/docker-ls/lib/auth" ) -type TokenAuthConfig interface { +type Config interface { MaxConcurrentRequests() uint Credentials() auth.RegistryCredentials } diff --git a/lib/connector/token_auth_connector.go b/lib/connector/token_auth_connector.go index 0999d14..290ccd7 100644 --- a/lib/connector/token_auth_connector.go +++ b/lib/connector/token_auth_connector.go @@ -1,6 +1,7 @@ package connector import ( + "errors" "net/http" "net/url" "strings" @@ -9,21 +10,12 @@ import ( ) type tokenAuthConnector struct { - cfg TokenAuthConfig + cfg Config httpClient *http.Client authenticator auth.Authenticator - semaphore chan int + semaphore semaphore tokenCache *tokenCache stat *statistics - basicAuth bool -} - -func (r *tokenAuthConnector) AquireLock() { - r.semaphore <- 1 -} - -func (r *tokenAuthConnector) ReleaseLock() { - _ = <-r.semaphore } func (r *tokenAuthConnector) Delete(url *url.URL, hint string) (*http.Response, error) { @@ -35,8 +27,8 @@ func (r *tokenAuthConnector) Get(url *url.URL, hint string) (*http.Response, err } func (r *tokenAuthConnector) Request(method string, url *url.URL, hint string) (response *http.Response, err error) { - r.AquireLock() - defer r.ReleaseLock() + r.semaphore.Lock() + defer r.semaphore.Unlock() r.stat.Request() @@ -73,6 +65,9 @@ func (r *tokenAuthConnector) Request(method string, url *url.URL, hint string) ( challenge, err := auth.ParseChallenge(resp.Header.Get("www-authenticate")) if err != nil { + err = errors.New(err.Error() + + " Are you shure that you are using the correct (token) auth scheme?") + return } @@ -126,11 +121,11 @@ func (r *tokenAuthConnector) GetStatistics() Statistics { return r.stat } -func NewTokenAuthConnector(cfg TokenAuthConfig) *tokenAuthConnector { +func NewTokenAuthConnector(cfg Config) Connector { connector := tokenAuthConnector{ cfg: cfg, httpClient: http.DefaultClient, - semaphore: make(chan int, cfg.MaxConcurrentRequests()), + semaphore: newSemaphore(cfg.MaxConcurrentRequests()), tokenCache: newTokenCache(), stat: new(statistics), } diff --git a/lib/connector_factory.go b/lib/connector_factory.go index 5be812c..910ab5c 100644 --- a/lib/connector_factory.go +++ b/lib/connector_factory.go @@ -5,5 +5,8 @@ import ( ) func createConnector(cfg *Config) connector.Connector { + if cfg.basicAuth { + return connector.NewBasicAuthConnector(cfg) + } return connector.NewTokenAuthConnector(cfg) }