mirror of
https://github.com/goharbor/harbor.git
synced 2024-12-25 18:18:04 +01:00
Add attribute admin username for authproxy
This commit adds the attribute "http_authproxy_admin_usernames", which is string that contains usernames separated by comma, when a user logs in and the username in the tokenreview status matches the setting of this attribute, the user will have administrator permission. Signed-off-by: Daniel Jiang <jiangd@vmware.com>
This commit is contained in:
parent
85c08d62a4
commit
ad8eee8623
@ -130,6 +130,7 @@ var (
|
|||||||
{Name: common.HTTPAuthProxyEndpoint, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
{Name: common.HTTPAuthProxyEndpoint, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
||||||
{Name: common.HTTPAuthProxyTokenReviewEndpoint, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
{Name: common.HTTPAuthProxyTokenReviewEndpoint, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
||||||
{Name: common.HTTPAuthProxyAdminGroups, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
{Name: common.HTTPAuthProxyAdminGroups, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
||||||
|
{Name: common.HTTPAuthProxyAdminUsernames, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
||||||
{Name: common.HTTPAuthProxyVerifyCert, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "true", ItemType: &BoolType{}},
|
{Name: common.HTTPAuthProxyVerifyCert, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "true", ItemType: &BoolType{}},
|
||||||
{Name: common.HTTPAuthProxySkipSearch, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "false", ItemType: &BoolType{}},
|
{Name: common.HTTPAuthProxySkipSearch, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "false", ItemType: &BoolType{}},
|
||||||
{Name: common.HTTPAuthProxyServerCertificate, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
{Name: common.HTTPAuthProxyServerCertificate, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}},
|
||||||
|
@ -97,6 +97,7 @@ const (
|
|||||||
HTTPAuthProxyEndpoint = "http_authproxy_endpoint"
|
HTTPAuthProxyEndpoint = "http_authproxy_endpoint"
|
||||||
HTTPAuthProxyTokenReviewEndpoint = "http_authproxy_tokenreview_endpoint"
|
HTTPAuthProxyTokenReviewEndpoint = "http_authproxy_tokenreview_endpoint"
|
||||||
HTTPAuthProxyAdminGroups = "http_authproxy_admin_groups"
|
HTTPAuthProxyAdminGroups = "http_authproxy_admin_groups"
|
||||||
|
HTTPAuthProxyAdminUsernames = "http_authproxy_admin_usernames"
|
||||||
HTTPAuthProxyVerifyCert = "http_authproxy_verify_cert"
|
HTTPAuthProxyVerifyCert = "http_authproxy_verify_cert"
|
||||||
HTTPAuthProxySkipSearch = "http_authproxy_skip_search"
|
HTTPAuthProxySkipSearch = "http_authproxy_skip_search"
|
||||||
HTTPAuthProxyServerCertificate = "http_authproxy_server_certificate"
|
HTTPAuthProxyServerCertificate = "http_authproxy_server_certificate"
|
||||||
|
@ -72,6 +72,7 @@ type HTTPAuthProxy struct {
|
|||||||
Endpoint string `json:"endpoint"`
|
Endpoint string `json:"endpoint"`
|
||||||
TokenReviewEndpoint string `json:"tokenreivew_endpoint"`
|
TokenReviewEndpoint string `json:"tokenreivew_endpoint"`
|
||||||
AdminGroups []string `json:"admin_groups"`
|
AdminGroups []string `json:"admin_groups"`
|
||||||
|
AdminUsernames []string `json:"admin_usernames"`
|
||||||
VerifyCert bool `json:"verify_cert"`
|
VerifyCert bool `json:"verify_cert"`
|
||||||
SkipSearch bool `json:"skip_search"`
|
SkipSearch bool `json:"skip_search"`
|
||||||
ServerCertificate string `json:"server_certificate"`
|
ServerCertificate string `json:"server_certificate"`
|
||||||
|
@ -116,7 +116,7 @@ func (a *Auth) tokenReview(sessionID string) (*models.User, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
u, err := authproxy.UserFromReviewStatus(reviewStatus, httpAuthProxySetting.AdminGroups)
|
u, err := authproxy.UserFromReviewStatus(reviewStatus, httpAuthProxySetting.AdminGroups, httpAuthProxySetting.AdminUsernames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -393,6 +393,7 @@ func HTTPAuthProxySetting() (*models.HTTPAuthProxy, error) {
|
|||||||
Endpoint: cfgMgr.Get(common.HTTPAuthProxyEndpoint).GetString(),
|
Endpoint: cfgMgr.Get(common.HTTPAuthProxyEndpoint).GetString(),
|
||||||
TokenReviewEndpoint: cfgMgr.Get(common.HTTPAuthProxyTokenReviewEndpoint).GetString(),
|
TokenReviewEndpoint: cfgMgr.Get(common.HTTPAuthProxyTokenReviewEndpoint).GetString(),
|
||||||
AdminGroups: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminGroups).GetString(), ","),
|
AdminGroups: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminGroups).GetString(), ","),
|
||||||
|
AdminUsernames: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminUsernames).GetString(), ","),
|
||||||
VerifyCert: cfgMgr.Get(common.HTTPAuthProxyVerifyCert).GetBool(),
|
VerifyCert: cfgMgr.Get(common.HTTPAuthProxyVerifyCert).GetBool(),
|
||||||
SkipSearch: cfgMgr.Get(common.HTTPAuthProxySkipSearch).GetBool(),
|
SkipSearch: cfgMgr.Get(common.HTTPAuthProxySkipSearch).GetBool(),
|
||||||
ServerCertificate: cfgMgr.Get(common.HTTPAuthProxyServerCertificate).GetString(),
|
ServerCertificate: cfgMgr.Get(common.HTTPAuthProxyServerCertificate).GetString(),
|
||||||
|
@ -248,6 +248,7 @@ y1bQusZMygQezfCuEzsewF+OpANFovCTUEs6s5vyoVNP8lk=
|
|||||||
assert.Equal(t, *v, models.HTTPAuthProxy{
|
assert.Equal(t, *v, models.HTTPAuthProxy{
|
||||||
Endpoint: "https://auth.proxy/suffix",
|
Endpoint: "https://auth.proxy/suffix",
|
||||||
AdminGroups: []string{"group1", "group2"},
|
AdminGroups: []string{"group1", "group2"},
|
||||||
|
AdminUsernames: []string{},
|
||||||
SkipSearch: true,
|
SkipSearch: true,
|
||||||
VerifyCert: true,
|
VerifyCert: true,
|
||||||
ServerCertificate: certificate,
|
ServerCertificate: certificate,
|
||||||
|
@ -78,14 +78,21 @@ func getTLSConfig(config *models.HTTPAuthProxy) rest.TLSClientConfig {
|
|||||||
|
|
||||||
// UserFromReviewStatus transform a review status to a user model.
|
// UserFromReviewStatus transform a review status to a user model.
|
||||||
// Group entries will be populated if needed.
|
// Group entries will be populated if needed.
|
||||||
func UserFromReviewStatus(status k8s_api_v1beta1.TokenReviewStatus, adminGroups []string) (*models.User, error) {
|
func UserFromReviewStatus(status k8s_api_v1beta1.TokenReviewStatus, adminGroups []string, adminUsernames []string) (*models.User, error) {
|
||||||
|
|
||||||
if !status.Authenticated {
|
if !status.Authenticated {
|
||||||
return nil, fmt.Errorf("failed to authenticate the token, error in status: %s", status.Error)
|
return nil, fmt.Errorf("failed to authenticate the token, error in status: %s", status.Error)
|
||||||
}
|
}
|
||||||
user := &models.User{
|
user := &models.User{
|
||||||
Username: status.User.Username,
|
Username: status.User.Username,
|
||||||
}
|
}
|
||||||
|
for _, au := range adminUsernames {
|
||||||
|
if status.User.Username == au {
|
||||||
|
log.Debugf("Username: %s in the adminusers list, assigning user admin permission", au)
|
||||||
|
user.AdminRoleInAuth = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(status.User.Groups) > 0 {
|
if len(status.User.Groups) > 0 {
|
||||||
userGroups := models.UserGroupsFromName(status.User.Groups, common.HTTPGroupType)
|
userGroups := models.UserGroupsFromName(status.User.Groups, common.HTTPGroupType)
|
||||||
groupIDList, err := group.PopulateGroup(userGroups)
|
groupIDList, err := group.PopulateGroup(userGroups)
|
||||||
@ -94,7 +101,7 @@ func UserFromReviewStatus(status k8s_api_v1beta1.TokenReviewStatus, adminGroups
|
|||||||
}
|
}
|
||||||
log.Debugf("current user's group ID list is %+v", groupIDList)
|
log.Debugf("current user's group ID list is %+v", groupIDList)
|
||||||
user.GroupIDs = groupIDList
|
user.GroupIDs = groupIDList
|
||||||
if len(adminGroups) > 0 {
|
if len(adminGroups) > 0 && !user.AdminRoleInAuth { // skip checking admin group if user already has admin role
|
||||||
agm := make(map[string]struct{})
|
agm := make(map[string]struct{})
|
||||||
for _, ag := range adminGroups {
|
for _, ag := range adminGroups {
|
||||||
agm[ag] = struct{}{}
|
agm[ag] = struct{}{}
|
||||||
@ -108,5 +115,4 @@ func UserFromReviewStatus(status k8s_api_v1beta1.TokenReviewStatus, adminGroups
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return user, nil
|
return user, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,16 +27,18 @@ func TestUserFromReviewStatus(t *testing.T) {
|
|||||||
adminInAuth bool
|
adminInAuth bool
|
||||||
}
|
}
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
input v1beta1.TokenReviewStatus
|
input v1beta1.TokenReviewStatus
|
||||||
adminGroups []string
|
adminGroups []string
|
||||||
expect result
|
adminUsernames []string
|
||||||
|
expect result
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
input: v1beta1.TokenReviewStatus{
|
input: v1beta1.TokenReviewStatus{
|
||||||
Authenticated: false,
|
Authenticated: false,
|
||||||
Error: "connection error",
|
Error: "connection error",
|
||||||
},
|
},
|
||||||
adminGroups: []string{"admin"},
|
adminGroups: []string{"admin"},
|
||||||
|
adminUsernames: []string{},
|
||||||
expect: result{
|
expect: result{
|
||||||
hasErr: true,
|
hasErr: true,
|
||||||
},
|
},
|
||||||
@ -49,7 +51,8 @@ func TestUserFromReviewStatus(t *testing.T) {
|
|||||||
UID: "u-1",
|
UID: "u-1",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
adminGroups: []string{"admin"},
|
adminGroups: []string{"admin"},
|
||||||
|
adminUsernames: []string{},
|
||||||
expect: result{
|
expect: result{
|
||||||
hasErr: false,
|
hasErr: false,
|
||||||
username: "jack",
|
username: "jack",
|
||||||
@ -66,7 +69,8 @@ func TestUserFromReviewStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Error: "",
|
Error: "",
|
||||||
},
|
},
|
||||||
adminGroups: []string{"group2", "admin"},
|
adminGroups: []string{"group2", "admin"},
|
||||||
|
adminUsernames: []string{},
|
||||||
expect: result{
|
expect: result{
|
||||||
hasErr: false,
|
hasErr: false,
|
||||||
username: "daniel",
|
username: "daniel",
|
||||||
@ -83,17 +87,18 @@ func TestUserFromReviewStatus(t *testing.T) {
|
|||||||
},
|
},
|
||||||
Error: "",
|
Error: "",
|
||||||
},
|
},
|
||||||
adminGroups: []string{},
|
adminGroups: []string{},
|
||||||
|
adminUsernames: []string{"daniel", "admin"},
|
||||||
expect: result{
|
expect: result{
|
||||||
hasErr: false,
|
hasErr: false,
|
||||||
username: "daniel",
|
username: "daniel",
|
||||||
groupLen: 2,
|
groupLen: 2,
|
||||||
adminInAuth: false,
|
adminInAuth: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
u, err := UserFromReviewStatus(c.input, c.adminGroups)
|
u, err := UserFromReviewStatus(c.input, c.adminGroups, c.adminUsernames)
|
||||||
if c.expect.hasErr == true {
|
if c.expect.hasErr == true {
|
||||||
assert.NotNil(t, err)
|
assert.NotNil(t, err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -86,7 +86,7 @@ func (a *authProxy) Generate(req *http.Request) security.Context {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
u2, err := authproxy.UserFromReviewStatus(tokenReviewStatus, httpAuthProxyConf.AdminGroups)
|
u2, err := authproxy.UserFromReviewStatus(tokenReviewStatus, httpAuthProxyConf.AdminGroups, httpAuthProxyConf.AdminUsernames)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("failed to get user information from token review status: %v", err)
|
log.Errorf("failed to get user information from token review status: %v", err)
|
||||||
return nil
|
return nil
|
||||||
|
@ -58,6 +58,7 @@ func TestAuthProxy(t *testing.T) {
|
|||||||
VerifyCert: false,
|
VerifyCert: false,
|
||||||
TokenReviewEndpoint: server.URL,
|
TokenReviewEndpoint: server.URL,
|
||||||
AdminGroups: []string{},
|
AdminGroups: []string{},
|
||||||
|
AdminUsernames: []string{},
|
||||||
})
|
})
|
||||||
|
|
||||||
// No onboard
|
// No onboard
|
||||||
|
Loading…
Reference in New Issue
Block a user