Merge pull request #13791 from reasonerjt/oidc-redirect-extra-parm

Add extra parms when forming redirect URI for OIDC
This commit is contained in:
stonezdj(Daojun Zhang) 2020-12-22 21:45:53 +08:00 committed by GitHub
commit bc0b6b43ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 75 additions and 25 deletions

View File

@ -144,6 +144,7 @@ var (
{Name: common.OIDCUserClaim, Scope: UserScope, Group: OIDCGroup, ItemType: &StringType{}}, {Name: common.OIDCUserClaim, Scope: UserScope, Group: OIDCGroup, ItemType: &StringType{}},
{Name: common.OIDCVerifyCert, Scope: UserScope, Group: OIDCGroup, DefaultValue: "true", ItemType: &BoolType{}}, {Name: common.OIDCVerifyCert, Scope: UserScope, Group: OIDCGroup, DefaultValue: "true", ItemType: &BoolType{}},
{Name: common.OIDCAutoOnboard, Scope: UserScope, Group: OIDCGroup, DefaultValue: "false", ItemType: &BoolType{}}, {Name: common.OIDCAutoOnboard, Scope: UserScope, Group: OIDCGroup, DefaultValue: "false", ItemType: &BoolType{}},
{Name: common.OIDCExtraRedirectParms, Scope: UserScope, Group: OIDCGroup, DefaultValue: "{}", ItemType: &StringToStringMapType{}},
{Name: common.WithChartMuseum, Scope: SystemScope, Group: BasicGroup, EnvKey: "WITH_CHARTMUSEUM", DefaultValue: "false", ItemType: &BoolType{}, Editable: true}, {Name: common.WithChartMuseum, Scope: SystemScope, Group: BasicGroup, EnvKey: "WITH_CHARTMUSEUM", DefaultValue: "false", ItemType: &BoolType{}, Editable: true},
{Name: common.WithTrivy, Scope: SystemScope, Group: BasicGroup, EnvKey: "WITH_TRIVY", DefaultValue: "false", ItemType: &BoolType{}, Editable: true}, {Name: common.WithTrivy, Scope: SystemScope, Group: BasicGroup, EnvKey: "WITH_TRIVY", DefaultValue: "false", ItemType: &BoolType{}, Editable: true},

View File

@ -189,6 +189,22 @@ func (t *MapType) get(str string) (interface{}, error) {
return result, err return result, err
} }
// StringToStringMapType ...
type StringToStringMapType struct {
}
func (t *StringToStringMapType) validate(str string) error {
result := map[string]string{}
err := json.Unmarshal([]byte(str), &result)
return err
}
func (t *StringToStringMapType) get(str string) (interface{}, error) {
result := map[string]string{}
err := json.Unmarshal([]byte(str), &result)
return result, err
}
// QuotaType ... // QuotaType ...
type QuotaType struct { type QuotaType struct {
Int64Type Int64Type

View File

@ -98,6 +98,18 @@ func TestMapType_get(t *testing.T) {
assert.Equal(t, map[string]interface{}{"sample": "abc", "another": "welcome"}, result) assert.Equal(t, map[string]interface{}{"sample": "abc", "another": "welcome"}, result)
} }
func TestStringToStringMapType_validate(t *testing.T) {
test := &StringToStringMapType{}
assert.Nil(t, test.validate(`{"sample":"abc", "another":"welcome"}`))
assert.NotNil(t, test.validate(`{"sample":"abc", "another":123}`))
}
func TestStringToStringMapType_get(t *testing.T) {
test := &StringToStringMapType{}
result, _ := test.get(`{"sample":"abc", "another":"welcome"}`)
assert.Equal(t, map[string]string{"sample": "abc", "another": "welcome"}, result)
}
func Test_parseInt64(t *testing.T) { func Test_parseInt64(t *testing.T) {
type args struct { type args struct {
str string str string

View File

@ -108,6 +108,7 @@ const (
OIDCAdminGroup = "oidc_admin_group" OIDCAdminGroup = "oidc_admin_group"
OIDCGroupsClaim = "oidc_groups_claim" OIDCGroupsClaim = "oidc_groups_claim"
OIDCAutoOnboard = "oidc_auto_onboard" OIDCAutoOnboard = "oidc_auto_onboard"
OIDCExtraRedirectParms = "oidc_extra_redirect_parms"
OIDCScope = "oidc_scope" OIDCScope = "oidc_scope"
OIDCUserClaim = "oidc_user_claim" OIDCUserClaim = "oidc_user_claim"

View File

@ -90,6 +90,7 @@ type OIDCSetting struct {
RedirectURL string `json:"redirect_url"` RedirectURL string `json:"redirect_url"`
Scope []string `json:"scope"` Scope []string `json:"scope"`
UserClaim string `json:"user_claim"` UserClaim string `json:"user_claim"`
ExtraRedirectParms map[string]string `json:"extra_redirect_parms"`
} }
// QuotaSetting wraps the settings for Quota // QuotaSetting wraps the settings for Quota

View File

@ -161,10 +161,16 @@ func AuthCodeURL(state string) (string, error) {
log.Errorf("Failed to get OAuth configuration, error: %v", err) log.Errorf("Failed to get OAuth configuration, error: %v", err)
return "", err return "", err
} }
if strings.HasPrefix(conf.Endpoint.AuthURL, googleEndpoint) { // make sure the refresh token will be returned var options []oauth2.AuthCodeOption
return conf.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("prompt", "consent")), nil setting := provider.setting.Load().(models.OIDCSetting)
for k, v := range setting.ExtraRedirectParms {
options = append(options, oauth2.SetAuthURLParam(k, v))
} }
return conf.AuthCodeURL(state), nil if strings.HasPrefix(conf.Endpoint.AuthURL, googleEndpoint) { // make sure the refresh token will be returned
options = append(options, oauth2.AccessTypeOffline)
options = append(options, oauth2.SetAuthURLParam("prompt", "consent"))
}
return conf.AuthCodeURL(state, options...), nil
} }
// ExchangeToken get the token from token provider via the code // ExchangeToken get the token from token provider via the code

View File

@ -90,12 +90,24 @@ func TestHelperGet(t *testing.T) {
} }
func TestAuthCodeURL(t *testing.T) { func TestAuthCodeURL(t *testing.T) {
conf := map[string]interface{}{
common.OIDCName: "test",
common.OIDCEndpoint: "https://accounts.google.com",
common.OIDCVerifyCert: "true",
common.OIDCScope: "openid, profile, offline_access",
common.OIDCCLientID: "client",
common.OIDCClientSecret: "secret",
common.ExtEndpoint: "https://harbor.test",
common.OIDCExtraRedirectParms: `{"test_key":"test_value"}`,
}
config.GetCfgManager().UpdateConfig(conf)
res, err := AuthCodeURL("random") res, err := AuthCodeURL("random")
assert.Nil(t, err) assert.Nil(t, err)
u, err := url.ParseRequestURI(res) u, err := url.ParseRequestURI(res)
assert.Nil(t, err) assert.Nil(t, err)
q, err := url.ParseQuery(u.RawQuery) q, err := url.ParseQuery(u.RawQuery)
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, "test_value", q.Get("test_key"))
assert.Equal(t, "offline", q.Get("access_type")) assert.Equal(t, "offline", q.Get("access_type"))
assert.False(t, strings.Contains(q.Get("scope"), "offline_access")) assert.False(t, strings.Contains(q.Get("scope"), "offline_access"))
} }

View File

@ -419,6 +419,7 @@ func OIDCSetting() (*models.OIDCSetting, error) {
RedirectURL: extEndpoint + common.OIDCCallbackPath, RedirectURL: extEndpoint + common.OIDCCallbackPath,
Scope: scope, Scope: scope,
UserClaim: cfgMgr.Get(common.OIDCUserClaim).GetString(), UserClaim: cfgMgr.Get(common.OIDCUserClaim).GetString(),
ExtraRedirectParms: cfgMgr.Get(common.OIDCExtraRedirectParms).GetStringToStringMap(),
}, nil }, nil
} }