auth: allow for world-readable deployment mode
This commit is contained in:
parent
ae6651a919
commit
10199457b4
33
WORKSPACE
33
WORKSPACE
@ -1,29 +1,39 @@
|
||||
workspace(name = "com_github_anuvu_zot")
|
||||
|
||||
go_version = "1.12.9"
|
||||
|
||||
go_os = "linux"
|
||||
|
||||
go_arch = "amd64"
|
||||
|
||||
|
||||
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
|
||||
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")
|
||||
|
||||
go_rules_version = "0.18.6"
|
||||
go_rules_version = "0.19.3"
|
||||
|
||||
http_archive(
|
||||
name = "io_bazel_rules_go",
|
||||
sha256 = "f04d2373bcaf8aa09bccb08a98a57e721306c8f6043a2a0ee610fd6853dcde3d",
|
||||
urls = ["https://github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version)],
|
||||
urls = [
|
||||
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
||||
"https://github.com/bazelbuild/rules_go/releases/download/{}/rules_go-{}.tar.gz".format(go_rules_version, go_rules_version),
|
||||
],
|
||||
sha256 = "313f2c7a23fecc33023563f082f381a32b9b7254f727a7dd2d6380ccc6dfe09b",
|
||||
)
|
||||
|
||||
gazelle_version = "0.17.0"
|
||||
gazelle_version = "0.18.1"
|
||||
|
||||
http_archive(
|
||||
name = "bazel_gazelle",
|
||||
sha256 = "3c681998538231a2d24d0c07ed5a7658cb72bfb5fd4bf9911157c0e9ac6a2687",
|
||||
sha256 = "be9296bfd64882e3c08e3283c58fcb461fa6dd3c171764fcc4cf322f60615a9b",
|
||||
urls = ["https://github.com/bazelbuild/bazel-gazelle/releases/download/{}/bazel-gazelle-{}.tar.gz".format(gazelle_version, gazelle_version)],
|
||||
)
|
||||
|
||||
buildtools_version = "0.26.0"
|
||||
buildtools_version = "0.25.1"
|
||||
|
||||
http_archive(
|
||||
name = "com_github_bazelbuild_buildtools",
|
||||
sha256 = "86592d703ecbe0c5cbb5139333a63268cf58d7efd2c459c8be8e69e77d135e29",
|
||||
sha256 = "0a0920151acf18c51866331944d12db9023707a6861e78225366f5711efc845b",
|
||||
strip_prefix = "buildtools-{}".format(buildtools_version),
|
||||
urls = ["https://github.com/bazelbuild/buildtools/archive/{}.tar.gz".format(buildtools_version)],
|
||||
)
|
||||
@ -47,7 +57,14 @@ load("@bazel_skylib//lib:versions.bzl", "versions")
|
||||
|
||||
versions.check(minimum_bazel_version = "0.26.1")
|
||||
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
|
||||
load("@io_bazel_rules_go//go:deps.bzl", "go_download_sdk", "go_register_toolchains", "go_rules_dependencies")
|
||||
|
||||
go_download_sdk(
|
||||
name = "go_sdk",
|
||||
goos = go_os,
|
||||
goarch = go_arch,
|
||||
version = go_version,
|
||||
)
|
||||
|
||||
go_rules_dependencies()
|
||||
|
||||
|
@ -16,7 +16,8 @@
|
||||
"path": "test/data/htpasswd"
|
||||
},
|
||||
"failDelay": 5
|
||||
}
|
||||
},
|
||||
"allowReadAccess": false
|
||||
},
|
||||
"log":{
|
||||
"level":"debug",
|
||||
|
@ -14,6 +14,7 @@ http:
|
||||
htpasswd:
|
||||
path: test/data/htpasswd
|
||||
failDelay: 5
|
||||
allowReadAccess: false
|
||||
log:
|
||||
level: debug
|
||||
output: /tmp/zot.log
|
||||
|
6
go.mod
6
go.mod
@ -20,6 +20,10 @@ require (
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 // indirect
|
||||
github.com/swaggo/http-swagger v0.0.0-20190614090009-c2865af9083e
|
||||
github.com/swaggo/swag v1.6.2
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 // indirect
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 // indirect
|
||||
golang.org/x/text v0.3.2 // indirect
|
||||
golang.org/x/tools v0.0.0-20190827205025-b29f5f60c37a // indirect
|
||||
gopkg.in/resty.v1 v1.12.0
|
||||
)
|
||||
|
13
go.sum
13
go.sum
@ -162,6 +162,8 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586 h1:7KByu05hhLed2MO29w7p1XfZvZ13m8mub3shuVftRs0=
|
||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -172,6 +174,9 @@ golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
|
||||
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
@ -185,16 +190,24 @@ golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456 h1:ng0gs1AKnRRuEMZoTLLlbOd+C17zUDepwGQBb/n+JVg=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468 h1:fTfk6GjmihJbK0mSUFgPPgYpsdmApQ86Mcd4GuKax9U=
|
||||
golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190827205025-b29f5f60c37a h1:0JEq5ZQ3TgsRlFmz4BcD+E6U6cOk4pOImCQSyIG59ZM=
|
||||
golang.org/x/tools v0.0.0-20190827205025-b29f5f60c37a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
|
@ -21,22 +21,30 @@ func authFail(w http.ResponseWriter, realm string, delay int) {
|
||||
}
|
||||
|
||||
func BasicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||
if c.Config.HTTP.Auth.HTPasswd.Path == "" {
|
||||
// no authentication
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// Process request
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
realm := c.Config.HTTP.Realm
|
||||
if realm == "" {
|
||||
realm = "Authorization Required"
|
||||
}
|
||||
realm = "Basic realm=" + strconv.Quote(realm)
|
||||
delay := c.Config.HTTP.Auth.FailDelay
|
||||
|
||||
if c.Config.HTTP.Auth.HTPasswd.Path == "" {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if c.Config.HTTP.AllowReadAccess &&
|
||||
c.Config.HTTP.TLS.CACert != "" &&
|
||||
r.TLS.VerifiedChains == nil &&
|
||||
r.Method != "GET" && r.Method != "HEAD" {
|
||||
authFail(w, realm, delay)
|
||||
return
|
||||
}
|
||||
|
||||
// Process request
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
credMap := make(map[string]string)
|
||||
|
||||
f, err := os.Open(c.Config.HTTP.Auth.HTPasswd.Path)
|
||||
@ -56,6 +64,12 @@ func BasicAuthHandler(c *Controller) mux.MiddlewareFunc {
|
||||
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if (r.Method == "GET" || r.Method == "HEAD") && c.Config.HTTP.AllowReadAccess {
|
||||
// Process request
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
basicAuth := r.Header.Get("Authorization")
|
||||
if basicAuth == "" {
|
||||
authFail(w, realm, delay)
|
||||
|
@ -24,11 +24,12 @@ type AuthConfig struct {
|
||||
}
|
||||
|
||||
type HTTPConfig struct {
|
||||
Address string
|
||||
Port string
|
||||
TLS TLSConfig `mapstructure:",omitempty"`
|
||||
Auth AuthConfig `mapstructure:",omitempty"`
|
||||
Realm string
|
||||
Address string
|
||||
Port string
|
||||
TLS TLSConfig `mapstructure:",omitempty"`
|
||||
Auth AuthConfig `mapstructure:",omitempty"`
|
||||
Realm string
|
||||
AllowReadAccess bool `mapstructure:",omitempty"`
|
||||
}
|
||||
|
||||
type LogConfig struct {
|
||||
|
@ -45,13 +45,13 @@ func (c *Controller) Run() error {
|
||||
return err
|
||||
}
|
||||
|
||||
clientAuth := tls.VerifyClientCertIfGiven
|
||||
if c.Config.HTTP.Auth.HTPasswd.Path == "" {
|
||||
clientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
if c.Config.HTTP.TLS.Key != "" && c.Config.HTTP.TLS.Cert != "" {
|
||||
if c.Config.HTTP.TLS.CACert != "" {
|
||||
clientAuth := tls.VerifyClientCertIfGiven
|
||||
if c.Config.HTTP.Auth.HTPasswd.Path == "" && !c.Config.HTTP.AllowReadAccess {
|
||||
clientAuth = tls.RequireAndVerifyClientCert
|
||||
}
|
||||
|
||||
caCert, err := ioutil.ReadFile(c.Config.HTTP.TLS.CACert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -26,6 +26,7 @@ const (
|
||||
htpasswdPath = "../../test/data/htpasswd" // nolint (gosec) - this is just test data
|
||||
ServerCert = "../../test/data/server.cert"
|
||||
ServerKey = "../../test/data/server.key"
|
||||
CACert = "../../test/data/ca.crt"
|
||||
)
|
||||
|
||||
func TestNew(t *testing.T) {
|
||||
@ -91,7 +92,7 @@ func TestBasicAuth(t *testing.T) {
|
||||
|
||||
func TestTLSWithBasicAuth(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile("../../test/data/ca.crt")
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
@ -158,9 +159,80 @@ func TestTLSWithBasicAuth(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSWithBasicAuthAllowReadAccess(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool})
|
||||
defer func() { resty.SetTLSClientConfig(nil) }()
|
||||
config := api.NewConfig()
|
||||
config.HTTP.Port = SecurePort2
|
||||
config.HTTP.Auth.HTPasswd.Path = htpasswdPath
|
||||
config.HTTP.TLS.Cert = ServerCert
|
||||
config.HTTP.TLS.Key = ServerKey
|
||||
config.HTTP.AllowReadAccess = true
|
||||
|
||||
c := api.NewController(config)
|
||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
c.Config.Storage.RootDirectory = dir
|
||||
go func() {
|
||||
// this blocks
|
||||
if err := c.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// wait till ready
|
||||
for {
|
||||
_, err := resty.R().Get(BaseURL2)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
ctx := context.Background()
|
||||
_ = c.Server.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
// accessing insecure HTTP site should fail
|
||||
resp, err := resty.R().Get(BaseURL2)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 400)
|
||||
|
||||
// without creds, should still be allowed to access
|
||||
resp, err = resty.R().Get(BaseSecureURL2 + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// with creds, should get expected status code
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// without creds, writes should fail
|
||||
resp, err = resty.R().Post(BaseSecureURL2 + "/v2/repo/blobs/uploads/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 401)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSMutualAuth(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile("../../test/data/ca.crt")
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
@ -171,7 +243,7 @@ func TestTLSMutualAuth(t *testing.T) {
|
||||
config.HTTP.Port = SecurePort2
|
||||
config.HTTP.TLS.Cert = ServerCert
|
||||
config.HTTP.TLS.Key = ServerKey
|
||||
config.HTTP.TLS.CACert = "../../test/data/ca.crt"
|
||||
config.HTTP.TLS.CACert = CACert
|
||||
|
||||
c := api.NewController(config)
|
||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||
@ -240,9 +312,9 @@ func TestTLSMutualAuth(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSMutualAndBasicAuth(t *testing.T) {
|
||||
func TestTLSMutualAuthAllowReadAccess(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile("../../test/data/ca.crt")
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
@ -253,7 +325,97 @@ func TestTLSMutualAndBasicAuth(t *testing.T) {
|
||||
config.HTTP.Port = SecurePort2
|
||||
config.HTTP.TLS.Cert = ServerCert
|
||||
config.HTTP.TLS.Key = ServerKey
|
||||
config.HTTP.TLS.CACert = "../../test/data/ca.crt"
|
||||
config.HTTP.TLS.CACert = CACert
|
||||
config.HTTP.AllowReadAccess = true
|
||||
|
||||
c := api.NewController(config)
|
||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
c.Config.Storage.RootDirectory = dir
|
||||
go func() {
|
||||
// this blocks
|
||||
if err := c.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// wait till ready
|
||||
for {
|
||||
_, err := resty.R().Get(BaseURL2)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
ctx := context.Background()
|
||||
_ = c.Server.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
// accessing insecure HTTP site should fail
|
||||
resp, err := resty.R().Get(BaseURL2)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 400)
|
||||
|
||||
// without client certs and creds, reads are allowed
|
||||
resp, err = resty.R().Get(BaseSecureURL2 + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// with creds but without certs, reads are allowed
|
||||
resp, err = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// without creds, writes should fail
|
||||
resp, err = resty.R().Post(BaseSecureURL2 + "/v2/repo/blobs/uploads/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 401)
|
||||
|
||||
// setup TLS mutual auth
|
||||
cert, err := tls.LoadX509KeyPair("../../test/data/client.cert", "../../test/data/client.key")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resty.SetCertificates(cert)
|
||||
defer func() { resty.SetCertificates(tls.Certificate{}) }()
|
||||
|
||||
// with client certs but without creds, should succeed
|
||||
resp, err = resty.R().Get(BaseSecureURL2 + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// with client certs and creds, should get expected status code
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
||||
// with client certs, creds shouldn't matter
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSMutualAndBasicAuth(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool})
|
||||
defer func() { resty.SetTLSClientConfig(nil) }()
|
||||
config := api.NewConfig()
|
||||
config.HTTP.Port = SecurePort2
|
||||
config.HTTP.TLS.Cert = ServerCert
|
||||
config.HTTP.TLS.Key = ServerKey
|
||||
config.HTTP.TLS.CACert = CACert
|
||||
config.HTTP.Auth.HTPasswd.Path = htpasswdPath
|
||||
|
||||
c := api.NewController(config)
|
||||
@ -325,3 +487,94 @@ func TestTLSMutualAndBasicAuth(t *testing.T) {
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
})
|
||||
}
|
||||
|
||||
func TestTLSMutualAndBasicAuthAllowReadAccess(t *testing.T) {
|
||||
Convey("Make a new controller", t, func() {
|
||||
caCert, err := ioutil.ReadFile(CACert)
|
||||
So(err, ShouldBeNil)
|
||||
caCertPool := x509.NewCertPool()
|
||||
caCertPool.AppendCertsFromPEM(caCert)
|
||||
|
||||
resty.SetTLSClientConfig(&tls.Config{RootCAs: caCertPool})
|
||||
defer func() { resty.SetTLSClientConfig(nil) }()
|
||||
config := api.NewConfig()
|
||||
config.HTTP.Port = SecurePort2
|
||||
config.HTTP.TLS.Cert = ServerCert
|
||||
config.HTTP.TLS.Key = ServerKey
|
||||
config.HTTP.TLS.CACert = CACert
|
||||
config.HTTP.Auth.HTPasswd.Path = htpasswdPath
|
||||
config.HTTP.AllowReadAccess = true
|
||||
|
||||
c := api.NewController(config)
|
||||
dir, err := ioutil.TempDir("", "oci-repo-test")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
c.Config.Storage.RootDirectory = dir
|
||||
go func() {
|
||||
// this blocks
|
||||
if err := c.Run(); err != nil {
|
||||
return
|
||||
}
|
||||
}()
|
||||
|
||||
// wait till ready
|
||||
for {
|
||||
_, err := resty.R().Get(BaseURL2)
|
||||
if err == nil {
|
||||
break
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
ctx := context.Background()
|
||||
_ = c.Server.Shutdown(ctx)
|
||||
}()
|
||||
|
||||
// accessing insecure HTTP site should fail
|
||||
resp, err := resty.R().Get(BaseURL2)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 400)
|
||||
|
||||
// without client certs and creds, should fail
|
||||
_, err = resty.R().Get(BaseSecureURL2)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 400)
|
||||
|
||||
// with creds but without certs, should succeed
|
||||
_, err = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2)
|
||||
So(err, ShouldBeNil)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 400)
|
||||
|
||||
// setup TLS mutual auth
|
||||
cert, err := tls.LoadX509KeyPair("../../test/data/client.cert", "../../test/data/client.key")
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
resty.SetCertificates(cert)
|
||||
defer func() { resty.SetCertificates(tls.Certificate{}) }()
|
||||
|
||||
// with client certs but without creds, reads should succeed
|
||||
resp, err = resty.R().Get(BaseSecureURL2 + "/v2/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
|
||||
// with only client certs, writes should fail
|
||||
resp, err = resty.R().Post(BaseSecureURL2 + "/v2/repo/blobs/uploads/")
|
||||
So(err, ShouldBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 401)
|
||||
|
||||
// with client certs and creds, should get expected status code
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2)
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 404)
|
||||
|
||||
resp, _ = resty.R().SetBasicAuth(username, passphrase).Get(BaseSecureURL2 + "/v2/")
|
||||
So(resp, ShouldNotBeNil)
|
||||
So(resp.StatusCode(), ShouldEqual, 200)
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user