Remove email configuration (#17712)

Email related settings are deprecated
   Remove email ping API
   Fixes #17683

Signed-off-by: stonezdj <stonezdj@gmail.com>

Signed-off-by: stonezdj <stonezdj@gmail.com>
This commit is contained in:
stonezdj(Daojun Zhang) 2022-11-14 15:03:49 +08:00 committed by GitHub
parent 484abd6213
commit a47e175056
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1 additions and 348 deletions

View File

@ -20,33 +20,6 @@ security:
- basic: [] - basic: []
- {} - {}
paths: paths:
/email/ping:
post:
summary: Test connection and authentication with email server.
description: |
Test connection and authentication with email server.
parameters:
- name: settings
in: body
description: 'Email server settings, if some of the settings are not assigned, they will be read from system configuration.'
required: false
schema:
$ref: '#/definitions/EmailServerSetting'
tags:
- Products
responses:
'200':
description: Ping email server successfully.
'400':
description: Inviald email server settings.
'401':
description: User need to login first.
'403':
description: Only admin has this authority.
'415':
$ref: '#/responses/UnsupportedMediaType'
'500':
description: Unexpected internal errors.
/chartrepo/{repo}/charts/{name}/{version}/labels: /chartrepo/{repo}/charts/{name}/{version}/labels:
get: get:
summary: Return the attached labels of chart. summary: Return the attached labels of chart.

View File

@ -8477,27 +8477,6 @@ definitions:
auth_mode: auth_mode:
$ref: '#/definitions/StringConfigItem' $ref: '#/definitions/StringConfigItem'
description: The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth" description: The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth"
email_from:
$ref: '#/definitions/StringConfigItem'
description: The sender name for Email notification.
email_host:
$ref: '#/definitions/StringConfigItem'
description: The hostname of SMTP server that sends Email notification.
email_identity:
$ref: '#/definitions/StringConfigItem'
description: By default it's empty so the email_username is picked
email_insecure:
$ref: '#/definitions/BoolConfigItem'
description: Whether or not the certificate will be verified when Harbor tries to access the email server.
email_port:
$ref: '#/definitions/IntegerConfigItem'
description: The port of SMTP server
email_ssl:
$ref: '#/definitions/BoolConfigItem'
description: When it''s set to true the system will access Email server via TLS by default. If it''s set to false, it still will handle "STARTTLS" from server side.
email_username:
$ref: '#/definitions/StringConfigItem'
description: The username for authenticate against SMTP server
ldap_base_dn: ldap_base_dn:
$ref: '#/definitions/StringConfigItem' $ref: '#/definitions/StringConfigItem'
description: The Base DN for LDAP binding. description: The Base DN for LDAP binding.
@ -8660,46 +8639,6 @@ definitions:
description: The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth" description: The auth mode of current system, such as "db_auth", "ldap_auth", "oidc_auth"
x-omitempty: true x-omitempty: true
x-isnullable: true x-isnullable: true
email_from:
type: string
description: The sender name for Email notification.
x-omitempty: true
x-isnullable: true
email_host:
type: string
description: The hostname of SMTP server that sends Email notification.
x-omitempty: true
x-isnullable: true
email_identity:
type: string
description: By default it's empty so the email_username is picked
x-omitempty: true
x-isnullable: true
email_insecure:
type: boolean
description: Whether or not the certificate will be verified when Harbor tries to access the email server.
x-omitempty: true
x-isnullable: true
email_password:
type: string
description: Email password
x-omitempty: true
x-isnullable: true
email_port:
type: integer
description: The port of SMTP server
x-omitempty: true
x-isnullable: true
email_ssl:
type: boolean
description: When it''s set to true the system will access Email server via TLS by default. If it''s set to false, it still will handle "STARTTLS" from server side.
x-omitempty: true
x-isnullable: true
email_username:
type: string
description: The username for authenticate against SMTP server
x-omitempty: true
x-isnullable: true
ldap_base_dn: ldap_base_dn:
type: string type: string
description: The Base DN for LDAP binding. description: The Base DN for LDAP binding.

View File

@ -31,7 +31,6 @@ import (
var TestDBConfig = map[string]interface{}{ var TestDBConfig = map[string]interface{}{
common.LDAPBaseDN: "dc=example,dc=com", common.LDAPBaseDN: "dc=example,dc=com",
common.LDAPURL: "ldap.example.com", common.LDAPURL: "ldap.example.com",
common.EmailHost: "127.0.0.1",
} }
var TestConfigWithScanAll = map[string]interface{}{ var TestConfigWithScanAll = map[string]interface{}{
@ -42,7 +41,6 @@ var TestConfigWithScanAll = map[string]interface{}{
"postgresql_sslmode": "disable", "postgresql_sslmode": "disable",
"ldap_base_dn": "dc=example,dc=com", "ldap_base_dn": "dc=example,dc=com",
"ldap_url": "ldap.example.com", "ldap_url": "ldap.example.com",
"email_host": "127.0.0.1",
"scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`, "scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`,
} }
@ -65,7 +63,6 @@ func (c *controllerTestSuite) TestGetUserCfg() {
c.Error(err, "failed to get user config") c.Error(err, "failed to get user config")
} }
c.Equal("dc=example,dc=com", resp["ldap_base_dn"].Val) c.Equal("dc=example,dc=com", resp["ldap_base_dn"].Val)
c.Equal("127.0.0.1", resp["email_host"].Val)
c.Equal("ldap.example.com", resp["ldap_url"].Val) c.Equal("ldap.example.com", resp["ldap_url"].Val)
} }
@ -107,7 +104,6 @@ func (c *controllerTestSuite) TestGetAll() {
c.Error(err, "failed to get user config") c.Error(err, "failed to get user config")
} }
c.Equal("dc=example,dc=com", resp["ldap_base_dn"]) c.Equal("dc=example,dc=com", resp["ldap_base_dn"])
c.Equal("127.0.0.1", resp["email_host"])
c.Equal("ldap.example.com", resp["ldap_url"]) c.Equal("ldap.example.com", resp["ldap_url"])
} }

View File

@ -1,120 +0,0 @@
// Copyright 2018 Project Harbor Authors
//
// 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 (
"errors"
"net"
"strconv"
"github.com/goharbor/harbor/src/common/utils/email"
"github.com/goharbor/harbor/src/lib/config"
"github.com/goharbor/harbor/src/lib/log"
"github.com/goharbor/harbor/src/lib/orm"
)
const (
pingEmailTimeout = 60
)
// EmailAPI ...
type EmailAPI struct {
BaseController
}
// Prepare ...
func (e *EmailAPI) Prepare() {
e.BaseController.Prepare()
if !e.SecurityCtx.IsAuthenticated() {
e.SendUnAuthorizedError(errors.New("UnAuthorized"))
return
}
if !e.SecurityCtx.IsSysAdmin() {
e.SendForbiddenError(errors.New(e.SecurityCtx.GetUsername()))
return
}
}
// Ping tests connection and authentication with email server
func (e *EmailAPI) Ping() {
var host, username, password, identity string
var port int
var ssl, insecure bool
ctx := orm.Context()
body := e.Ctx.Input.CopyBody(1 << 32)
if len(body) == 0 {
cfg, err := config.Email(ctx)
if err != nil {
log.Errorf("failed to get email configurations: %v", err)
e.SendInternalServerError(err)
return
}
host = cfg.Host
port = cfg.Port
username = cfg.Username
password = cfg.Password
identity = cfg.Identity
ssl = cfg.SSL
insecure = cfg.Insecure
} else {
settings := &struct {
Host string `json:"email_host"`
Port *int `json:"email_port"`
Username string `json:"email_username"`
Password *string `json:"email_password"`
SSL bool `json:"email_ssl"`
Identity string `json:"email_identity"`
Insecure bool `json:"email_insecure"`
}{}
if err := e.DecodeJSONReq(&settings); err != nil {
e.SendBadRequestError(err)
return
}
if len(settings.Host) == 0 || settings.Port == nil {
e.SendBadRequestError(errors.New("empty host or port"))
return
}
if settings.Password == nil {
cfg, err := config.Email(ctx)
if err != nil {
log.Errorf("failed to get email configurations: %v", err)
e.SendInternalServerError(err)
return
}
settings.Password = &cfg.Password
}
host = settings.Host
port = *settings.Port
username = settings.Username
password = *settings.Password
identity = settings.Identity
ssl = settings.SSL
insecure = settings.Insecure
}
addr := net.JoinHostPort(host, strconv.Itoa(port))
if err := email.Ping(addr, identity, username,
password, pingEmailTimeout, ssl, insecure); err != nil {
log.Errorf("failed to ping email server: %v", err)
// do not return any detail information of the error, or may cause SSRF security issue #3755
e.SendBadRequestError(errors.New("failed to ping email server"))
return
}
}

View File

@ -1,76 +0,0 @@
// Copyright 2018 Project Harbor Authors
//
// 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"
)
func TestPingEmail(t *testing.T) {
fmt.Println("Testing ping email server")
assert := assert.New(t)
apiTest := newHarborAPI()
// case 1: ping email server without admin role
code, _, err := apiTest.PingEmail(*testUser, nil)
if err != nil {
t.Errorf("failed to test ping email server: %v", err)
return
}
assert.Equal(401, code, "the status code of ping email server with non-admin user should be 401")
// case 2: empty email host
settings := `{
"email_host": ""
}`
code, _, err = apiTest.PingEmail(*admin, []byte(settings))
if err != nil {
t.Errorf("failed to test ping email server: %v", err)
return
}
assert.Equal(400, code)
// case 3: secure connection with admin role
settings = `{
"email_host": "smtp.gmail.com",
"email_port": 465,
"email_identity": "",
"email_username": "wrong_username",
"email_ssl": true
}`
code, _, err = apiTest.PingEmail(*admin, []byte(settings))
if err != nil {
t.Errorf("failed to test ping email server: %v", err)
return
}
assert.Equal(400, code)
// case 4: ping email server whose settings are read from config
code, _, err = apiTest.PingEmail(*admin, nil)
if err != nil {
t.Errorf("failed to test ping email server: %v", err)
return
}
assert.Equal(400, code)
}

View File

@ -16,7 +16,6 @@
package api package api
import ( import (
"bytes"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
@ -88,8 +87,6 @@ func init() {
beego.BConfig.WebConfig.Session.SessionOn = true beego.BConfig.WebConfig.Session.SessionOn = true
beego.TestBeegoInit(apppath) beego.TestBeegoInit(apppath)
beego.Router("/api/email/ping", &EmailAPI{}, "post:Ping")
// Charts are controlled under projects // Charts are controlled under projects
chartRepositoryAPIType := &ChartRepositoryAPI{} chartRepositoryAPIType := &ChartRepositoryAPI{}
beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus") beego.Router("/api/chartrepo/health", chartRepositoryAPIType, "get:GetHealthStatus")
@ -146,11 +143,3 @@ func request(_sling *sling.Sling, acceptHeader string, authInfo ...usrInfo) (int
code, _, body, err := request0(_sling, acceptHeader, authInfo...) code, _, body, err := request0(_sling, acceptHeader, authInfo...)
return code, body, err return code, body, err
} }
func (a testapi) PingEmail(authInfo usrInfo, settings []byte) (int, string, error) {
_sling := sling.New().Base(a.basePath).Post("/api/email/ping").Body(bytes.NewReader(settings))
code, body, err := request(_sling, jsonAcceptHeader, authInfo)
return code, string(body), err
}

View File

@ -20,7 +20,7 @@ import "github.com/goharbor/harbor/src/common"
type Item struct { type Item struct {
// The Scope of this configuration item: eg: SystemScope, UserScope // The Scope of this configuration item: eg: SystemScope, UserScope
Scope string `json:"scope,omitempty"` Scope string `json:"scope,omitempty"`
// email, ldapbasic, ldapgroup, uaa settings, used to retieve configure items by group // ldapbasic, ldapgroup, uaa settings, used to retieve configure items by group
Group string `json:"group,omitempty"` Group string `json:"group,omitempty"`
// environment key to retrieves this value when initialize, for example: POSTGRESQL_HOST, only used for system settings, for user settings no EnvKey // environment key to retrieves this value when initialize, for example: POSTGRESQL_HOST, only used for system settings, for user settings no EnvKey
EnvKey string `json:"environment_key,omitempty"` EnvKey string `json:"environment_key,omitempty"`
@ -44,7 +44,6 @@ const (
// Group // Group
LdapBasicGroup = "ldapbasic" LdapBasicGroup = "ldapbasic"
LdapGroupGroup = "ldapgroup" LdapGroupGroup = "ldapgroup"
EmailGroup = "email"
UAAGroup = "uaa" UAAGroup = "uaa"
HTTPAuthGroup = "http_auth" HTTPAuthGroup = "http_auth"
OIDCGroup = "oidc" OIDCGroup = "oidc"
@ -74,15 +73,6 @@ var (
{Name: common.CoreLocalURL, Scope: SystemScope, Group: BasicGroup, EnvKey: "CORE_LOCAL_URL", DefaultValue: "http://127.0.0.1:8080", ItemType: &StringType{}, Editable: false}, {Name: common.CoreLocalURL, Scope: SystemScope, Group: BasicGroup, EnvKey: "CORE_LOCAL_URL", DefaultValue: "http://127.0.0.1:8080", ItemType: &StringType{}, Editable: false},
{Name: common.DatabaseType, Scope: SystemScope, Group: BasicGroup, EnvKey: "DATABASE_TYPE", DefaultValue: "postgresql", ItemType: &StringType{}, Editable: false}, {Name: common.DatabaseType, Scope: SystemScope, Group: BasicGroup, EnvKey: "DATABASE_TYPE", DefaultValue: "postgresql", ItemType: &StringType{}, Editable: false},
{Name: common.EmailFrom, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_FROM", DefaultValue: "admin <sample_admin@mydomain.com>", ItemType: &StringType{}, Editable: false, Description: `The sender name for Email notification.`},
{Name: common.EmailHost, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_HOST", DefaultValue: "smtp.mydomain.com", ItemType: &StringType{}, Editable: false, Description: `The hostname of SMTP server that sends Email notification.`},
{Name: common.EmailIdentity, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_IDENTITY", DefaultValue: "", ItemType: &StringType{}, Editable: false, Description: `By default it's empty so the email_username is picked`},
{Name: common.EmailInsecure, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_INSECURE", DefaultValue: "false", ItemType: &BoolType{}, Editable: false, Description: `Whether or not the certificate will be verified when Harbor tries to access the email server.`},
{Name: common.EmailPassword, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_PWD", DefaultValue: "", ItemType: &PasswordType{}, Editable: false, Description: `Email password`},
{Name: common.EmailPort, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_PORT", DefaultValue: "25", ItemType: &PortType{}, Editable: false, Description: `The port of SMTP server`},
{Name: common.EmailSSL, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_SSL", DefaultValue: "false", ItemType: &BoolType{}, Editable: false, Description: `When it''s set to true the system will access Email server via TLS by default. If it''s set to false, it still will handle "STARTTLS" from server side.`},
{Name: common.EmailUsername, Scope: UserScope, Group: EmailGroup, EnvKey: "EMAIL_USR", DefaultValue: "sample_admin@mydomain.com", ItemType: &StringType{}, Editable: false, Description: `The username for authenticate against SMTP server`},
{Name: common.ExtEndpoint, Scope: SystemScope, Group: BasicGroup, EnvKey: "EXT_ENDPOINT", DefaultValue: "https://host01.com", ItemType: &StringType{}, Editable: false}, {Name: common.ExtEndpoint, Scope: SystemScope, Group: BasicGroup, EnvKey: "EXT_ENDPOINT", DefaultValue: "https://host01.com", ItemType: &StringType{}, Editable: false},
{Name: common.JobServiceURL, Scope: SystemScope, Group: BasicGroup, EnvKey: "JOBSERVICE_URL", DefaultValue: "http://jobservice:8080", ItemType: &StringType{}, Editable: false}, {Name: common.JobServiceURL, Scope: SystemScope, Group: BasicGroup, EnvKey: "JOBSERVICE_URL", DefaultValue: "http://jobservice:8080", ItemType: &StringType{}, Editable: false},

View File

@ -18,18 +18,6 @@ import (
"github.com/beego/beego/orm" "github.com/beego/beego/orm"
) )
// Email ...
type Email struct {
Host string `json:"host"`
Port int `json:"port"`
Username string `json:"username"`
Password string `json:"password"`
SSL bool `json:"ssl"`
Identity string `json:"identity"`
From string `json:"from"`
Insecure bool `json:"insecure"`
}
// HTTPAuthProxy wraps the settings for HTTP auth proxy // HTTPAuthProxy wraps the settings for HTTP auth proxy
type HTTPAuthProxy struct { type HTTPAuthProxy struct {
Endpoint string `json:"endpoint"` Endpoint string `json:"endpoint"`

View File

@ -132,10 +132,6 @@ func TestConfig(t *testing.T) {
t.Fatalf("failed to get onldy admin create project: %v", err) t.Fatalf("failed to get onldy admin create project: %v", err)
} }
if _, err := Email(ctx); err != nil {
t.Fatalf("failed to get email settings: %v", err)
}
if _, err := Database(); err != nil { if _, err := Database(); err != nil {
t.Fatalf("failed to get database: %v", err) t.Fatalf("failed to get database: %v", err)
} }

View File

@ -108,25 +108,6 @@ func OnlyAdminCreateProject(ctx context.Context) (bool, error) {
return DefaultMgr().Get(ctx, common.ProjectCreationRestriction).GetString() == common.ProCrtRestrAdmOnly, nil return DefaultMgr().Get(ctx, common.ProjectCreationRestriction).GetString() == common.ProCrtRestrAdmOnly, nil
} }
// Email returns email server settings
func Email(ctx context.Context) (*cfgModels.Email, error) {
mgr := DefaultMgr()
err := mgr.Load(ctx)
if err != nil {
return nil, err
}
return &cfgModels.Email{
Host: mgr.Get(ctx, common.EmailHost).GetString(),
Port: mgr.Get(ctx, common.EmailPort).GetInt(),
Username: mgr.Get(ctx, common.EmailUsername).GetString(),
Password: mgr.Get(ctx, common.EmailPassword).GetString(),
SSL: mgr.Get(ctx, common.EmailSSL).GetBool(),
From: mgr.Get(ctx, common.EmailFrom).GetString(),
Identity: mgr.Get(ctx, common.EmailIdentity).GetString(),
Insecure: mgr.Get(ctx, common.EmailInsecure).GetBool(),
}, nil
}
// UAASettings returns the UAASettings to access UAA service. // UAASettings returns the UAASettings to access UAA service.
func UAASettings(ctx context.Context) (*models.UAASettings, error) { func UAASettings(ctx context.Context) (*models.UAASettings, error) {
mgr := DefaultMgr() mgr := DefaultMgr()

View File

@ -36,7 +36,6 @@ var TestDBConfig = map[string]interface{}{
"postgresql_password": "root123", "postgresql_password": "root123",
"postgresql_username": "postgres", "postgresql_username": "postgres",
"postgresql_sslmode": "disable", "postgresql_sslmode": "disable",
"email_host": "127.0.0.1",
"scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`, "scan_all_policy": `{"parameter":{"daily_time":0},"type":"daily"}`,
} }
@ -54,7 +53,6 @@ func TestMain(m *testing.M) {
func TestLoadFromDatabase(t *testing.T) { func TestLoadFromDatabase(t *testing.T) {
configManager.UpdateConfig(testCtx, TestDBConfig) configManager.UpdateConfig(testCtx, TestDBConfig)
configManager.Load(testCtx) configManager.Load(testCtx)
assert.Equal(t, "127.0.0.1", configManager.Get(testCtx, "email_host").GetString())
assert.Equal(t, `{"parameter":{"daily_time":0},"type":"daily"}`, configManager.Get(testCtx, "scan_all_policy").GetString()) assert.Equal(t, `{"parameter":{"daily_time":0},"type":"daily"}`, configManager.Get(testCtx, "scan_all_policy").GetString())
} }

View File

@ -24,7 +24,6 @@ import (
// RegisterRoutes for Harbor legacy APIs // RegisterRoutes for Harbor legacy APIs
func registerLegacyRoutes() { func registerLegacyRoutes() {
version := APIVersion version := APIVersion
beego.Router("/api/"+version+"/email/ping", &api.EmailAPI{}, "post:Ping")
// APIs for chart repository // APIs for chart repository
if config.WithChartMuseum() { if config.WithChartMuseum() {