From 3c39c7d2bc47ce4db70cfc2fc3fe55c04fd59d50 Mon Sep 17 00:00:00 2001 From: Daniel Jiang Date: Wed, 7 Apr 2021 14:11:39 +0800 Subject: [PATCH] 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 --- src/common/config/metadata/metadatalist.go | 1 + src/common/const.go | 1 + src/common/models/config.go | 1 + src/core/auth/authproxy/auth.go | 2 +- src/core/config/config.go | 1 + src/core/config/config_test.go | 1 + src/pkg/authproxy/http.go | 14 +++++++---- src/pkg/authproxy/http_test.go | 23 +++++++++++-------- src/server/middleware/security/auth_proxy.go | 2 +- .../middleware/security/auth_proxy_test.go | 1 + 10 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/common/config/metadata/metadatalist.go b/src/common/config/metadata/metadatalist.go index d6f32a20a..2ca9170b9 100644 --- a/src/common/config/metadata/metadatalist.go +++ b/src/common/config/metadata/metadatalist.go @@ -130,6 +130,7 @@ var ( {Name: common.HTTPAuthProxyEndpoint, 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.HTTPAuthProxyAdminUsernames, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}}, {Name: common.HTTPAuthProxyVerifyCert, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "true", ItemType: &BoolType{}}, {Name: common.HTTPAuthProxySkipSearch, Scope: UserScope, Group: HTTPAuthGroup, DefaultValue: "false", ItemType: &BoolType{}}, {Name: common.HTTPAuthProxyServerCertificate, Scope: UserScope, Group: HTTPAuthGroup, ItemType: &StringType{}}, diff --git a/src/common/const.go b/src/common/const.go index 42525dbb4..5a084fa18 100755 --- a/src/common/const.go +++ b/src/common/const.go @@ -97,6 +97,7 @@ const ( HTTPAuthProxyEndpoint = "http_authproxy_endpoint" HTTPAuthProxyTokenReviewEndpoint = "http_authproxy_tokenreview_endpoint" HTTPAuthProxyAdminGroups = "http_authproxy_admin_groups" + HTTPAuthProxyAdminUsernames = "http_authproxy_admin_usernames" HTTPAuthProxyVerifyCert = "http_authproxy_verify_cert" HTTPAuthProxySkipSearch = "http_authproxy_skip_search" HTTPAuthProxyServerCertificate = "http_authproxy_server_certificate" diff --git a/src/common/models/config.go b/src/common/models/config.go index ac8f6542a..73c268667 100644 --- a/src/common/models/config.go +++ b/src/common/models/config.go @@ -72,6 +72,7 @@ type HTTPAuthProxy struct { Endpoint string `json:"endpoint"` TokenReviewEndpoint string `json:"tokenreivew_endpoint"` AdminGroups []string `json:"admin_groups"` + AdminUsernames []string `json:"admin_usernames"` VerifyCert bool `json:"verify_cert"` SkipSearch bool `json:"skip_search"` ServerCertificate string `json:"server_certificate"` diff --git a/src/core/auth/authproxy/auth.go b/src/core/auth/authproxy/auth.go index 0ea97bf3b..ddd667f82 100644 --- a/src/core/auth/authproxy/auth.go +++ b/src/core/auth/authproxy/auth.go @@ -116,7 +116,7 @@ func (a *Auth) tokenReview(sessionID string) (*models.User, error) { if err != nil { return nil, err } - u, err := authproxy.UserFromReviewStatus(reviewStatus, httpAuthProxySetting.AdminGroups) + u, err := authproxy.UserFromReviewStatus(reviewStatus, httpAuthProxySetting.AdminGroups, httpAuthProxySetting.AdminUsernames) if err != nil { return nil, err } diff --git a/src/core/config/config.go b/src/core/config/config.go index 20b3b5817..f25f3b620 100755 --- a/src/core/config/config.go +++ b/src/core/config/config.go @@ -392,6 +392,7 @@ func HTTPAuthProxySetting() (*models.HTTPAuthProxy, error) { Endpoint: cfgMgr.Get(common.HTTPAuthProxyEndpoint).GetString(), TokenReviewEndpoint: cfgMgr.Get(common.HTTPAuthProxyTokenReviewEndpoint).GetString(), AdminGroups: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminGroups).GetString(), ","), + AdminUsernames: splitAndTrim(cfgMgr.Get(common.HTTPAuthProxyAdminUsernames).GetString(), ","), VerifyCert: cfgMgr.Get(common.HTTPAuthProxyVerifyCert).GetBool(), SkipSearch: cfgMgr.Get(common.HTTPAuthProxySkipSearch).GetBool(), ServerCertificate: cfgMgr.Get(common.HTTPAuthProxyServerCertificate).GetString(), diff --git a/src/core/config/config_test.go b/src/core/config/config_test.go index eb3faf443..db090fcb0 100644 --- a/src/core/config/config_test.go +++ b/src/core/config/config_test.go @@ -248,6 +248,7 @@ y1bQusZMygQezfCuEzsewF+OpANFovCTUEs6s5vyoVNP8lk= assert.Equal(t, *v, models.HTTPAuthProxy{ Endpoint: "https://auth.proxy/suffix", AdminGroups: []string{"group1", "group2"}, + AdminUsernames: []string{}, SkipSearch: true, VerifyCert: true, ServerCertificate: certificate, diff --git a/src/pkg/authproxy/http.go b/src/pkg/authproxy/http.go index 1dcf27725..d9e76dcd9 100644 --- a/src/pkg/authproxy/http.go +++ b/src/pkg/authproxy/http.go @@ -78,14 +78,21 @@ func getTLSConfig(config *models.HTTPAuthProxy) rest.TLSClientConfig { // UserFromReviewStatus transform a review status to a user model. // 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 { return nil, fmt.Errorf("failed to authenticate the token, error in status: %s", status.Error) } user := &models.User{ 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 { userGroups := models.UserGroupsFromName(status.User.Groups, common.HTTPGroupType) 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) 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{}) for _, ag := range adminGroups { agm[ag] = struct{}{} @@ -108,5 +115,4 @@ func UserFromReviewStatus(status k8s_api_v1beta1.TokenReviewStatus, adminGroups } } return user, nil - } diff --git a/src/pkg/authproxy/http_test.go b/src/pkg/authproxy/http_test.go index 58cb53e63..2e65366a2 100644 --- a/src/pkg/authproxy/http_test.go +++ b/src/pkg/authproxy/http_test.go @@ -27,16 +27,18 @@ func TestUserFromReviewStatus(t *testing.T) { adminInAuth bool } cases := []struct { - input v1beta1.TokenReviewStatus - adminGroups []string - expect result + input v1beta1.TokenReviewStatus + adminGroups []string + adminUsernames []string + expect result }{ { input: v1beta1.TokenReviewStatus{ Authenticated: false, Error: "connection error", }, - adminGroups: []string{"admin"}, + adminGroups: []string{"admin"}, + adminUsernames: []string{}, expect: result{ hasErr: true, }, @@ -49,7 +51,8 @@ func TestUserFromReviewStatus(t *testing.T) { UID: "u-1", }, }, - adminGroups: []string{"admin"}, + adminGroups: []string{"admin"}, + adminUsernames: []string{}, expect: result{ hasErr: false, username: "jack", @@ -66,7 +69,8 @@ func TestUserFromReviewStatus(t *testing.T) { }, Error: "", }, - adminGroups: []string{"group2", "admin"}, + adminGroups: []string{"group2", "admin"}, + adminUsernames: []string{}, expect: result{ hasErr: false, username: "daniel", @@ -83,17 +87,18 @@ func TestUserFromReviewStatus(t *testing.T) { }, Error: "", }, - adminGroups: []string{}, + adminGroups: []string{}, + adminUsernames: []string{"daniel", "admin"}, expect: result{ hasErr: false, username: "daniel", groupLen: 2, - adminInAuth: false, + adminInAuth: true, }, }, } 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 { assert.NotNil(t, err) } else { diff --git a/src/server/middleware/security/auth_proxy.go b/src/server/middleware/security/auth_proxy.go index 8decd3910..143be670b 100644 --- a/src/server/middleware/security/auth_proxy.go +++ b/src/server/middleware/security/auth_proxy.go @@ -86,7 +86,7 @@ func (a *authProxy) Generate(req *http.Request) security.Context { return nil } } - u2, err := authproxy.UserFromReviewStatus(tokenReviewStatus, httpAuthProxyConf.AdminGroups) + u2, err := authproxy.UserFromReviewStatus(tokenReviewStatus, httpAuthProxyConf.AdminGroups, httpAuthProxyConf.AdminUsernames) if err != nil { log.Errorf("failed to get user information from token review status: %v", err) return nil diff --git a/src/server/middleware/security/auth_proxy_test.go b/src/server/middleware/security/auth_proxy_test.go index 16f30c174..ac09f5919 100644 --- a/src/server/middleware/security/auth_proxy_test.go +++ b/src/server/middleware/security/auth_proxy_test.go @@ -58,6 +58,7 @@ func TestAuthProxy(t *testing.T) { VerifyCert: false, TokenReviewEndpoint: server.URL, AdminGroups: []string{}, + AdminUsernames: []string{}, }) // No onboard