mirror of
https://github.com/goharbor/harbor.git
synced 2024-11-25 11:46:43 +01:00
Merge pull request #1101 from reasonerjt/config-refactory
Config refactory
This commit is contained in:
commit
ffbe980622
@ -3,11 +3,11 @@ MYSQL_PORT=3306
|
||||
MYSQL_USR=root
|
||||
MYSQL_PWD=$db_password
|
||||
REGISTRY_URL=http://registry:5000
|
||||
JOB_SERVICE_URL=http://jobservice
|
||||
UI_URL=http://ui
|
||||
CONFIG_PATH=/etc/ui/app.conf
|
||||
HARBOR_REG_URL=$hostname
|
||||
EXT_REG_URL=$hostname
|
||||
HARBOR_ADMIN_PASSWORD=$harbor_admin_password
|
||||
HARBOR_URL=$ui_url
|
||||
AUTH_MODE=$auth_mode
|
||||
LDAP_URL=$ldap_url
|
||||
LDAP_SEARCH_DN=$ldap_searchdn
|
||||
@ -23,6 +23,7 @@ USE_COMPRESSED_JS=$use_compressed_js
|
||||
LOG_LEVEL=debug
|
||||
GODEBUG=netdns=cgo
|
||||
EXT_ENDPOINT=$ui_url
|
||||
TOKEN_URL=http://ui
|
||||
TOKEN_ENDPOINT=http://ui
|
||||
VERIFY_REMOTE_CERT=$verify_remote_cert
|
||||
TOKEN_EXPIRATION=$token_expiration
|
||||
PROJECT_CREATION_RESTRICTION=$project_creation_restriction
|
||||
|
@ -83,6 +83,9 @@ crt_organizationalunit = organizational unit
|
||||
crt_commonname = example.com
|
||||
crt_email = example@example.com
|
||||
|
||||
#The flag to control what users have permission to create projects
|
||||
#Be default everyone can create a project, set to "adminonly" such that only admin can create project.
|
||||
project_creation_restriction = everyone
|
||||
|
||||
#The path of cert and key files for nginx, they are applied only the protocol is set to https
|
||||
ssl_cert = /data/server.crt
|
||||
|
@ -32,6 +32,10 @@ def validate(conf):
|
||||
cert_key_path = rcp.get("configuration", "ssl_cert_key")
|
||||
if not os.path.isfile(cert_key_path):
|
||||
raise Exception("Error: The path for certificate key: %s is invalid" % cert_key_path)
|
||||
project_creation = rcp.get("configuration", "project_creation_restriction")
|
||||
|
||||
if project_creation != "everyone" and project_creation != "adminonly":
|
||||
raise Exception("Error invalid value for project_creation_restriction: %s" % project_creation)
|
||||
|
||||
def get_secret_key(path):
|
||||
key_file = os.path.join(path, "secretkey")
|
||||
@ -115,6 +119,7 @@ crt_email = rcp.get("configuration", "crt_email")
|
||||
max_job_workers = rcp.get("configuration", "max_job_workers")
|
||||
token_expiration = rcp.get("configuration", "token_expiration")
|
||||
verify_remote_cert = rcp.get("configuration", "verify_remote_cert")
|
||||
proj_cre_restriction = rcp.get("configuration", "project_creation_restriction")
|
||||
#secret_key = rcp.get("configuration", "secret_key")
|
||||
secret_key = get_secret_key(args.data_volume)
|
||||
########
|
||||
@ -200,6 +205,7 @@ render(os.path.join(templates_dir, "ui", "env"),
|
||||
ui_secret=ui_secret,
|
||||
secret_key=secret_key,
|
||||
verify_remote_cert=verify_remote_cert,
|
||||
project_creation_restriction=proj_cre_restriction,
|
||||
token_expiration=token_expiration)
|
||||
|
||||
render(os.path.join(templates_dir, "ui", "app.conf"),
|
||||
|
@ -19,14 +19,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/astaxie/beego/validation"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
)
|
||||
@ -213,12 +213,5 @@ func (b *BaseAPI) GetPaginationParams() (page, pageSize int64) {
|
||||
|
||||
// GetIsInsecure ...
|
||||
func GetIsInsecure() bool {
|
||||
insecure := false
|
||||
|
||||
verifyRemoteCert := os.Getenv("VERIFY_REMOTE_CERT")
|
||||
if verifyRemoteCert == "off" {
|
||||
insecure = true
|
||||
}
|
||||
|
||||
return insecure
|
||||
return config.VerifyRemoteCert()
|
||||
}
|
||||
|
178
src/common/config/config.go
Normal file
178
src/common/config/config.go
Normal file
@ -0,0 +1,178 @@
|
||||
/*
|
||||
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 config provide methods to get the configurations reqruied by code in src/common
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ConfLoader is the interface to load configurations
|
||||
type ConfLoader interface {
|
||||
// Load will load configuration from different source into a string map, the values in the map will be parsed in to configurations.
|
||||
Load() (map[string]string, error)
|
||||
}
|
||||
|
||||
// EnvConfigLoader loads the config from env vars.
|
||||
type EnvConfigLoader struct {
|
||||
Keys []string
|
||||
}
|
||||
|
||||
// Load ...
|
||||
func (ec *EnvConfigLoader) Load() (map[string]string, error) {
|
||||
m := make(map[string]string)
|
||||
for _, k := range ec.Keys {
|
||||
m[k] = os.Getenv(k)
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
// ConfParser ...
|
||||
type ConfParser interface {
|
||||
|
||||
//Parse parse the input raw map into a config map
|
||||
Parse(raw map[string]string, config map[string]interface{}) error
|
||||
}
|
||||
|
||||
// Config wraps a map for the processed configuration values,
|
||||
// and loader parser to read configuration from external source and process the values.
|
||||
type Config struct {
|
||||
Config map[string]interface{}
|
||||
Loader ConfLoader
|
||||
Parser ConfParser
|
||||
}
|
||||
|
||||
// Load reload the configurations
|
||||
func (conf *Config) Load() error {
|
||||
rawMap, err := conf.Loader.Load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = conf.Parser.Parse(rawMap, conf.Config)
|
||||
return err
|
||||
}
|
||||
|
||||
// MySQLSetting wraps the settings of a MySQL DB
|
||||
type MySQLSetting struct {
|
||||
Database string
|
||||
User string
|
||||
Password string
|
||||
Host string
|
||||
Port string
|
||||
}
|
||||
|
||||
// SQLiteSetting wraps the settings of a SQLite DB
|
||||
type SQLiteSetting struct {
|
||||
FilePath string
|
||||
}
|
||||
|
||||
type commonParser struct{}
|
||||
|
||||
// Parse parses the db settings, veryfy_remote_cert, ext_endpoint, token_endpoint
|
||||
func (cp *commonParser) Parse(raw map[string]string, config map[string]interface{}) error {
|
||||
db := strings.ToLower(raw["DATABASE"])
|
||||
if db == "mysql" || db == "" {
|
||||
db = "mysql"
|
||||
mySQLDB := raw["MYSQL_DATABASE"]
|
||||
if len(mySQLDB) == 0 {
|
||||
mySQLDB = "registry"
|
||||
}
|
||||
setting := MySQLSetting{
|
||||
mySQLDB,
|
||||
raw["MYSQL_USR"],
|
||||
raw["MYSQL_PWD"],
|
||||
raw["MYSQL_HOST"],
|
||||
raw["MYSQL_PORT"],
|
||||
}
|
||||
config["mysql"] = setting
|
||||
} else if db == "sqlite" {
|
||||
f := raw["SQLITE_FILE"]
|
||||
if len(f) == 0 {
|
||||
f = "registry.db"
|
||||
}
|
||||
setting := SQLiteSetting{
|
||||
f,
|
||||
}
|
||||
config["sqlite"] = setting
|
||||
} else {
|
||||
return fmt.Errorf("Invalid DB: %s", db)
|
||||
}
|
||||
config["database"] = db
|
||||
|
||||
//By default it's true
|
||||
config["verify_remote_cert"] = raw["VERIFY_REMOTE_CERT"] != "off"
|
||||
|
||||
config["ext_endpoint"] = raw["EXT_ENDPOINT"]
|
||||
config["token_endpoint"] = raw["TOKEN_ENDPOINT"]
|
||||
config["log_level"] = raw["LOG_LEVEL"]
|
||||
return nil
|
||||
}
|
||||
|
||||
var commonConfig *Config
|
||||
|
||||
func init() {
|
||||
commonKeys := []string{"DATABASE", "MYSQL_DATABASE", "MYSQL_USR", "MYSQL_PWD", "MYSQL_HOST", "MYSQL_PORT", "SQLITE_FILE", "VERIFY_REMOTE_CERT", "EXT_ENDPOINT", "TOKEN_ENDPOINT", "LOG_LEVEL"}
|
||||
commonConfig = &Config{
|
||||
Config: make(map[string]interface{}),
|
||||
Loader: &EnvConfigLoader{Keys: commonKeys},
|
||||
Parser: &commonParser{},
|
||||
}
|
||||
if err := commonConfig.Load(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload will reload the configuration.
|
||||
func Reload() error {
|
||||
return commonConfig.Load()
|
||||
}
|
||||
|
||||
// Database returns the DB type in configuration.
|
||||
func Database() string {
|
||||
return commonConfig.Config["database"].(string)
|
||||
}
|
||||
|
||||
// MySQL returns the mysql setting in configuration.
|
||||
func MySQL() MySQLSetting {
|
||||
return commonConfig.Config["mysql"].(MySQLSetting)
|
||||
}
|
||||
|
||||
// SQLite returns the SQLite setting
|
||||
func SQLite() SQLiteSetting {
|
||||
return commonConfig.Config["sqlite"].(SQLiteSetting)
|
||||
}
|
||||
|
||||
// VerifyRemoteCert returns bool value.
|
||||
func VerifyRemoteCert() bool {
|
||||
return commonConfig.Config["verify_remote_cert"].(bool)
|
||||
}
|
||||
|
||||
// ExtEndpoint ...
|
||||
func ExtEndpoint() string {
|
||||
return commonConfig.Config["ext_endpoint"].(string)
|
||||
}
|
||||
|
||||
// TokenEndpoint returns the endpoint string of token service, which can be accessed by internal service of Harbor.
|
||||
func TokenEndpoint() string {
|
||||
return commonConfig.Config["token_endpoint"].(string)
|
||||
}
|
||||
|
||||
// LogLevel returns the log level in string format.
|
||||
func LogLevel() string {
|
||||
return commonConfig.Config["log_level"].(string)
|
||||
}
|
111
src/common/config/config_test.go
Normal file
111
src/common/config/config_test.go
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEnvConfLoader(t *testing.T) {
|
||||
os.Unsetenv("KEY2")
|
||||
os.Setenv("KEY1", "V1")
|
||||
os.Setenv("KEY3", "V3")
|
||||
keys := []string{"KEY1", "KEY2"}
|
||||
ecl := EnvConfigLoader{
|
||||
keys,
|
||||
}
|
||||
m, err := ecl.Load()
|
||||
if err != nil {
|
||||
t.Errorf("Error loading the configuration via env: %v", err)
|
||||
}
|
||||
if m["KEY1"] != "V1" {
|
||||
t.Errorf("The value for key KEY1 should be V1, but infact: %s", m["KEY1"])
|
||||
}
|
||||
if len(m["KEY2"]) > 0 {
|
||||
t.Errorf("The value for key KEY2 should be emptye, but infact: %s", m["KEY2"])
|
||||
}
|
||||
if _, ok := m["KEY3"]; ok {
|
||||
t.Errorf("The KEY3 should not be in result as it's not in the initial key list")
|
||||
}
|
||||
os.Unsetenv("KEY1")
|
||||
os.Unsetenv("KEY3")
|
||||
}
|
||||
|
||||
func TestCommonConfig(t *testing.T) {
|
||||
|
||||
mysql := MySQLSetting{"registry", "root", "password", "127.0.0.1", "3306"}
|
||||
sqlite := SQLiteSetting{"file.db"}
|
||||
verify := "off"
|
||||
ext := "http://harbor"
|
||||
token := "http://token"
|
||||
loglevel := "info"
|
||||
|
||||
os.Setenv("DATABASE", "")
|
||||
os.Setenv("MYSQL_DATABASE", mysql.Database)
|
||||
os.Setenv("MYSQL_USR", mysql.User)
|
||||
os.Setenv("MYSQL_PWD", mysql.Password)
|
||||
os.Setenv("MYSQL_HOST", mysql.Host)
|
||||
os.Setenv("MYSQL_PORT", mysql.Port)
|
||||
os.Setenv("SQLITE_FILE", sqlite.FilePath)
|
||||
os.Setenv("VERIFY_REMOTE_CERT", verify)
|
||||
os.Setenv("EXT_ENDPOINT", ext)
|
||||
os.Setenv("TOKEN_ENDPOINT", token)
|
||||
os.Setenv("LOG_LEVEL", loglevel)
|
||||
|
||||
err := Reload()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error when loading the configurations, error: %v", err)
|
||||
}
|
||||
if Database() != "mysql" {
|
||||
t.Errorf("Expected Database value: mysql, fact: %s", mysql)
|
||||
}
|
||||
if MySQL() != mysql {
|
||||
t.Errorf("Expected MySQL setting: %+v, fact: %+v", mysql, MySQL())
|
||||
}
|
||||
if VerifyRemoteCert() {
|
||||
t.Errorf("Expected VerifyRemoteCert: false, env var: %s, fact: %v", verify, VerifyRemoteCert())
|
||||
}
|
||||
if ExtEndpoint() != ext {
|
||||
t.Errorf("Expected ExtEndpoint: %s, fact: %s", ext, ExtEndpoint())
|
||||
}
|
||||
if TokenEndpoint() != token {
|
||||
t.Errorf("Expected TokenEndpoint: %s, fact: %s", token, TokenEndpoint())
|
||||
}
|
||||
if LogLevel() != loglevel {
|
||||
t.Errorf("Expected LogLevel: %s, fact: %s", loglevel, LogLevel())
|
||||
}
|
||||
os.Setenv("DATABASE", "sqlite")
|
||||
err = Reload()
|
||||
if err != nil {
|
||||
t.Errorf("Unexpected error when loading the configurations, error: %v", err)
|
||||
}
|
||||
if SQLite() != sqlite {
|
||||
t.Errorf("Expected SQLite setting: %+v, fact %+v", sqlite, SQLite())
|
||||
}
|
||||
|
||||
os.Unsetenv("DATABASE")
|
||||
os.Unsetenv("MYSQL_DATABASE")
|
||||
os.Unsetenv("MYSQL_USR")
|
||||
os.Unsetenv("MYSQL_PWD")
|
||||
os.Unsetenv("MYSQL_HOST")
|
||||
os.Unsetenv("MYSQL_PORT")
|
||||
os.Unsetenv("SQLITE_FILE")
|
||||
os.Unsetenv("VERIFY_REMOTE_CERT")
|
||||
os.Unsetenv("EXT_ENDPOINT")
|
||||
os.Unsetenv("TOKEN_ENDPOINT")
|
||||
os.Unsetenv("LOG_LEVEL")
|
||||
|
||||
}
|
@ -17,11 +17,10 @@ package dao
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/astaxie/beego/orm"
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
@ -52,42 +51,18 @@ func InitDatabase() {
|
||||
}
|
||||
|
||||
func getDatabase() (db Database, err error) {
|
||||
switch strings.ToLower(os.Getenv("DATABASE")) {
|
||||
switch config.Database() {
|
||||
case "", "mysql":
|
||||
host, port, usr, pwd, database := getMySQLConnInfo()
|
||||
db = NewMySQL(host, port, usr, pwd, database)
|
||||
db = NewMySQL(config.MySQL().Host, config.MySQL().Port, config.MySQL().User,
|
||||
config.MySQL().Password, config.MySQL().Database)
|
||||
case "sqlite":
|
||||
file := getSQLiteConnInfo()
|
||||
db = NewSQLite(file)
|
||||
db = NewSQLite(config.SQLite().FilePath)
|
||||
default:
|
||||
err = fmt.Errorf("invalid database: %s", os.Getenv("DATABASE"))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// TODO read from config
|
||||
func getMySQLConnInfo() (host, port, username, password, database string) {
|
||||
host = os.Getenv("MYSQL_HOST")
|
||||
port = os.Getenv("MYSQL_PORT")
|
||||
username = os.Getenv("MYSQL_USR")
|
||||
password = os.Getenv("MYSQL_PWD")
|
||||
database = os.Getenv("MYSQL_DATABASE")
|
||||
if len(database) == 0 {
|
||||
database = "registry"
|
||||
err = fmt.Errorf("invalid database: %s", config.Database())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// TODO read from config
|
||||
func getSQLiteConnInfo() string {
|
||||
file := os.Getenv("SQLITE_FILE")
|
||||
if len(file) == 0 {
|
||||
file = "registry.db"
|
||||
}
|
||||
return file
|
||||
}
|
||||
|
||||
var globalOrm orm.Ormer
|
||||
var once sync.Once
|
||||
|
||||
|
@ -22,6 +22,8 @@ import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
)
|
||||
|
||||
var logger = New(os.Stdout, NewTextFormatter(), WarningLevel)
|
||||
@ -29,8 +31,7 @@ var logger = New(os.Stdout, NewTextFormatter(), WarningLevel)
|
||||
func init() {
|
||||
logger.callDepth = 4
|
||||
|
||||
// TODO add item in configuaration file
|
||||
lvl := os.Getenv("LOG_LEVEL")
|
||||
lvl := config.LogLevel()
|
||||
if len(lvl) == 0 {
|
||||
logger.SetLevel(InfoLevel)
|
||||
return
|
||||
|
@ -21,15 +21,15 @@ import (
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
token_util "github.com/vmware/harbor/src/ui/service/token"
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
|
||||
token_util "github.com/vmware/harbor/src/ui/service/token"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -234,11 +234,11 @@ func (s *standardTokenAuthorizer) generateToken(realm, service string, scopes []
|
||||
// 2. the realm field returned by registry is an IP which can not reachable
|
||||
// inside Harbor
|
||||
func tokenURL(realm string) string {
|
||||
extEndpoint := os.Getenv("EXT_ENDPOINT")
|
||||
tokenURL := os.Getenv("TOKEN_URL")
|
||||
if len(extEndpoint) != 0 && len(tokenURL) != 0 &&
|
||||
extEndpoint := config.ExtEndpoint()
|
||||
tokenEndpoint := config.TokenEndpoint()
|
||||
if len(extEndpoint) != 0 && len(tokenEndpoint) != 0 &&
|
||||
strings.Contains(realm, extEndpoint) {
|
||||
realm = strings.TrimRight(tokenURL, "/") + "/service/token"
|
||||
realm = strings.TrimRight(tokenEndpoint, "/") + "/service/token"
|
||||
}
|
||||
return realm
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import (
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
|
||||
"strconv"
|
||||
"time"
|
||||
@ -72,11 +73,19 @@ func (p *ProjectAPI) Prepare() {
|
||||
// Post ...
|
||||
func (p *ProjectAPI) Post() {
|
||||
p.userID = p.ValidateUser()
|
||||
|
||||
isSysAdmin, err := dao.IsAdminRole(p.userID)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to check admin role: %v", err)
|
||||
}
|
||||
if !isSysAdmin && config.OnlyAdminCreateProject() {
|
||||
log.Errorf("Only sys admin can create project")
|
||||
p.RenderError(http.StatusForbidden, "Only system admin can create project")
|
||||
return
|
||||
}
|
||||
var req projectReq
|
||||
p.DecodeJSONReq(&req)
|
||||
public := req.Public
|
||||
err := validateProjectReq(req)
|
||||
err = validateProjectReq(req)
|
||||
if err != nil {
|
||||
log.Errorf("Invalid project request, error: %v", err)
|
||||
p.RenderError(http.StatusBadRequest, fmt.Sprintf("invalid request: %v", err))
|
||||
|
@ -19,23 +19,23 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
"github.com/docker/distribution/manifest/schema1"
|
||||
"github.com/docker/distribution/manifest/schema2"
|
||||
"github.com/vmware/harbor/src/common/api"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
"github.com/vmware/harbor/src/ui/service/cache"
|
||||
svc_utils "github.com/vmware/harbor/src/ui/service/utils"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/api"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
|
||||
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
"github.com/vmware/harbor/src/common/utils/registry/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// RepositoryAPI handles request to /api/repositories /api/repositories/tags /api/repositories/manifests, the parm has to be put
|
||||
@ -361,7 +361,7 @@ func (ra *RepositoryAPI) GetManifests() {
|
||||
}
|
||||
|
||||
func (ra *RepositoryAPI) initRepositoryClient(repoName string) (r *registry.Repository, err error) {
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
endpoint := config.InternalRegistryURL()
|
||||
|
||||
username, password, ok := ra.Ctx.Request.BasicAuth()
|
||||
if ok {
|
||||
|
@ -20,17 +20,17 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/vmware/harbor/src/common/api"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/api"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
"github.com/vmware/harbor/src/common/utils/registry/auth"
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// TargetAPI handles request to /api/targets/ping /api/targets/{}
|
||||
@ -41,8 +41,7 @@ type TargetAPI struct {
|
||||
|
||||
// Prepare validates the user
|
||||
func (t *TargetAPI) Prepare() {
|
||||
//TODO:move to config
|
||||
t.secretKey = os.Getenv("SECRET_KEY")
|
||||
t.secretKey = config.SecretKey()
|
||||
|
||||
userID := t.ValidateUser()
|
||||
isSysAdmin, err := dao.IsAdminRole(userID)
|
||||
|
@ -18,7 +18,6 @@ package api
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
@ -27,6 +26,7 @@ import (
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// UserAPI handles request to /api/users/{}
|
||||
@ -47,16 +47,9 @@ type passwordReq struct {
|
||||
// Prepare validates the URL and parms
|
||||
func (ua *UserAPI) Prepare() {
|
||||
|
||||
authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
|
||||
if authMode == "" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
ua.AuthMode = authMode
|
||||
ua.AuthMode = config.AuthMode()
|
||||
|
||||
selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
|
||||
if selfRegistration == "on" {
|
||||
ua.SelfRegistration = true
|
||||
}
|
||||
ua.SelfRegistration = config.SelfRegistration()
|
||||
|
||||
if ua.Ctx.Input.IsPost() {
|
||||
sessionUserID := ua.GetSession("userId")
|
||||
@ -241,9 +234,7 @@ func (ua *UserAPI) Delete() {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO read from conifg
|
||||
authMode := os.Getenv("AUTH_MODE")
|
||||
if authMode == "ldap_auth" {
|
||||
if config.AuthMode() == "ldap_auth" {
|
||||
ua.CustomAbort(http.StatusForbidden, "user can not be deleted in LDAP authentication mode")
|
||||
}
|
||||
|
||||
|
@ -22,18 +22,18 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/service/cache"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/common/utils/registry"
|
||||
registry_error "github.com/vmware/harbor/src/common/utils/registry/error"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
"github.com/vmware/harbor/src/ui/service/cache"
|
||||
)
|
||||
|
||||
func checkProjectPermission(userID int, projectID int64) bool {
|
||||
@ -233,9 +233,8 @@ func postReplicationAction(policyID int64, acton string) error {
|
||||
func addAuthentication(req *http.Request) {
|
||||
if req != nil {
|
||||
req.AddCookie(&http.Cookie{
|
||||
Name: models.UISecretCookie,
|
||||
// TODO read secret from config
|
||||
Value: os.Getenv("UI_SECRET"),
|
||||
Name: models.UISecretCookie,
|
||||
Value: config.UISecret(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -351,8 +350,7 @@ func diffRepos(reposInRegistry []string, reposInDB []string) ([]string, []string
|
||||
}
|
||||
|
||||
// TODO remove the workaround when the bug of registry is fixed
|
||||
// TODO read it from config
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
endpoint := config.InternalRegistryURL()
|
||||
client, err := cache.NewRepositoryClient(endpoint, true,
|
||||
"admin", repoInR, "repository", repoInR)
|
||||
if err != nil {
|
||||
@ -374,8 +372,7 @@ func diffRepos(reposInRegistry []string, reposInDB []string) ([]string, []string
|
||||
j++
|
||||
} else {
|
||||
// TODO remove the workaround when the bug of registry is fixed
|
||||
// TODO read it from config
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
endpoint := config.InternalRegistryURL()
|
||||
client, err := cache.NewRepositoryClient(endpoint, true,
|
||||
"admin", repoInR, "repository", repoInR)
|
||||
if err != nil {
|
||||
@ -425,7 +422,7 @@ func projectExists(repository string) (bool, error) {
|
||||
}
|
||||
|
||||
func initRegistryClient() (r *registry.Registry, err error) {
|
||||
endpoint := os.Getenv("REGISTRY_URL")
|
||||
endpoint := config.InternalRegistryURL()
|
||||
|
||||
addr := endpoint
|
||||
if strings.Contains(endpoint, "/") {
|
||||
@ -462,32 +459,20 @@ func initRegistryClient() (r *registry.Registry, err error) {
|
||||
}
|
||||
|
||||
func buildReplicationURL() string {
|
||||
url := getJobServiceURL()
|
||||
url := config.InternalJobServiceURL()
|
||||
return fmt.Sprintf("%s/api/jobs/replication", url)
|
||||
}
|
||||
|
||||
func buildJobLogURL(jobID string) string {
|
||||
url := getJobServiceURL()
|
||||
url := config.InternalJobServiceURL()
|
||||
return fmt.Sprintf("%s/api/jobs/replication/%s/log", url, jobID)
|
||||
}
|
||||
|
||||
func buildReplicationActionURL() string {
|
||||
url := getJobServiceURL()
|
||||
url := config.InternalJobServiceURL()
|
||||
return fmt.Sprintf("%s/api/jobs/replication/actions", url)
|
||||
}
|
||||
|
||||
func getJobServiceURL() string {
|
||||
url := os.Getenv("JOB_SERVICE_URL")
|
||||
url = strings.TrimSpace(url)
|
||||
url = strings.TrimRight(url, "/")
|
||||
|
||||
if len(url) == 0 {
|
||||
url = "http://jobservice"
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
func getReposByProject(name string, keyword ...string) ([]string, error) {
|
||||
repositories := []string{}
|
||||
|
||||
|
@ -17,11 +17,11 @@ package auth
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// 1.5 seconds
|
||||
@ -50,7 +50,7 @@ func Register(name string, authenticator Authenticator) {
|
||||
// Login authenticates user credentials based on setting.
|
||||
func Login(m models.AuthModel) (*models.User, error) {
|
||||
|
||||
var authMode = os.Getenv("AUTH_MODE")
|
||||
var authMode = config.AuthMode()
|
||||
if authMode == "" || m.Principal == "admin" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
|
@ -18,14 +18,14 @@ package ldap
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
|
||||
"github.com/mqu/openldap"
|
||||
)
|
||||
@ -46,7 +46,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
return nil, fmt.Errorf("the principal contains meta char: %q", c)
|
||||
}
|
||||
}
|
||||
ldapURL := os.Getenv("LDAP_URL")
|
||||
ldapURL := config.LDAP().URL
|
||||
if ldapURL == "" {
|
||||
return nil, errors.New("can not get any available LDAP_URL")
|
||||
}
|
||||
@ -57,16 +57,16 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
ldap.SetOption(openldap.LDAP_OPT_PROTOCOL_VERSION, openldap.LDAP_VERSION3)
|
||||
|
||||
ldapBaseDn := os.Getenv("LDAP_BASE_DN")
|
||||
ldapBaseDn := config.LDAP().BaseDn
|
||||
if ldapBaseDn == "" {
|
||||
return nil, errors.New("can not get any available LDAP_BASE_DN")
|
||||
}
|
||||
log.Debug("baseDn:", ldapBaseDn)
|
||||
|
||||
ldapSearchDn := os.Getenv("LDAP_SEARCH_DN")
|
||||
ldapSearchDn := config.LDAP().SearchDn
|
||||
if ldapSearchDn != "" {
|
||||
log.Debug("Search DN: ", ldapSearchDn)
|
||||
ldapSearchPwd := os.Getenv("LDAP_SEARCH_PWD")
|
||||
ldapSearchPwd := config.LDAP().SearchPwd
|
||||
err = ldap.Bind(ldapSearchDn, ldapSearchPwd)
|
||||
if err != nil {
|
||||
log.Debug("Bind search dn error", err)
|
||||
@ -74,8 +74,8 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
}
|
||||
|
||||
attrName := os.Getenv("LDAP_UID")
|
||||
filter := os.Getenv("LDAP_FILTER")
|
||||
attrName := config.LDAP().UID
|
||||
filter := config.LDAP().Filter
|
||||
if filter != "" {
|
||||
filter = "(&" + filter + "(" + attrName + "=" + m.Principal + "))"
|
||||
} else {
|
||||
@ -83,7 +83,7 @@ func (l *Auth) Authenticate(m models.AuthModel) (*models.User, error) {
|
||||
}
|
||||
log.Debug("one or more filter", filter)
|
||||
|
||||
ldapScope := os.Getenv("LDAP_SCOPE")
|
||||
ldapScope := config.LDAP().Scope
|
||||
var scope int
|
||||
if ldapScope == "1" {
|
||||
scope = openldap.LDAP_SCOPE_BASE
|
||||
|
155
src/ui/config/config.go
Normal file
155
src/ui/config/config.go
Normal file
@ -0,0 +1,155 @@
|
||||
/*
|
||||
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 config provides methods to get configurations required by code in src/ui
|
||||
package config
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
commonConfig "github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
)
|
||||
|
||||
// LDAPSetting wraps the setting of an LDAP server
|
||||
type LDAPSetting struct {
|
||||
URL string
|
||||
BaseDn string
|
||||
SearchDn string
|
||||
SearchPwd string
|
||||
UID string
|
||||
Filter string
|
||||
Scope string
|
||||
}
|
||||
|
||||
type uiParser struct{}
|
||||
|
||||
// Parse parses the auth settings url settings and other configuration consumed by code under src/ui
|
||||
func (up *uiParser) Parse(raw map[string]string, config map[string]interface{}) error {
|
||||
mode := raw["AUTH_MODE"]
|
||||
if mode == "ldap_auth" {
|
||||
setting := LDAPSetting{
|
||||
URL: raw["LDAP_URL"],
|
||||
BaseDn: raw["LDAP_BASE_DN"],
|
||||
SearchDn: raw["LDAP_SEARCH_DN"],
|
||||
SearchPwd: raw["LDAP_SEARCH_PWD"],
|
||||
UID: raw["LDAP_UID"],
|
||||
Filter: raw["LDAP_FILTER"],
|
||||
Scope: raw["LDAP_SCOPE"],
|
||||
}
|
||||
config["ldap"] = setting
|
||||
}
|
||||
config["auth_mode"] = mode
|
||||
var tokenExpiration = 30 //minutes
|
||||
if len(raw["TOKEN_EXPIRATION"]) > 0 {
|
||||
i, err := strconv.Atoi(raw["TOKEN_EXPIRATION"])
|
||||
if err != nil {
|
||||
log.Warningf("failed to parse token expiration: %v, using default value %d", err, tokenExpiration)
|
||||
} else if i <= 0 {
|
||||
log.Warningf("invalid token expiration, using default value: %d minutes", tokenExpiration)
|
||||
} else {
|
||||
tokenExpiration = i
|
||||
}
|
||||
}
|
||||
config["token_exp"] = tokenExpiration
|
||||
config["admin_password"] = raw["HARBOR_ADMIN_PASSWORD"]
|
||||
config["ext_reg_url"] = raw["EXT_REG_URL"]
|
||||
config["ui_secret"] = raw["UI_SECRET"]
|
||||
config["secret_key"] = raw["SECRET_KEY"]
|
||||
config["self_registration"] = raw["SELF_REGISTRATION"] != "off"
|
||||
config["admin_create_project"] = strings.ToLower(raw["PROJECT_CREATION_RESTRICTION"]) == "adminonly"
|
||||
registryURL := raw["REGISTRY_URL"]
|
||||
registryURL = strings.TrimRight(registryURL, "/")
|
||||
config["internal_registry_url"] = registryURL
|
||||
jobserviceURL := raw["JOB_SERVICE_URL"]
|
||||
jobserviceURL = strings.TrimRight(jobserviceURL, "/")
|
||||
config["internal_jobservice_url"] = jobserviceURL
|
||||
return nil
|
||||
}
|
||||
|
||||
var uiConfig *commonConfig.Config
|
||||
|
||||
func init() {
|
||||
uiKeys := []string{"AUTH_MODE", "LDAP_URL", "LDAP_BASE_DN", "LDAP_SEARCH_DN", "LDAP_SEARCH_PWD", "LDAP_UID", "LDAP_FILTER", "LDAP_SCOPE", "TOKEN_EXPIRATION", "HARBOR_ADMIN_PASSWORD", "EXT_REG_URL", "UI_SECRET", "SECRET_KEY", "SELF_REGISTRATION", "PROJECT_CREATION_RESTRICTION", "REGISTRY_URL", "JOB_SERVICE_URL"}
|
||||
uiConfig = &commonConfig.Config{
|
||||
Config: make(map[string]interface{}),
|
||||
Loader: &commonConfig.EnvConfigLoader{Keys: uiKeys},
|
||||
Parser: &uiParser{},
|
||||
}
|
||||
if err := uiConfig.Load(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
// Reload ...
|
||||
func Reload() error {
|
||||
return uiConfig.Load()
|
||||
}
|
||||
|
||||
// AuthMode ...
|
||||
func AuthMode() string {
|
||||
return uiConfig.Config["auth_mode"].(string)
|
||||
}
|
||||
|
||||
// LDAP returns the setting of ldap server
|
||||
func LDAP() LDAPSetting {
|
||||
return uiConfig.Config["ldap"].(LDAPSetting)
|
||||
}
|
||||
|
||||
// TokenExpiration returns the token expiration time (in minute)
|
||||
func TokenExpiration() int {
|
||||
return uiConfig.Config["token_exp"].(int)
|
||||
}
|
||||
|
||||
// ExtRegistryURL returns the registry URL to exposed to external client
|
||||
func ExtRegistryURL() string {
|
||||
return uiConfig.Config["ext_reg_url"].(string)
|
||||
}
|
||||
|
||||
// UISecret returns the value of UI secret cookie, used for communication between UI and JobService
|
||||
func UISecret() string {
|
||||
return uiConfig.Config["ui_secret"].(string)
|
||||
}
|
||||
|
||||
// SecretKey returns the secret key to encrypt the password of target
|
||||
func SecretKey() string {
|
||||
return uiConfig.Config["secret_key"].(string)
|
||||
}
|
||||
|
||||
// SelfRegistration returns the enablement of self registration
|
||||
func SelfRegistration() bool {
|
||||
return uiConfig.Config["self_registration"].(bool)
|
||||
}
|
||||
|
||||
// InternalRegistryURL returns registry URL for internal communication between Harbor containers
|
||||
func InternalRegistryURL() string {
|
||||
return uiConfig.Config["internal_registry_url"].(string)
|
||||
}
|
||||
|
||||
// InternalJobServiceURL returns jobservice URL for internal communication between Harbor containers
|
||||
func InternalJobServiceURL() string {
|
||||
return uiConfig.Config["internal_jobservice_url"].(string)
|
||||
}
|
||||
|
||||
// InitialAdminPassword returns the initial password for administrator
|
||||
func InitialAdminPassword() string {
|
||||
return uiConfig.Config["admin_password"].(string)
|
||||
}
|
||||
|
||||
// OnlyAdminCreateProject returns the flag to restrict that only sys admin can create project
|
||||
func OnlyAdminCreateProject() bool {
|
||||
return uiConfig.Config["admin_create_project"].(bool)
|
||||
}
|
144
src/ui/config/config_test.go
Normal file
144
src/ui/config/config_test.go
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
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 config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
auth = "ldap_auth"
|
||||
ldap = LDAPSetting{
|
||||
"ldap://test.ldap.com",
|
||||
"ou=people",
|
||||
"dc=whatever,dc=org",
|
||||
"1234567",
|
||||
"cn",
|
||||
"uid",
|
||||
"2",
|
||||
}
|
||||
tokenExp = "3"
|
||||
tokenExpRes = 3
|
||||
adminPassword = "password"
|
||||
externalRegURL = "127.0.0.1"
|
||||
uiSecret = "ffadsdfsdf"
|
||||
secretKey = "keykey"
|
||||
selfRegistration = "off"
|
||||
projectCreationRestriction = "adminonly"
|
||||
internalRegistryURL = "http://registry:5000"
|
||||
jobServiceURL = "http://jobservice"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
|
||||
os.Setenv("AUTH_MODE", auth)
|
||||
os.Setenv("LDAP_URL", ldap.URL)
|
||||
os.Setenv("LDAP_BASE_DN", ldap.BaseDn)
|
||||
os.Setenv("LDAP_SEARCH_DN", ldap.SearchDn)
|
||||
os.Setenv("LDAP_SEARCH_PWD", ldap.SearchPwd)
|
||||
os.Setenv("LDAP_UID", ldap.UID)
|
||||
os.Setenv("LDAP_SCOPE", ldap.Scope)
|
||||
os.Setenv("LDAP_FILTER", ldap.Filter)
|
||||
os.Setenv("TOKEN_EXPIRATION", tokenExp)
|
||||
os.Setenv("HARBOR_ADMIN_PASSWORD", adminPassword)
|
||||
os.Setenv("EXT_REG_URL", externalRegURL)
|
||||
os.Setenv("UI_SECRET", uiSecret)
|
||||
os.Setenv("SECRET_KEY", secretKey)
|
||||
os.Setenv("SELF_REGISTRATION", selfRegistration)
|
||||
os.Setenv("PROJECT_CREATION_RESTRICTION", projectCreationRestriction)
|
||||
os.Setenv("REGISTRY_URL", internalRegistryURL)
|
||||
os.Setenv("JOB_SERVICE_URL", jobServiceURL)
|
||||
|
||||
err := Reload()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
rc := m.Run()
|
||||
|
||||
os.Unsetenv("AUTH_MODE")
|
||||
os.Unsetenv("LDAP_URL")
|
||||
os.Unsetenv("LDAP_BASE_DN")
|
||||
os.Unsetenv("LDAP_SEARCH_DN")
|
||||
os.Unsetenv("LDAP_SEARCH_PWD")
|
||||
os.Unsetenv("LDAP_UID")
|
||||
os.Unsetenv("LDAP_SCOPE")
|
||||
os.Unsetenv("LDAP_FILTER")
|
||||
os.Unsetenv("TOKEN_EXPIRATION")
|
||||
os.Unsetenv("HARBOR_ADMIN_PASSWORD")
|
||||
os.Unsetenv("EXT_REG_URL")
|
||||
os.Unsetenv("UI_SECRET")
|
||||
os.Unsetenv("SECRET_KEY")
|
||||
os.Unsetenv("SELF_REGISTRATION")
|
||||
os.Unsetenv("CREATE_PROJECT_RESTRICTION")
|
||||
os.Unsetenv("REGISTRY_URL")
|
||||
os.Unsetenv("JOB_SERVICE_URL")
|
||||
|
||||
os.Exit(rc)
|
||||
}
|
||||
|
||||
func TestAuth(t *testing.T) {
|
||||
if AuthMode() != auth {
|
||||
t.Errorf("Expected auth mode:%s, in fact: %s", auth, AuthMode())
|
||||
}
|
||||
if LDAP() != ldap {
|
||||
t.Errorf("Expected ldap setting: %+v, in fact: %+v", ldap, LDAP())
|
||||
}
|
||||
}
|
||||
|
||||
func TestTokenExpiration(t *testing.T) {
|
||||
if TokenExpiration() != tokenExpRes {
|
||||
t.Errorf("Expected token expiration: %d, in fact: %d", tokenExpRes, TokenExpiration())
|
||||
}
|
||||
}
|
||||
|
||||
func TestURLs(t *testing.T) {
|
||||
if InternalRegistryURL() != internalRegistryURL {
|
||||
t.Errorf("Expected internal Registry URL: %s, in fact: %s", internalRegistryURL, InternalRegistryURL())
|
||||
}
|
||||
if InternalJobServiceURL() != jobServiceURL {
|
||||
t.Errorf("Expected internal jobservice URL: %s, in fact: %s", jobServiceURL, InternalJobServiceURL())
|
||||
}
|
||||
if ExtRegistryURL() != externalRegURL {
|
||||
t.Errorf("Expected External Registry URL: %s, in fact: %s", externalRegURL, ExtRegistryURL())
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelfRegistration(t *testing.T) {
|
||||
if SelfRegistration() {
|
||||
t.Errorf("Expected Self Registration to be false")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSecrets(t *testing.T) {
|
||||
if SecretKey() != secretKey {
|
||||
t.Errorf("Expected Secrect Key :%s, in fact: %s", secretKey, SecretKey())
|
||||
}
|
||||
if UISecret() != uiSecret {
|
||||
t.Errorf("Expected UI Secret: %s, in fact: %s", uiSecret, UISecret())
|
||||
}
|
||||
}
|
||||
|
||||
func TestProjectCreationRestrict(t *testing.T) {
|
||||
if !OnlyAdminCreateProject() {
|
||||
t.Errorf("Expected OnlyAdminCreateProject to be true")
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitAdminPassword(t *testing.T) {
|
||||
if InitialAdminPassword() != adminPassword {
|
||||
t.Errorf("Expected adminPassword: %s, in fact: %s", adminPassword, InitialAdminPassword())
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/auth"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// BaseController wraps common methods such as i18n support, forward, which can be leveraged by other UI render controllers.
|
||||
@ -99,7 +100,7 @@ func (b *BaseController) Prepare() {
|
||||
b.Data["CurLang"] = curLang.Name
|
||||
b.Data["RestLangs"] = restLangs
|
||||
|
||||
authMode := strings.ToLower(os.Getenv("AUTH_MODE"))
|
||||
authMode := config.AuthMode()
|
||||
if authMode == "" {
|
||||
authMode = "db_auth"
|
||||
}
|
||||
@ -116,11 +117,9 @@ func (b *BaseController) Prepare() {
|
||||
b.UseCompressedJS = false
|
||||
}
|
||||
|
||||
selfRegistration := strings.ToLower(os.Getenv("SELF_REGISTRATION"))
|
||||
if selfRegistration == "on" {
|
||||
b.SelfRegistration = true
|
||||
}
|
||||
b.Data["SelfRegistration"] = b.SelfRegistration
|
||||
b.SelfRegistration = config.SelfRegistration()
|
||||
|
||||
b.Data["SelfRegistration"] = config.SelfRegistration()
|
||||
}
|
||||
|
||||
// Forward to setup layout and template for content for a page.
|
||||
|
@ -3,11 +3,11 @@ package controllers
|
||||
import (
|
||||
"bytes"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"text/template"
|
||||
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/vmware/harbor/src/common/config"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/common/utils"
|
||||
@ -49,7 +49,7 @@ func (cc *CommonController) SendEmail() {
|
||||
|
||||
message := new(bytes.Buffer)
|
||||
|
||||
harborURL := os.Getenv("HARBOR_URL")
|
||||
harborURL := config.ExtEndpoint()
|
||||
if harborURL == "" {
|
||||
harborURL = "localhost"
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package controllers
|
||||
|
||||
import "os"
|
||||
import (
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// RepositoryController handles request to /repository
|
||||
type RepositoryController struct {
|
||||
@ -9,6 +11,6 @@ type RepositoryController struct {
|
||||
|
||||
// Get renders repository page
|
||||
func (rc *RepositoryController) Get() {
|
||||
rc.Data["HarborRegUrl"] = os.Getenv("HARBOR_REG_URL")
|
||||
rc.Data["HarborRegUrl"] = config.ExtRegistryURL()
|
||||
rc.Forward("page_title_repository", "repository.htm")
|
||||
}
|
||||
|
@ -25,11 +25,12 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
_ "github.com/astaxie/beego/session/redis"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/api"
|
||||
_ "github.com/vmware/harbor/src/ui/auth/db"
|
||||
_ "github.com/vmware/harbor/src/ui/auth/ldap"
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/models"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -76,7 +77,7 @@ func main() {
|
||||
|
||||
dao.InitDatabase()
|
||||
|
||||
if err := updateInitPassword(adminUserID, os.Getenv("HARBOR_ADMIN_PASSWORD")); err != nil {
|
||||
if err := updateInitPassword(adminUserID, config.InitialAdminPassword()); err != nil {
|
||||
log.Error(err)
|
||||
}
|
||||
initRouters()
|
||||
|
@ -21,13 +21,12 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/harbor/src/common/dao"
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
|
||||
"github.com/docker/distribution/registry/auth/token"
|
||||
"github.com/docker/libtrust"
|
||||
@ -38,27 +37,10 @@ const (
|
||||
privateKey = "/etc/ui/private_key.pem"
|
||||
)
|
||||
|
||||
var (
|
||||
expiration = 30 //minutes
|
||||
)
|
||||
var expiration int //minutes
|
||||
|
||||
func init() {
|
||||
// TODO read it from config
|
||||
expi := os.Getenv("TOKEN_EXPIRATION")
|
||||
if len(expi) != 0 {
|
||||
i, err := strconv.Atoi(expi)
|
||||
if err != nil {
|
||||
log.Errorf("failed to parse token expiration: %v, using default value: %d minutes", err, expiration)
|
||||
return
|
||||
}
|
||||
|
||||
if i <= 0 {
|
||||
log.Warningf("invalid token expiration, using default value: %d minutes", expiration)
|
||||
return
|
||||
}
|
||||
|
||||
expiration = i
|
||||
}
|
||||
expiration = config.TokenExpiration()
|
||||
log.Infof("token expiration: %d minutes", expiration)
|
||||
}
|
||||
|
||||
@ -109,7 +91,7 @@ func FilterAccess(username string, a *token.ResourceActions) {
|
||||
repoLength := len(repoSplit)
|
||||
if repoLength > 1 { //Only check the permission when the requested image has a namespace, i.e. project
|
||||
var projectName string
|
||||
registryURL := os.Getenv("HARBOR_REG_URL")
|
||||
registryURL := config.ExtRegistryURL()
|
||||
if repoSplit[0] == registryURL {
|
||||
projectName = repoSplit[1]
|
||||
log.Infof("Detected Registry URL in Project Name. Assuming this is a notary request and setting Project Name as %s\n", projectName)
|
||||
|
@ -18,14 +18,14 @@ package utils
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/vmware/harbor/src/common/utils/log"
|
||||
"github.com/vmware/harbor/src/ui/config"
|
||||
)
|
||||
|
||||
// VerifySecret verifies the UI_SECRET cookie in a http request.
|
||||
func VerifySecret(r *http.Request) bool {
|
||||
secret := os.Getenv("UI_SECRET")
|
||||
secret := config.UISecret()
|
||||
c, err := r.Cookie("uisecret")
|
||||
if err != nil {
|
||||
log.Warningf("Failed to get secret cookie, error: %v", err)
|
||||
|
Loading…
Reference in New Issue
Block a user