diff --git a/.travis.yml b/.travis.yml index 7337b0bdd..8c734d966 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ env: MAX_JOB_WORKERS: 3 SECRET_KEY: 1234567890123456 AUTH_MODE: db_auth - SELF_REGISTRATION: "on" + SELF_REGISTRATION: on before_install: - sudo ./tests/hostcfg.sh diff --git a/src/adminserver/api/cfg.go b/src/adminserver/api/cfg.go index 79b0b4dcf..6a2198c6e 100644 --- a/src/adminserver/api/cfg.go +++ b/src/adminserver/api/cfg.go @@ -102,79 +102,3 @@ func UpdateCfgs(w http.ResponseWriter, r *http.Request) { return } } - -/* -// populate attrs of cfg according to m -func populate(cfg *models.SystemCfg, m map[string]string) error { - if mode, ok := m[comcfg.AUTHMode]; ok { - cfg.Authentication.Mode = mode - } - if value, ok := m[comcfg.SelfRegistration]; ok { - cfg.Authentication.SelfRegistration = value == "1" - } - if url, ok := m[comcfg.LDAPURL]; ok { - cfg.Authentication.LDAP.URL = url - } - if dn, ok := m[comcfg.LDAPSearchDN]; ok { - cfg.Authentication.LDAP.SearchDN = dn - } - if pwd, ok := m[comcfg.LDAPSearchPwd]; ok { - cfg.Authentication.LDAP.SearchPassword = pwd - } - if dn, ok := m[comcfg.LDAPBaseDN]; ok { - cfg.Authentication.LDAP.BaseDN = dn - } - if uid, ok := m[comcfg.LDAPUID]; ok { - cfg.Authentication.LDAP.UID = uid - } - if filter, ok := m[comcfg.LDAPFilter]; ok { - cfg.Authentication.LDAP.Filter = filter - } - if scope, ok := m[comcfg.LDAPScope]; ok { - i, err := strconv.Atoi(scope) - if err != nil { - return err - } - cfg.Authentication.LDAP.Scope = i - } - if timeout, ok := m[comcfg.LDAPTimeout]; ok { - i, err := strconv.Atoi(timeout) - if err != nil { - return err - } - cfg.Authentication.LDAP.Timeout = i - } - - if value, ok := m[comcfg.EmailHost]; ok { - cfg.Email.Host = value - } - if value, ok := m[comcfg.EmailPort]; ok { - cfg.Email.Port = value - } - if value, ok := m[comcfg.EmailUsername]; ok { - cfg.Email.Username = value - } - if value, ok := m[comcfg.EmailPassword]; ok { - cfg.Email.Password = value - } - if value, ok := m[comcfg.EmailSSL]; ok { - cfg.Email.SSL = value == "1" - } - if value, ok := m[comcfg.EmailFrom]; ok { - cfg.Email.From = value - } - if value, ok := m[comcfg.EmailIdentity]; ok { - cfg.Email.Identity = value - } - - if value, ok := m[comcfg.ProjectCreationRestriction]; ok { - cfg.ProjectCreationRestriction = value - } - - if value, ok := m[comcfg.VerifyRemoteCert]; ok { - cfg.VerifyRemoteCert = value == "1" - } - - return nil -} -*/ diff --git a/src/adminserver/api/cfg_test.go b/src/adminserver/api/cfg_test.go index 320aa5e50..8ae8553c2 100644 --- a/src/adminserver/api/cfg_test.go +++ b/src/adminserver/api/cfg_test.go @@ -16,10 +16,152 @@ package api import ( + "bytes" + "encoding/json" + "io" + "io/ioutil" + "net/http" "net/http/httptest" + "os" + "testing" + + "github.com/vmware/harbor/src/adminserver/systemcfg" + "github.com/vmware/harbor/src/common/config" ) -func test() { - httptest.NewRecorder() +func TestConfigAPI(t *testing.T) { + path := "/tmp/config.json" + secret := "secret" + envs := map[string]string{ + "JSON_STORE_PATH": path, + "UI_SECRET": secret, + "MYSQL_PORT": "3306", + "TOKEN_EXPIRATION": "30", + "CFG_EXPIRATION": "5", + "MAX_JOB_WORKERS": "3", + "LDAP_SCOPE": "3", + "LDAP_TIMEOUT": "30", + "EMAIL_PORT": "25", + } + + for k, v := range envs { + if err := os.Setenv(k, v); err != nil { + t.Fatalf("failed to set env %s: %v", k, err) + } + } + defer os.Remove(path) + + if err := systemcfg.Init(); err != nil { + t.Errorf("failed to initialize systemconfigurations: %v", err) + return + } + + r, err := http.NewRequest("GET", "", nil) + if err != nil { + t.Errorf("failed to create request: %v", err) + return + } + + w := httptest.NewRecorder() + ListCfgs(w, r) + if w.Code != http.StatusUnauthorized { + t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusUnauthorized) + return + } + + r.AddCookie(&http.Cookie{ + Name: "secret", + Value: secret, + }) + + w = httptest.NewRecorder() + ListCfgs(w, r) + if w.Code != http.StatusOK { + t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK) + return + } + + m, err := parse(w.Body) + if err != nil { + t.Errorf("failed to parse response body: %v", err) + return + } + + scope := int(m[config.LDAPScope].(float64)) + if scope != 3 { + t.Errorf("unexpected ldap scope: %d != %d", scope, 3) + return + } + + // modify configurations + c := map[string]interface{}{ + config.AUTHMode: config.LDAPAuth, + } + + b, err := json.Marshal(c) + if err != nil { + t.Errorf("failed to marshal configuartions: %v", err) + return + } + + w = httptest.NewRecorder() + r, err = http.NewRequest("GET", "", bytes.NewReader(b)) + if err != nil { + t.Errorf("failed to create request: %v", err) + return + } + r.AddCookie(&http.Cookie{ + Name: "secret", + Value: secret, + }) + + UpdateCfgs(w, r) + + if w.Code != http.StatusOK { + t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK) + return + } + + // confirm the modification is done + r, err = http.NewRequest("GET", "", nil) + if err != nil { + t.Errorf("failed to create request: %v", err) + return + } + r.AddCookie(&http.Cookie{ + Name: "secret", + Value: secret, + }) + w = httptest.NewRecorder() + ListCfgs(w, r) + if w.Code != http.StatusOK { + t.Errorf("unexpected status code: %d != %d", w.Code, http.StatusOK) + return + } + + m, err = parse(w.Body) + if err != nil { + t.Errorf("failed to parse response body: %v", err) + return + } + + mode := m[config.AUTHMode].(string) + if mode != config.LDAPAuth { + t.Errorf("unexpected ldap scope: %s != %s", mode, config.LDAPAuth) + return + } +} + +func parse(reader io.Reader) (map[string]interface{}, error) { + b, err := ioutil.ReadAll(reader) + if err != nil { + return nil, err + } + + m := map[string]interface{}{} + if err := json.Unmarshal(b, &m); err != nil { + return nil, err + } + return m, nil } diff --git a/src/common/config/config_test.go b/src/common/config/config_test.go index 81448edf3..77b8b7829 100644 --- a/src/common/config/config_test.go +++ b/src/common/config/config_test.go @@ -13,3 +13,6 @@ limitations under the License. */ package config + +// the functions in common/config/config.go have been tested +// by cases in UI and Jobservice diff --git a/src/common/models/config.go b/src/common/models/config.go index 50a73edef..16f518d2b 100644 --- a/src/common/models/config.go +++ b/src/common/models/config.go @@ -15,12 +15,14 @@ package models +/* // Authentication ... type Authentication struct { Mode string `json:"mode"` SelfRegistration bool `json:"self_registration"` LDAP *LDAP `json:"ldap,omitempty"` } +*/ // LDAP ... type LDAP struct { @@ -66,6 +68,7 @@ type Email struct { From string `json:"from"` } +/* // Registry ... type Registry struct { URL string `json:"url"` @@ -94,3 +97,4 @@ type SystemCfg struct { SecretKey string `json:"secret_key,omitempty"` CfgExpiration int `json:"cfg_expiration"` } +*/ diff --git a/src/ui/api/config.go b/src/ui/api/config.go index 7c1f2a2f1..89f5371a0 100644 --- a/src/ui/api/config.go +++ b/src/ui/api/config.go @@ -262,6 +262,10 @@ func convertForPut(m map[string]string) (map[string]interface{}, error) { } for _, k := range numKeys { + if _, ok := cfg[k]; !ok { + continue + } + v, err := strconv.Atoi(cfg[k].(string)) if err != nil { return nil, err @@ -270,6 +274,10 @@ func convertForPut(m map[string]string) (map[string]interface{}, error) { } for _, k := range boolKeys { + if _, ok := cfg[k]; !ok { + continue + } + cfg[k] = cfg[k] == "1" } diff --git a/src/ui/api/config_test.go b/src/ui/api/config_test.go new file mode 100644 index 000000000..ca4b4e2c2 --- /dev/null +++ b/src/ui/api/config_test.go @@ -0,0 +1,70 @@ +/* + 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 api + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/vmware/harbor/src/common/config" +) + +func TestGetConfig(t *testing.T) { + fmt.Println("Testing getting configurations") + assert := assert.New(t) + apiTest := newHarborAPI() + + //case 1: get configurations without admin role + code, _, err := apiTest.GetConfig(*testUser) + if err != nil { + t.Fatalf("failed to get configurations: %v", err) + } + + assert.Equal(401, code, "the status code of getting configurations with non-admin user should be 401") + + //case 2: get configurations with admin role + code, cfg, err := apiTest.GetConfig(*admin) + if err != nil { + t.Fatalf("failed to get configurations: %v", err) + } + + if !assert.Equal(200, code, "the status code of getting configurations with admin user should be 200") { + return + } + + mode := cfg[config.AUTHMode].Value.(string) + assert.Equal(config.DBAuth, mode, fmt.Sprintf("the auth mode should be %s", config.DBAuth)) +} + +func TestPutConfig(t *testing.T) { + fmt.Println("Testing modifying configurations") + assert := assert.New(t) + apiTest := newHarborAPI() + + cfg := map[string]string{ + config.VerifyRemoteCert: "0", + } + + code, err := apiTest.PutConfig(*admin, cfg) + if err != nil { + t.Fatalf("failed to get configurations: %v", err) + } + + if !assert.Equal(200, code, "the status code of modifying configurations with admin user should be 200") { + return + } +} diff --git a/src/ui/api/harborapi_test.go b/src/ui/api/harborapi_test.go index ac6dd6819..c55fb243c 100644 --- a/src/ui/api/harborapi_test.go +++ b/src/ui/api/harborapi_test.go @@ -99,6 +99,7 @@ func init() { beego.Router("/api/systeminfo/volumes", &SystemInfoAPI{}, "get:GetVolumeInfo") beego.Router("/api/systeminfo/getcert", &SystemInfoAPI{}, "get:GetCert") beego.Router("/api/ldap/ping", &LdapAPI{}, "post:Ping") + beego.Router("/api/configurations", &ConfigAPI{}) _ = updateInitPassword(1, "Harbor12345") @@ -922,3 +923,23 @@ func (a testapi) LdapPost(authInfo usrInfo, ldapConf apilib.LdapConf) (int, erro httpStatusCode, _, err := request(_sling, jsonAcceptHeader, authInfo) return httpStatusCode, err } + +func (a testapi) GetConfig(authInfo usrInfo) (int, map[string]*value, error) { + _sling := sling.New().Base(a.basePath).Get("/api/configurations") + + cfg := map[string]*value{} + + code, body, err := request(_sling, jsonAcceptHeader, authInfo) + if err == nil && code == 200 { + err = json.Unmarshal(body, &cfg) + } + return code, cfg, err +} + +func (a testapi) PutConfig(authInfo usrInfo, cfg map[string]string) (int, error) { + _sling := sling.New().Base(a.basePath).Put("/api/configurations").BodyJSON(cfg) + + code, _, err := request(_sling, jsonAcceptHeader, authInfo) + + return code, err +}