mirror of
https://github.com/project-zot/zot.git
synced 2024-12-16 21:56:37 -05:00
fix(authn): handle the case where zot with openid runs behind a proxy (#1675)
added a new config option under 'http' called externalURL which is used by openid/oauth2 clients to redirect back to zot Signed-off-by: Petu Eusebiu <peusebiu@cisco.com>
This commit is contained in:
parent
ed90e3bd24
commit
4d125d55ed
5 changed files with 320 additions and 259 deletions
|
@ -181,6 +181,8 @@ zot can be configured to use the above providers with:
|
||||||
```
|
```
|
||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"port": "8080",
|
||||||
"auth": {
|
"auth": {
|
||||||
"openid": {
|
"openid": {
|
||||||
"providers": {
|
"providers": {
|
||||||
|
@ -207,7 +209,7 @@ zot can be configured to use the above providers with:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The login with either provider use http://127.0.0.1:8080/auth/login?provider=\<provider\>&callback_ui=http://127.0.0.1:8080/home
|
To login with either provider use http://127.0.0.1:8080/auth/login?provider=\<provider\>&callback_ui=http://127.0.0.1:8080/home
|
||||||
for example to login with github use http://127.0.0.1:8080/auth/login?provider=github&callback_ui=http://127.0.0.1:8080/home
|
for example to login with github use http://127.0.0.1:8080/auth/login?provider=github&callback_ui=http://127.0.0.1:8080/home
|
||||||
|
|
||||||
callback_ui query parameter is used by zot to redirect to UI after a successful openid/oauth2 authentication
|
callback_ui query parameter is used by zot to redirect to UI after a successful openid/oauth2 authentication
|
||||||
|
@ -258,6 +260,30 @@ images to/from zot.
|
||||||
Given this limitation, if openif authentication is enabled in the configuration, API keys are also enabled
|
Given this limitation, if openif authentication is enabled in the configuration, API keys are also enabled
|
||||||
implicitly, as a viable alternative authentication method for pushing and pulling container images.
|
implicitly, as a viable alternative authentication method for pushing and pulling container images.
|
||||||
|
|
||||||
|
### OpenID/OAuth2 social login behind a proxy/load balancer
|
||||||
|
|
||||||
|
In the case of running zot with openid enabled behind a proxy/load balancer http.externalUrl should be provided.
|
||||||
|
|
||||||
|
```
|
||||||
|
"http": {
|
||||||
|
"address": "0.0.0.0",
|
||||||
|
"port": "8080",
|
||||||
|
"externalUrl: "https://zot.example.com",
|
||||||
|
"auth": {
|
||||||
|
"openid": {
|
||||||
|
"providers": {
|
||||||
|
"github": {
|
||||||
|
"clientid": <client_id>,
|
||||||
|
"clientsecret": <client_secret>,
|
||||||
|
"scopes": ["read:org", "user", "repo"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This config value will be used by oauth2/openid clients to redirect back to zot.
|
||||||
|
|
||||||
### Session based login
|
### Session based login
|
||||||
|
|
||||||
Whenever a user logs in zot using any of the auth options available(basic auth/openid) zot will set a 'session' cookie on its response.
|
Whenever a user logs in zot using any of the auth options available(basic auth/openid) zot will set a 'session' cookie on its response.
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
"http": {
|
"http": {
|
||||||
"address": "127.0.0.1",
|
"address": "127.0.0.1",
|
||||||
"port": "8080",
|
"port": "8080",
|
||||||
|
"externalUrl": "http://127.0.0.1:8080",
|
||||||
"realm": "zot",
|
"realm": "zot",
|
||||||
"auth": {
|
"auth": {
|
||||||
"htpasswd": {
|
"htpasswd": {
|
||||||
|
|
|
@ -586,11 +586,6 @@ func getRelyingPartyArgs(cfg *config.Config, provider string) (
|
||||||
panic(zerr.ErrOpenIDProviderDoesNotExist)
|
panic(zerr.ErrOpenIDProviderDoesNotExist)
|
||||||
}
|
}
|
||||||
|
|
||||||
scheme := "http"
|
|
||||||
if cfg.HTTP.TLS != nil {
|
|
||||||
scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
clientID := cfg.HTTP.Auth.OpenID.Providers[provider].ClientID
|
clientID := cfg.HTTP.Auth.OpenID.Providers[provider].ClientID
|
||||||
clientSecret := cfg.HTTP.Auth.OpenID.Providers[provider].ClientSecret
|
clientSecret := cfg.HTTP.Auth.OpenID.Providers[provider].ClientSecret
|
||||||
|
|
||||||
|
@ -604,7 +599,22 @@ func getRelyingPartyArgs(cfg *config.Config, provider string) (
|
||||||
issuer := cfg.HTTP.Auth.OpenID.Providers[provider].Issuer
|
issuer := cfg.HTTP.Auth.OpenID.Providers[provider].Issuer
|
||||||
keyPath := cfg.HTTP.Auth.OpenID.Providers[provider].KeyPath
|
keyPath := cfg.HTTP.Auth.OpenID.Providers[provider].KeyPath
|
||||||
baseURL := net.JoinHostPort(cfg.HTTP.Address, port)
|
baseURL := net.JoinHostPort(cfg.HTTP.Address, port)
|
||||||
redirectURI := fmt.Sprintf("%s://%s%s", scheme, baseURL, constants.CallbackBasePath+fmt.Sprintf("/%s", provider))
|
|
||||||
|
callback := constants.CallbackBasePath + fmt.Sprintf("/%s", provider)
|
||||||
|
|
||||||
|
var redirectURI string
|
||||||
|
|
||||||
|
if cfg.HTTP.ExternalURL != "" {
|
||||||
|
externalURL := strings.TrimSuffix(cfg.HTTP.ExternalURL, "/")
|
||||||
|
redirectURI = fmt.Sprintf("%s%s", externalURL, callback)
|
||||||
|
} else {
|
||||||
|
scheme := "http"
|
||||||
|
if cfg.HTTP.TLS != nil {
|
||||||
|
scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
redirectURI = fmt.Sprintf("%s://%s%s", scheme, baseURL, callback)
|
||||||
|
}
|
||||||
|
|
||||||
options := []rp.Option{
|
options := []rp.Option{
|
||||||
rp.WithVerifierOpts(rp.WithIssuedAtOffset(issuedAtOffset)),
|
rp.WithVerifierOpts(rp.WithIssuedAtOffset(issuedAtOffset)),
|
||||||
|
|
|
@ -84,6 +84,7 @@ type RatelimitConfig struct {
|
||||||
//nolint:maligned
|
//nolint:maligned
|
||||||
type HTTPConfig struct {
|
type HTTPConfig struct {
|
||||||
Address string
|
Address string
|
||||||
|
ExternalURL string `mapstructure:",omitempty"`
|
||||||
Port string
|
Port string
|
||||||
AllowOrigin string // comma separated
|
AllowOrigin string // comma separated
|
||||||
TLS *TLSConfig
|
TLS *TLSConfig
|
||||||
|
|
|
@ -2595,6 +2595,23 @@ func TestOpenIDMiddleware(t *testing.T) {
|
||||||
conf := config.New()
|
conf := config.New()
|
||||||
conf.HTTP.Port = port
|
conf.HTTP.Port = port
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
testCaseName string
|
||||||
|
address string
|
||||||
|
externalURL string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
address: "0.0.0.0",
|
||||||
|
externalURL: fmt.Sprintf("http://%s", net.JoinHostPort(conf.HTTP.Address, conf.HTTP.Port)),
|
||||||
|
testCaseName: "with ExternalURL provided in config",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
address: "127.0.0.1",
|
||||||
|
externalURL: "",
|
||||||
|
testCaseName: "without ExternalURL provided in config",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// need a username different than ldap one, to test both logic
|
// need a username different than ldap one, to test both logic
|
||||||
content := fmt.Sprintf("%s:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n", htpasswdUsername)
|
content := fmt.Sprintf("%s:$2y$05$hlbSXDp6hzDLu6VwACS39ORvVRpr3OMR4RlJ31jtlaOEGnPjKZI1m\n", htpasswdUsername)
|
||||||
htpasswdPath := test.MakeHtpasswdFileFromString(content)
|
htpasswdPath := test.MakeHtpasswdFileFromString(content)
|
||||||
|
@ -2674,239 +2691,245 @@ func TestOpenIDMiddleware(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctlr := api.NewController(conf)
|
ctlr := api.NewController(conf)
|
||||||
dir := t.TempDir()
|
|
||||||
|
|
||||||
ctlr.Config.Storage.RootDirectory = dir
|
for _, testcase := range testCases {
|
||||||
|
t.Run(testcase.testCaseName, func(t *testing.T) {
|
||||||
|
dir := t.TempDir()
|
||||||
|
|
||||||
cm := test.NewControllerManager(ctlr)
|
ctlr.Config.Storage.RootDirectory = dir
|
||||||
|
ctlr.Config.HTTP.ExternalURL = testcase.externalURL
|
||||||
|
ctlr.Config.HTTP.Address = testcase.address
|
||||||
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
|
||||||
cm.StartServer()
|
cm.StartServer()
|
||||||
defer cm.StopServer()
|
defer cm.StopServer()
|
||||||
test.WaitTillServerReady(baseURL)
|
test.WaitTillServerReady(baseURL)
|
||||||
|
|
||||||
Convey("browser client requests", t, func() {
|
Convey("browser client requests", t, func() {
|
||||||
Convey("login with no provider supplied", func() {
|
Convey("login with no provider supplied", func() {
|
||||||
client := resty.New()
|
client := resty.New()
|
||||||
client.SetRedirectPolicy(test.CustomRedirectPolicy(20))
|
client.SetRedirectPolicy(test.CustomRedirectPolicy(20))
|
||||||
// first login user
|
// first login user
|
||||||
resp, err := client.R().
|
resp, err := client.R().
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
SetQueryParam("provider", "unknown").
|
SetQueryParam("provider", "unknown").
|
||||||
Get(baseURL + constants.LoginPath)
|
Get(baseURL + constants.LoginPath)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp, ShouldNotBeNil)
|
So(resp, ShouldNotBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
|
So(resp.StatusCode(), ShouldEqual, http.StatusBadRequest)
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("login with openid and get catalog with session", func() {
|
Convey("login with openid and get catalog with session", func() {
|
||||||
client := resty.New()
|
client := resty.New()
|
||||||
client.SetRedirectPolicy(test.CustomRedirectPolicy(20))
|
client.SetRedirectPolicy(test.CustomRedirectPolicy(20))
|
||||||
|
|
||||||
Convey("with callback_ui value provided", func() {
|
Convey("with callback_ui value provided", func() {
|
||||||
// first login user
|
// first login user
|
||||||
resp, err := client.R().
|
resp, err := client.R().
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
SetQueryParam("provider", "dex").
|
SetQueryParam("provider", "dex").
|
||||||
SetQueryParam("callback_ui", baseURL+"/v2/").
|
SetQueryParam("callback_ui", baseURL+"/v2/").
|
||||||
Get(baseURL + constants.LoginPath)
|
Get(baseURL + constants.LoginPath)
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
So(resp, ShouldNotBeNil)
|
So(resp, ShouldNotBeNil)
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
})
|
||||||
|
|
||||||
|
// first login user
|
||||||
|
resp, err := client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
SetQueryParam("provider", "dex").
|
||||||
|
Get(baseURL + constants.LoginPath)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
||||||
|
|
||||||
|
client.SetCookies(resp.Cookies())
|
||||||
|
|
||||||
|
// call endpoint with session (added to client after previous request)
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// logout with options method for coverage
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Options(baseURL + constants.LogoutPath)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
|
||||||
|
// logout user
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Post(baseURL + constants.LogoutPath)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// calling endpoint should fail with unathorized access
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
|
//nolint: dupl
|
||||||
|
Convey("login with basic auth(htpasswd) and get catalog with session", func() {
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
|
// without creds, should get access error
|
||||||
|
resp, err := client.R().Get(baseURL + "/v2/")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
var e apiErr.Error
|
||||||
|
err = json.Unmarshal(resp.Body(), &e)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
// first login user
|
||||||
|
// with creds, should get expected status code
|
||||||
|
resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().
|
||||||
|
SetBasicAuth(htpasswdUsername, passphrase).
|
||||||
|
Get(baseURL + constants.FullMgmt)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
client.SetCookies(resp.Cookies())
|
||||||
|
|
||||||
|
// call endpoint with session, without credentials, (added to client after previous request)
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + constants.FullMgmt)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// logout user
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Post(baseURL + constants.LogoutPath)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// calling endpoint should fail with unathorized access
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
|
//nolint: dupl
|
||||||
|
Convey("login with ldap and get catalog", func() {
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
|
// without creds, should get access error
|
||||||
|
resp, err := client.R().Get(baseURL + "/v2/")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
var e apiErr.Error
|
||||||
|
err = json.Unmarshal(resp.Body(), &e)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
// first login user
|
||||||
|
// with creds, should get expected status code
|
||||||
|
resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().
|
||||||
|
SetBasicAuth(username, passphrase).
|
||||||
|
Get(baseURL + constants.FullMgmt)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
client.SetCookies(resp.Cookies())
|
||||||
|
|
||||||
|
// call endpoint with session, without credentials, (added to client after previous request)
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + constants.FullMgmt)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// logout user
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Post(baseURL + constants.LogoutPath)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// calling endpoint should fail with unathorized access
|
||||||
|
resp, err = client.R().
|
||||||
|
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("unauthenticated catalog request", func() {
|
||||||
|
client := resty.New()
|
||||||
|
|
||||||
|
// mgmt should work both unauthenticated and authenticated
|
||||||
|
resp, err := client.R().
|
||||||
|
Get(baseURL + constants.FullMgmt)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
||||||
|
|
||||||
|
// call endpoint without session
|
||||||
|
resp, err = client.R().
|
||||||
|
Get(baseURL + "/v2/_catalog")
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
So(resp, ShouldNotBeNil)
|
||||||
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
// first login user
|
|
||||||
resp, err := client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
SetQueryParam("provider", "dex").
|
|
||||||
Get(baseURL + constants.LoginPath)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusCreated)
|
|
||||||
|
|
||||||
client.SetCookies(resp.Cookies())
|
|
||||||
|
|
||||||
// call endpoint with session (added to client after previous request)
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// logout with options method for coverage
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Options(baseURL + constants.LogoutPath)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
|
|
||||||
// logout user
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Post(baseURL + constants.LogoutPath)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// calling endpoint should fail with unathorized access
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
})
|
})
|
||||||
|
}
|
||||||
//nolint: dupl
|
|
||||||
Convey("login with basic auth(htpasswd) and get catalog with session", func() {
|
|
||||||
client := resty.New()
|
|
||||||
|
|
||||||
// without creds, should get access error
|
|
||||||
resp, err := client.R().Get(baseURL + "/v2/")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
var e apiErr.Error
|
|
||||||
err = json.Unmarshal(resp.Body(), &e)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
// first login user
|
|
||||||
// with creds, should get expected status code
|
|
||||||
resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().SetBasicAuth(htpasswdUsername, passphrase).Get(baseURL + "/v2/")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().
|
|
||||||
SetBasicAuth(htpasswdUsername, passphrase).
|
|
||||||
Get(baseURL + constants.FullMgmt)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
client.SetCookies(resp.Cookies())
|
|
||||||
|
|
||||||
// call endpoint with session, without credentials, (added to client after previous request)
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + constants.FullMgmt)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// logout user
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Post(baseURL + constants.LogoutPath)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// calling endpoint should fail with unathorized access
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
})
|
|
||||||
|
|
||||||
//nolint: dupl
|
|
||||||
Convey("login with ldap and get catalog", func() {
|
|
||||||
client := resty.New()
|
|
||||||
|
|
||||||
// without creds, should get access error
|
|
||||||
resp, err := client.R().Get(baseURL + "/v2/")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
var e apiErr.Error
|
|
||||||
err = json.Unmarshal(resp.Body(), &e)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
// first login user
|
|
||||||
// with creds, should get expected status code
|
|
||||||
resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().SetBasicAuth(username, passphrase).Get(baseURL + "/v2/")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().
|
|
||||||
SetBasicAuth(username, passphrase).
|
|
||||||
Get(baseURL + constants.FullMgmt)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
client.SetCookies(resp.Cookies())
|
|
||||||
|
|
||||||
// call endpoint with session, without credentials, (added to client after previous request)
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + constants.FullMgmt)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// logout user
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Post(baseURL + constants.LogoutPath)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// calling endpoint should fail with unathorized access
|
|
||||||
resp, err = client.R().
|
|
||||||
SetHeader(constants.SessionClientHeaderName, constants.SessionClientHeaderValue).
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("unauthenticated catalog request", func() {
|
|
||||||
client := resty.New()
|
|
||||||
|
|
||||||
// mgmt should work both unauthenticated and authenticated
|
|
||||||
resp, err := client.R().
|
|
||||||
Get(baseURL + constants.FullMgmt)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusOK)
|
|
||||||
|
|
||||||
// call endpoint without session
|
|
||||||
resp, err = client.R().
|
|
||||||
Get(baseURL + "/v2/_catalog")
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
So(resp, ShouldNotBeNil)
|
|
||||||
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsOpenIDEnabled(t *testing.T) {
|
func TestIsOpenIDEnabled(t *testing.T) {
|
||||||
|
@ -2931,38 +2954,38 @@ func TestIsOpenIDEnabled(t *testing.T) {
|
||||||
|
|
||||||
rootDir := t.TempDir()
|
rootDir := t.TempDir()
|
||||||
|
|
||||||
// Convey("Only OAuth2 provided", func() {
|
Convey("Only OAuth2 provided", func() {
|
||||||
// mockOIDCConfig := mockOIDCServer.Config()
|
mockOIDCConfig := mockOIDCServer.Config()
|
||||||
// conf.HTTP.Auth = &config.AuthConfig{
|
conf.HTTP.Auth = &config.AuthConfig{
|
||||||
// OpenID: &config.OpenIDConfig{
|
OpenID: &config.OpenIDConfig{
|
||||||
// Providers: map[string]config.OpenIDProviderConfig{
|
Providers: map[string]config.OpenIDProviderConfig{
|
||||||
// "github": {
|
"github": {
|
||||||
// ClientID: mockOIDCConfig.ClientID,
|
ClientID: mockOIDCConfig.ClientID,
|
||||||
// ClientSecret: mockOIDCConfig.ClientSecret,
|
ClientSecret: mockOIDCConfig.ClientSecret,
|
||||||
// KeyPath: "",
|
KeyPath: "",
|
||||||
// Issuer: mockOIDCConfig.Issuer,
|
Issuer: mockOIDCConfig.Issuer,
|
||||||
// Scopes: []string{"email", "groups"},
|
Scopes: []string{"email", "groups"},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// },
|
},
|
||||||
// }
|
}
|
||||||
|
|
||||||
// ctlr := api.NewController(conf)
|
ctlr := api.NewController(conf)
|
||||||
|
|
||||||
// ctlr.Config.Storage.RootDirectory = rootDir
|
ctlr.Config.Storage.RootDirectory = rootDir
|
||||||
|
|
||||||
// cm := test.NewControllerManager(ctlr)
|
cm := test.NewControllerManager(ctlr)
|
||||||
|
|
||||||
// cm.StartServer()
|
cm.StartServer()
|
||||||
// defer cm.StopServer()
|
defer cm.StopServer()
|
||||||
// test.WaitTillServerReady(baseURL)
|
test.WaitTillServerReady(baseURL)
|
||||||
|
|
||||||
// resp, err := resty.R().
|
resp, err := resty.R().
|
||||||
// Get(baseURL + "/v2/")
|
Get(baseURL + "/v2/")
|
||||||
// So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
// So(resp, ShouldNotBeNil)
|
So(resp, ShouldNotBeNil)
|
||||||
// So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
So(resp.StatusCode(), ShouldEqual, http.StatusUnauthorized)
|
||||||
// })
|
})
|
||||||
|
|
||||||
Convey("Unsupported provider", func() {
|
Convey("Unsupported provider", func() {
|
||||||
mockOIDCConfig := mockOIDCServer.Config()
|
mockOIDCConfig := mockOIDCServer.Config()
|
||||||
|
|
Loading…
Reference in a new issue