Skip to content

Commit

Permalink
Merge pull request #8 from armosec/fix-auth
Browse files Browse the repository at this point in the history
Fix auth
  • Loading branch information
Daniel-GrunbergerCA authored Dec 18, 2022
2 parents 45cf3e9 + 4515dde commit 7cd04f9
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 75 deletions.
2 changes: 1 addition & 1 deletion interfaces/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
)

type IRegistry interface {
Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) (repositories []string, nextPage *common.PaginationOption, statusCode int, err error)
Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) (repositories []string, nextPage *common.PaginationOption, err error)
List(repoName string, pagination common.PaginationOption, options ...remote.Option) (tags []string, nextPagination *common.PaginationOption, err error)
GetLatestTags(repoName string, depth int, options ...remote.Option) (tags []string, err error)
GetAuth() *authn.AuthConfig
Expand Down
59 changes: 26 additions & 33 deletions registries/defaultregistry/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/google/go-containerregistry/pkg/authn"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/google/go-containerregistry/pkg/v1/remote/transport"
"github.com/google/go-containerregistry/pkg/v1/types"
version "github.com/hashicorp/go-version"
"k8s.io/utils/strings/slices"
Expand Down Expand Up @@ -77,27 +76,22 @@ func (reg *DefaultRegistry) List(repoName string, pagination common.PaginationOp
}

// this is the default catalog implementation uses remote(for now)
func (reg *DefaultRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, int, error) {
var statusCode int
func (reg *DefaultRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, error) {
if err := common.ValidateAuth(reg.GetAuth()); err == nil {
if authenticator == nil {
authenticator = authn.FromConfig(*reg.GetAuth())
}
res, _, statusCode, err := reg.CatalogPage(ctx, pagination, options, authenticator)
return res, nil, statusCode, err
res, _, err := reg.CatalogPage(ctx, pagination, options, authenticator)
return res, nil, err
}
repos, err := remote.CatalogPage(*reg.GetRegistry(), pagination.Cursor, pagination.Size, remote.WithAuth(authn.Anonymous))
if err != nil {
if transportError, ok := err.(*transport.Error); ok {
statusCode = transportError.StatusCode
}
}
return repos, common.CalcNextV2Pagination(repos, pagination.Size), statusCode, err

return repos, common.CalcNextV2Pagination(repos, pagination.Size), err
}

// Build http req and append password / token as bearer token
// See https://cloud.google.com/container-registry/docs/advanced-authentication#token
func (reg *DefaultRegistry) gcrCatalogPage(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, int, error) {
func (reg *DefaultRegistry) gcrCatalogPage(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, error) {
uri := reg.GetURL("_catalog")
q := uri.Query()

Expand All @@ -110,7 +104,7 @@ func (reg *DefaultRegistry) gcrCatalogPage(pagination common.PaginationOption, o
uri.RawQuery = q.Encode()
req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}
if pagination.Cursor != "" {
url := uri.String()
Expand All @@ -125,51 +119,50 @@ func (reg *DefaultRegistry) gcrCatalogPage(pagination common.PaginationOption, o
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", reg.GetAuth().Password))
resp, err := reg.HTTPClient.Do(req)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
return nil, nil, fmt.Errorf("authentication error: got %v status code", resp.StatusCode)
}
if resp.StatusCode > 399 {
return nil, nil, fmt.Errorf("got %v status code", resp.StatusCode)
}

defer resp.Body.Close()
repos := &CatalogV2Response{}
if err := json.NewDecoder(resp.Body).Decode(repos); err != nil {
return nil, nil, resp.StatusCode, err
return nil, nil, err
}
pgn := &common.PaginationOption{Size: pagination.Size}
if len(repos.Repositories) > 0 && pagination.Size > 0 {
pgn.Cursor = repos.Repositories[len(repos.Repositories)-1]
}

return repos.Repositories, pgn, resp.StatusCode, nil
return repos.Repositories, pgn, nil
}

func (reg *DefaultRegistry) CatalogPage(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, int, error) {
func (reg *DefaultRegistry) CatalogPage(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, error) {
var repos []string
var err error
var statusCode int
var pgn *common.PaginationOption
switch provider := getRegistryProvider(reg.Registry.RegistryStr()); provider {
case "gcr":
repos, pgn, statusCode, err = reg.gcrCatalogPage(pagination, options)
repos, pgn, err = reg.gcrCatalogPage(pagination, options)
default:
repos, err = remote.CatalogPage(*reg.GetRegistry(), pagination.Cursor, pagination.Size, remote.WithAuth(authenticator))
// for google's container registry error implementation
if err != nil {
if transportError, ok := err.(*transport.Error); ok {
statusCode = transportError.StatusCode
}
}
pgn = common.CalcNextV2Pagination(repos, pagination.Size)
}
return repos, pgn, statusCode, err
return repos, pgn, err

}

func (reg *DefaultRegistry) GetV2Token(client *http.Client, url string) (*common.V2TokenResponse, int, error) {
func (reg *DefaultRegistry) GetV2Token(client *http.Client, url string) (*common.V2TokenResponse, error) {
if reg.GetAuth() == nil {
return nil, 0, fmt.Errorf("no authorization found")
return nil, fmt.Errorf("no authorization found")
}
req, err := http.NewRequest(http.MethodGet, url, nil)
if err != nil {
return nil, 0, err
return nil, err
}

if reg.GetAuth().Username != "" && reg.GetAuth().Password != "" {
Expand All @@ -180,21 +173,21 @@ func (reg *DefaultRegistry) GetV2Token(client *http.Client, url string) (*common
resp, err := client.Do(req)

if err != nil {
return nil, 0, err
return nil, err
}

defer resp.Body.Close()

token := &common.V2TokenResponse{}

if err := json.NewDecoder(resp.Body).Decode(token); err != nil {
return nil, resp.StatusCode, err
return nil, err
}

if token.Token == "" {
return nil, resp.StatusCode, fmt.Errorf("recieved an empty token")
return nil, fmt.Errorf("recieved an empty token")
}
return token, resp.StatusCode, nil
return token, nil
}

// GetLatestTags returns the latest tags for a given repository in descending order by the image creation time
Expand Down
2 changes: 1 addition & 1 deletion registries/factory_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func TestHarborAdminProject(t *testing.T) {
*/
func testHarbor(reg interfaces.IRegistry, t *testing.T) {
ctx := context.Background()
for repos, repoNextPage, _, err := reg.Catalog(ctx, common.MakePagination(1), common.CatalogOption{}, nil); err == nil; repos, repoNextPage, _, err = reg.Catalog(ctx, *repoNextPage, common.CatalogOption{}, nil) {
for repos, repoNextPage, err := reg.Catalog(ctx, common.MakePagination(1), common.CatalogOption{}, nil); err == nil; repos, repoNextPage, err = reg.Catalog(ctx, *repoNextPage, common.CatalogOption{}, nil) {
if err != nil {
t.Errorf("%s", err.Error())
}
Expand Down
21 changes: 8 additions & 13 deletions registries/harbor/harbor.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,49 +39,44 @@ func (*HarborRegistry) GetMaxPageSize() int {
return 100
}

func (h *HarborRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, int, error) {
func (h *HarborRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, error) {
//if first pagination request set the page number (cursor) to 1
if len(pagination.Cursor) == 0 {
pagination.Cursor = "1"
} else {
//ensure pagination Cursor is a number
_, err := strconv.Atoi(pagination.Cursor)
if err != nil {
return nil, nil, 0, fmt.Errorf("invalid pagination, cursor must be an integer")
return nil, nil, fmt.Errorf("invalid pagination, cursor must be an integer")
}
}
//create list repos request
req, err := h.repositoriesRequest(strconv.Itoa(pagination.Size), pagination.Cursor)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}
//create client according to registry configuration
res, err := h.getClient().Do(req)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}
if err := transport.CheckError(res, http.StatusOK); err != nil {
// for google's container registry error implementation
var statusCode int
if transportError, ok := err.(*transport.Error); ok {
statusCode = transportError.StatusCode
}
return nil, nil, statusCode, err
return nil, nil, err
}

defer res.Body.Close()

body, err := ioutil.ReadAll(res.Body)
if err != nil {
return nil, nil, res.StatusCode, err
return nil, nil, err
}
//decode the repositories names from the response
if repos, err := decodeObjectsNames(body); err != nil {
return nil, nil, res.StatusCode, err
return nil, nil, err
} else {
//get next pagination (can be nill if this is the last one)
nextPagination, err := getNextPageOption(res)
return repos, nextPagination, res.StatusCode, err
return repos, nextPagination, err
}
}

Expand Down
13 changes: 6 additions & 7 deletions registries/harbor/harbor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,8 @@ func TestCatalogAndList(t *testing.T) {
assert.Nil(t, err)
ctx := context.Background()
//test catalog
repos, nextPage, statusCode, err := harbor.Catalog(ctx, common.NoPaginationOption(), common.CatalogOption{}, nil)
repos, nextPage, err := harbor.Catalog(ctx, common.NoPaginationOption(), common.CatalogOption{}, nil)
assert.Nil(t, nextPage)
assert.Equal(t, 200, statusCode)
assert.Nil(t, err)
assert.Equal(t, []string{"my-project/ca-ws", "user2private/kibana", "user-project/kibana", "my-project/kibana", "my-project/postgres"}, repos)
testServer.Close()
Expand Down Expand Up @@ -93,9 +92,9 @@ func TestCatalogAndListWithProjectAndPagination(t *testing.T) {
t.Error(err)
}
//test catalog
repos, nextReposPage, statusCode, err := harbor.Catalog(ctx, common.MakePagination(2), common.CatalogOption{}, nil)
repos, nextReposPage, err := harbor.Catalog(ctx, common.MakePagination(2), common.CatalogOption{}, nil)
assert.Nil(t, err)
assert.Equal(t, 200, statusCode)

assert.Equal(t, []string{"my-project/ca-ws", "my-project/kibana"}, repos)
assert.Equal(t, &common.PaginationOption{Cursor: "2", Size: 2}, nextReposPage)
testServer.Close()
Expand All @@ -111,9 +110,9 @@ func TestCatalogAndListWithProjectAndPagination(t *testing.T) {
t.Error(err)
}

_, nextReposPage, statusCode, err = harbor.Catalog(ctx, common.PaginationOption{Cursor: "2", Size: 1}, common.CatalogOption{}, nil)
_, nextReposPage, err = harbor.Catalog(ctx, common.PaginationOption{Cursor: "2", Size: 1}, common.CatalogOption{}, nil)
assert.Nil(t, err)
assert.Equal(t, 200, statusCode)

assert.Equal(t, &common.PaginationOption{Cursor: "3", Size: 1}, nextReposPage)
testServer.Close()

Expand All @@ -127,7 +126,7 @@ func TestCatalogAndListWithProjectAndPagination(t *testing.T) {
if err != nil {
t.Error(err)
}
_, nextReposPage, _, err = harbor.Catalog(ctx, common.PaginationOption{Cursor: "2", Size: 2}, common.CatalogOption{}, nil)
_, nextReposPage, err = harbor.Catalog(ctx, common.PaginationOption{Cursor: "2", Size: 2}, common.CatalogOption{}, nil)
assert.Nil(t, err)
assert.Nil(t, nextReposPage)
testServer.Close()
Expand Down
48 changes: 30 additions & 18 deletions registries/quay/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func catalogOptionsToQuery(uri *url.URL, pagination common.PaginationOption, opt

return uri
}
func (reg *QuayioRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, int, error) {
func (reg *QuayioRegistry) Catalog(ctx context.Context, pagination common.PaginationOption, options common.CatalogOption, authenticator authn.Authenticator) ([]string, *common.PaginationOption, error) {
//if quay is invalid we use it as public!!!!
if err := common.ValidateAuth(reg.GetAuth()); err == nil {
if authenticator == nil {
Expand All @@ -53,12 +53,12 @@ func (reg *QuayioRegistry) Catalog(ctx context.Context, pagination common.Pagina
return reg.catalogQuayProprietery(pagination, options)
}

func (reg *QuayioRegistry) catalogQuayV2Auth(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, int, error) {
func (reg *QuayioRegistry) catalogQuayV2Auth(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, error) {

//Token Request
token, statusCode, err := reg.GetV2Token(reg.HTTPClient, AUTH_URL)
token, err := reg.GetV2Token(reg.HTTPClient, AUTH_URL)
if err != nil {
return nil, nil, statusCode, err
return nil, nil, err
}
reg.GetAuth().RegistryToken = token.Token
uri := reg.DefaultRegistry.GetURL("_catalog")
Expand All @@ -73,7 +73,7 @@ func (reg *QuayioRegistry) catalogQuayV2Auth(pagination common.PaginationOption,
uri.RawQuery = q.Encode()
req, err := http.NewRequest(http.MethodGet, uri.String(), nil)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}

if pagination.Cursor != "" {
Expand All @@ -89,26 +89,32 @@ func (reg *QuayioRegistry) catalogQuayV2Auth(pagination common.PaginationOption,
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", token.Token))
resp, err := reg.HTTPClient.Do(req)
if err != nil {
return nil, nil, 0, err
return nil, nil, err
}
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
return nil, nil, fmt.Errorf("authentication error: got %v status code", resp.StatusCode)
}
if resp.StatusCode > 399 {
return nil, nil, fmt.Errorf("error: got %v status code", resp.StatusCode)
}

defer resp.Body.Close()
repos := &defaultregistry.CatalogV2Response{}
if err := json.NewDecoder(resp.Body).Decode(repos); err != nil {
return nil, nil, resp.StatusCode, err
return nil, nil, err
}
pgn := &common.PaginationOption{Size: pagination.Size}
if len(repos.Repositories) > 0 && pagination.Size > 0 {
pgn.Cursor = repos.Repositories[len(repos.Repositories)-1]
}

return repos.Repositories, pgn, resp.StatusCode, nil
return repos.Repositories, pgn, nil
}

func (reg *QuayioRegistry) catalogQuayProprietery(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, int, error) {
data, statusCode, err := reg.CatalogAux(pagination, options)
func (reg *QuayioRegistry) catalogQuayProprietery(pagination common.PaginationOption, options common.CatalogOption) ([]string, *common.PaginationOption, error) {
data, err := reg.CatalogAux(pagination, options)
if err != nil {
return nil, nil, statusCode, err
return nil, nil, err
}
repositories := data.Transform(pagination.Size)
var pgn *common.PaginationOption = nil
Expand All @@ -118,31 +124,37 @@ func (reg *QuayioRegistry) catalogQuayProprietery(pagination common.PaginationOp
repositories = append(repositories, data.Transform(0)...)

}
return repositories, pgn, statusCode, nil
return repositories, pgn, nil
}

func (reg *QuayioRegistry) CatalogAux(pagination common.PaginationOption, options common.CatalogOption) (*QuayCatalogResponse, int, error) {
func (reg *QuayioRegistry) CatalogAux(pagination common.PaginationOption, options common.CatalogOption) (*QuayCatalogResponse, error) {
uri := reg.getURL("repository")
uri = catalogOptionsToQuery(uri, pagination, options)
client := http.Client{}

req, err := http.NewRequest("GET", uri.String(), nil)
if err != nil {
return nil, 0, err
return nil, err
}
resp, err := client.Do(req)
if err != nil {
return nil, 0, err
return nil, err
}
if resp.StatusCode == http.StatusUnauthorized || resp.StatusCode == http.StatusForbidden {
return nil, fmt.Errorf("authentication error: got %v status code", resp.StatusCode)
}
if resp.StatusCode > 399 {
return nil, fmt.Errorf("error: got %v status code", resp.StatusCode)
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, resp.StatusCode, err
return nil, err
}
data := &QuayCatalogResponse{}
if err := json.Unmarshal(body, data); err != nil {
return nil, resp.StatusCode, err
return nil, err
}
body = nil
return data, resp.StatusCode, nil
return data, nil
}
3 changes: 1 addition & 2 deletions registries/quay/quayio_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ func TestSimpleNoAuth(t *testing.T) {

quayio, err := NewQuayIORegistry(nil, &registry, &common.RegistryOptions{})
ctx := context.Background()
repos, _, statusCode, err := quayio.Catalog(ctx, common.NoPaginationOption(), common.CatalogOption{IsPublic: true, Namespaces: "quay"}, nil)
repos, _, err := quayio.Catalog(ctx, common.NoPaginationOption(), common.CatalogOption{IsPublic: true, Namespaces: "quay"}, nil)
assert.Nil(t, err, "failed to catalog")
assert.NotEmpty(t, repos, "expected some returned images")
assert.Equal(t, 200, statusCode, "expected status code 200")

repo := repos[0]
fullRepoName := quayio.GetRegistry().Name() + "/" + repo
Expand Down

0 comments on commit 7cd04f9

Please sign in to comment.