mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-23 18:55:18 +01:00
Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
fa41c6aa17
@ -89,6 +89,6 @@ http {
|
|||||||
server {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name harbordomain.com;
|
server_name harbordomain.com;
|
||||||
rewrite ^/(.*) https://$server_name$1 permanent;
|
rewrite ^/(.*) https://$server_name/$1 permanent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ insert into role (role_code, name) values
|
|||||||
create table user (
|
create table user (
|
||||||
user_id int NOT NULL AUTO_INCREMENT,
|
user_id int NOT NULL AUTO_INCREMENT,
|
||||||
username varchar(15),
|
username varchar(15),
|
||||||
email varchar(30),
|
email varchar(128),
|
||||||
password varchar(40) NOT NULL,
|
password varchar(40) NOT NULL,
|
||||||
realname varchar (20) NOT NULL,
|
realname varchar (20) NOT NULL,
|
||||||
comment varchar (30),
|
comment varchar (30),
|
||||||
|
@ -46,8 +46,8 @@ func NewRequestAuthorizer(handlers []Handler, challenges []au.Challenge) *Reques
|
|||||||
|
|
||||||
// ModifyRequest adds authorization to the request
|
// ModifyRequest adds authorization to the request
|
||||||
func (r *RequestAuthorizer) ModifyRequest(req *http.Request) error {
|
func (r *RequestAuthorizer) ModifyRequest(req *http.Request) error {
|
||||||
for _, handler := range r.handlers {
|
|
||||||
for _, challenge := range r.challenges {
|
for _, challenge := range r.challenges {
|
||||||
|
for _, handler := range r.handlers {
|
||||||
if handler.Scheme() == challenge.Scheme {
|
if handler.Scheme() == challenge.Scheme {
|
||||||
if err := handler.AuthorizeRequest(req, challenge.Parameters); err != nil {
|
if err := handler.AuthorizeRequest(req, challenge.Parameters); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -22,6 +22,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
token_util "github.com/vmware/harbor/service/token"
|
token_util "github.com/vmware/harbor/service/token"
|
||||||
@ -48,6 +49,7 @@ type tokenHandler struct {
|
|||||||
cache string // cached token
|
cache string // cached token
|
||||||
expiresIn int // The duration in seconds since the token was issued that it will remain valid
|
expiresIn int // The duration in seconds since the token was issued that it will remain valid
|
||||||
issuedAt *time.Time // The RFC3339-serialized UTC standard time at which a given token was issued
|
issuedAt *time.Time // The RFC3339-serialized UTC standard time at which a given token was issued
|
||||||
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scheme returns the scheme that the handler can handle
|
// Scheme returns the scheme that the handler can handle
|
||||||
@ -77,8 +79,10 @@ func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]str
|
|||||||
|
|
||||||
expired := true
|
expired := true
|
||||||
|
|
||||||
if t.expiresIn != 0 && t.issuedAt != nil {
|
cachedToken, cachedExpiredIn, cachedIssuedAt := t.getCachedToken()
|
||||||
expired = t.issuedAt.Add(time.Duration(t.expiresIn) * time.Second).Before(time.Now().UTC())
|
|
||||||
|
if len(cachedToken) != 0 && cachedExpiredIn != 0 && cachedIssuedAt != nil {
|
||||||
|
expired = cachedIssuedAt.Add(time.Duration(cachedExpiredIn) * time.Second).Before(time.Now().UTC())
|
||||||
}
|
}
|
||||||
|
|
||||||
if expired || hasFrom {
|
if expired || hasFrom {
|
||||||
@ -93,13 +97,11 @@ func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]str
|
|||||||
token = to
|
token = to
|
||||||
|
|
||||||
if !hasFrom {
|
if !hasFrom {
|
||||||
t.cache = token
|
t.updateCachedToken(to, expiresIn, issuedAt)
|
||||||
t.expiresIn = expiresIn
|
|
||||||
t.issuedAt = issuedAt
|
|
||||||
log.Debug("add token to cache")
|
log.Debug("add token to cache")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
token = t.cache
|
token = cachedToken
|
||||||
log.Debug("get token from cache")
|
log.Debug("get token from cache")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -109,6 +111,20 @@ func (t *tokenHandler) AuthorizeRequest(req *http.Request, params map[string]str
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *tokenHandler) getCachedToken() (string, int, *time.Time) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
return t.cache, t.expiresIn, t.issuedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *tokenHandler) updateCachedToken(token string, expiresIn int, issuedAt *time.Time) {
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
t.cache = token
|
||||||
|
t.expiresIn = expiresIn
|
||||||
|
t.issuedAt = issuedAt
|
||||||
|
}
|
||||||
|
|
||||||
// Implements interface Handler
|
// Implements interface Handler
|
||||||
type standardTokenHandler struct {
|
type standardTokenHandler struct {
|
||||||
tokenHandler
|
tokenHandler
|
||||||
@ -168,6 +184,7 @@ func (s *standardTokenHandler) generateToken(realm, service string, scopes []str
|
|||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
err = registry_errors.Error{
|
err = registry_errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -23,12 +23,13 @@ import (
|
|||||||
// an Error instance will be returned
|
// an Error instance will be returned
|
||||||
type Error struct {
|
type Error struct {
|
||||||
StatusCode int
|
StatusCode int
|
||||||
|
StatusText string
|
||||||
Message string
|
Message string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error ...
|
// Error ...
|
||||||
func (e Error) Error() string {
|
func (e Error) Error() string {
|
||||||
return fmt.Sprintf("%d %s", e.StatusCode, e.Message)
|
return fmt.Sprintf("%d %s %s", e.StatusCode, e.StatusText, e.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseError parses err, if err is type Error, convert it to Error
|
// ParseError parses err, if err is type Error, convert it to Error
|
||||||
|
@ -89,6 +89,10 @@ func (r *Registry) Catalog() ([]string, error) {
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return repos, e
|
||||||
|
}
|
||||||
return repos, err
|
return repos, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,6 +119,7 @@ func (r *Registry) Catalog() ([]string, error) {
|
|||||||
|
|
||||||
return repos, errors.Error{
|
return repos, errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,6 +72,9 @@ func NewRepositoryWithCredential(name, endpoint string, credential auth.Credenti
|
|||||||
}
|
}
|
||||||
|
|
||||||
client, err := newClient(endpoint, "", credential, "repository", name, "pull", "push")
|
client, err := newClient(endpoint, "", credential, "repository", name, "pull", "push")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
repository := &Repository{
|
repository := &Repository{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -108,6 +111,17 @@ func NewRepositoryWithUsername(name, endpoint, username string) (*Repository, er
|
|||||||
return repository, nil
|
return repository, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// try to convert err to errors.Error if it is
|
||||||
|
func isUnauthorizedError(err error) (bool, error) {
|
||||||
|
if strings.Contains(err.Error(), http.StatusText(http.StatusUnauthorized)) {
|
||||||
|
return true, errors.Error{
|
||||||
|
StatusCode: http.StatusUnauthorized,
|
||||||
|
StatusText: http.StatusText(http.StatusUnauthorized),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
// ListTag ...
|
// ListTag ...
|
||||||
func (r *Repository) ListTag() ([]string, error) {
|
func (r *Repository) ListTag() ([]string, error) {
|
||||||
tags := []string{}
|
tags := []string{}
|
||||||
@ -118,6 +132,10 @@ func (r *Repository) ListTag() ([]string, error) {
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return tags, e
|
||||||
|
}
|
||||||
return tags, err
|
return tags, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,9 +159,9 @@ func (r *Repository) ListTag() ([]string, error) {
|
|||||||
|
|
||||||
return tags, nil
|
return tags, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return tags, errors.Error{
|
return tags, errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +179,11 @@ func (r *Repository) ManifestExist(reference string) (digest string, exist bool,
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,6 +206,7 @@ func (r *Repository) ManifestExist(reference string) (digest string, exist bool,
|
|||||||
|
|
||||||
err = errors.Error{
|
err = errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -201,6 +225,11 @@ func (r *Repository) PullManifest(reference string, acceptMediaTypes []string) (
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +248,7 @@ func (r *Repository) PullManifest(reference string, acceptMediaTypes []string) (
|
|||||||
|
|
||||||
err = errors.Error{
|
err = errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +266,11 @@ func (r *Repository) PushManifest(reference, mediaType string, payload []byte) (
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -253,6 +288,7 @@ func (r *Repository) PushManifest(reference, mediaType string, payload []byte) (
|
|||||||
|
|
||||||
err = errors.Error{
|
err = errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,6 +304,10 @@ func (r *Repository) DeleteManifest(digest string) error {
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,6 +324,7 @@ func (r *Repository) DeleteManifest(digest string) error {
|
|||||||
|
|
||||||
return errors.Error{
|
return errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,6 +339,7 @@ func (r *Repository) DeleteTag(tag string) error {
|
|||||||
if !exist {
|
if !exist {
|
||||||
return errors.Error{
|
return errors.Error{
|
||||||
StatusCode: http.StatusNotFound,
|
StatusCode: http.StatusNotFound,
|
||||||
|
StatusText: http.StatusText(http.StatusNotFound),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -313,6 +355,10 @@ func (r *Repository) BlobExist(digest string) (bool, error) {
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return false, e
|
||||||
|
}
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +379,7 @@ func (r *Repository) BlobExist(digest string) (bool, error) {
|
|||||||
|
|
||||||
return false, errors.Error{
|
return false, errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -346,6 +393,11 @@ func (r *Repository) PullBlob(digest string) (size int64, data []byte, err error
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,6 +419,7 @@ func (r *Repository) PullBlob(digest string) (size int64, data []byte, err error
|
|||||||
|
|
||||||
err = errors.Error{
|
err = errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,6 +432,11 @@ func (r *Repository) initiateBlobUpload(name string) (location, uploadUUID strin
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
err = e
|
||||||
|
return
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,6 +455,7 @@ func (r *Repository) initiateBlobUpload(name string) (location, uploadUUID strin
|
|||||||
|
|
||||||
err = errors.Error{
|
err = errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,6 +470,10 @@ func (r *Repository) monolithicBlobUpload(location, digest string, size int64, d
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,6 +490,7 @@ func (r *Repository) monolithicBlobUpload(location, digest string, size int64, d
|
|||||||
|
|
||||||
return errors.Error{
|
return errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -460,6 +524,10 @@ func (r *Repository) DeleteBlob(digest string) error {
|
|||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
ok, e := isUnauthorizedError(err)
|
||||||
|
if ok {
|
||||||
|
return e
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -476,6 +544,7 @@ func (r *Repository) DeleteBlob(digest string) error {
|
|||||||
|
|
||||||
return errors.Error{
|
return errors.Error{
|
||||||
StatusCode: resp.StatusCode,
|
StatusCode: resp.StatusCode,
|
||||||
|
StatusText: resp.Status,
|
||||||
Message: string(b),
|
Message: string(b),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
176
utils/registry/repository_test.go
Normal file
176
utils/registry/repository_test.go
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package registry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
//"github.com/vmware/harbor/utils/log"
|
||||||
|
"github.com/vmware/harbor/utils/registry/auth"
|
||||||
|
"github.com/vmware/harbor/utils/registry/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
username = "user"
|
||||||
|
password = "P@ssw0rd"
|
||||||
|
repo = "samalba/my-app"
|
||||||
|
tags = tagResp{Tags: []string{"1.0", "2.0", "3.0"}}
|
||||||
|
validToken = "valid_token"
|
||||||
|
invalidToken = "invalid_token"
|
||||||
|
credential auth.Credential
|
||||||
|
registryServer *httptest.Server
|
||||||
|
tokenServer *httptest.Server
|
||||||
|
repositoryClient *Repository
|
||||||
|
)
|
||||||
|
|
||||||
|
type tagResp struct {
|
||||||
|
Tags []string `json:"tags"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestMain(m *testing.M) {
|
||||||
|
//log.SetLevel(log.DebugLevel)
|
||||||
|
credential = auth.NewBasicAuthCredential(username, password)
|
||||||
|
|
||||||
|
tokenServer = initTokenServer()
|
||||||
|
defer tokenServer.Close()
|
||||||
|
|
||||||
|
registryServer = initRegistryServer()
|
||||||
|
defer registryServer.Close()
|
||||||
|
|
||||||
|
os.Exit(m.Run())
|
||||||
|
}
|
||||||
|
|
||||||
|
func initRegistryServer() *httptest.Server {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/v2/", servePing)
|
||||||
|
mux.HandleFunc(fmt.Sprintf("/v2/%s/tags/list", repo), serveTaglisting)
|
||||||
|
|
||||||
|
return httptest.NewServer(mux)
|
||||||
|
}
|
||||||
|
|
||||||
|
//response ping request: http://registry/v2
|
||||||
|
func servePing(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isTokenValid(r) {
|
||||||
|
challenge(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveTaglisting(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !isTokenValid(r) {
|
||||||
|
challenge(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(tags); err != nil {
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTokenValid(r *http.Request) bool {
|
||||||
|
valid := false
|
||||||
|
auth := r.Header.Get(http.CanonicalHeaderKey("Authorization"))
|
||||||
|
if len(auth) != 0 {
|
||||||
|
auth = strings.TrimSpace(auth)
|
||||||
|
index := strings.Index(auth, "Bearer")
|
||||||
|
token := auth[index+6:]
|
||||||
|
token = strings.TrimSpace(token)
|
||||||
|
if token == validToken {
|
||||||
|
valid = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
func challenge(w http.ResponseWriter) {
|
||||||
|
challenge := "Bearer realm=\"" + tokenServer.URL + "/service/token\",service=\"token-service\""
|
||||||
|
w.Header().Set("Www-Authenticate", challenge)
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func initTokenServer() *httptest.Server {
|
||||||
|
mux := http.NewServeMux()
|
||||||
|
mux.HandleFunc("/service/token", serveToken)
|
||||||
|
|
||||||
|
return httptest.NewServer(mux)
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveToken(w http.ResponseWriter, r *http.Request) {
|
||||||
|
u, p, ok := r.BasicAuth()
|
||||||
|
if !ok || u != username || p != password {
|
||||||
|
w.WriteHeader(http.StatusUnauthorized)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[string]interface{})
|
||||||
|
result["token"] = validToken
|
||||||
|
result["expires_in"] = 300
|
||||||
|
result["issued_at"] = time.Now().Format(time.RFC3339)
|
||||||
|
|
||||||
|
encoder := json.NewEncoder(w)
|
||||||
|
if err := encoder.Encode(result); err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
w.Write([]byte(err.Error()))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListTag(t *testing.T) {
|
||||||
|
client, err := NewRepositoryWithCredential(repo, registryServer.URL, credential)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := client.ListTag()
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if len(list) != len(tags.Tags) {
|
||||||
|
t.Errorf("expected length: %d, actual length: %d", len(tags.Tags), len(list))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListTagWithInvalidCredential(t *testing.T) {
|
||||||
|
credential := auth.NewBasicAuthCredential(username, "wrong_password")
|
||||||
|
client, err := NewRepositoryWithCredential(repo, registryServer.URL, credential)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = client.ListTag()
|
||||||
|
if err != nil {
|
||||||
|
e, ok := errors.ParseError(err)
|
||||||
|
if ok && e.StatusCode == http.StatusUnauthorized {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user