Add support to ensure user belongs in required groups when using the OIDC provider

This commit is contained in:
Stefan Sedich
2020-09-21 10:43:54 -07:00
parent a87beab1a0
commit 9d59519a96
10 changed files with 281 additions and 18 deletions
+5
View File
@@ -93,6 +93,7 @@ type Options struct {
InsecureOIDCSkipIssuerVerification bool `flag:"insecure-oidc-skip-issuer-verification" cfg:"insecure_oidc_skip_issuer_verification"`
SkipOIDCDiscovery bool `flag:"skip-oidc-discovery" cfg:"skip_oidc_discovery"`
OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url"`
OIDCGroupsClaim string `flag:"oidc-groups-claim" cfg:"oidc_groups_claim"`
LoginURL string `flag:"login-url" cfg:"login_url"`
RedeemURL string `flag:"redeem-url" cfg:"redeem_url"`
ProfileURL string `flag:"profile-url" cfg:"profile_url"`
@@ -102,6 +103,7 @@ type Options struct {
Prompt string `flag:"prompt" cfg:"prompt"`
ApprovalPrompt string `flag:"approval-prompt" cfg:"approval_prompt"` // Deprecated by OIDC 1.0
UserIDClaim string `flag:"user-id-claim" cfg:"user_id_claim"`
AllowedGroups []string `flag:"allowed-group" cfg:"allowed_groups"`
SignatureKey string `flag:"signature-key" cfg:"signature_key"`
AcrValues string `flag:"acr-values" cfg:"acr_values"`
@@ -167,6 +169,7 @@ func NewOptions() *Options {
InsecureOIDCAllowUnverifiedEmail: false,
SkipOIDCDiscovery: false,
Logging: loggingDefaults(),
OIDCGroupsClaim: "groups",
}
}
@@ -248,6 +251,7 @@ func NewFlagSet() *pflag.FlagSet {
flagSet.Bool("insecure-oidc-skip-issuer-verification", false, "Do not verify if issuer matches OIDC discovery URL")
flagSet.Bool("skip-oidc-discovery", false, "Skip OIDC discovery and use manually supplied Endpoints")
flagSet.String("oidc-jwks-url", "", "OpenID Connect JWKS URL (ie: https://www.googleapis.com/oauth2/v3/certs)")
flagSet.String("oidc-groups-claim", "groups", "which claim contains the user groups")
flagSet.String("login-url", "", "Authentication endpoint")
flagSet.String("redeem-url", "", "Token redemption endpoint")
flagSet.String("profile-url", "", "Profile access endpoint")
@@ -265,6 +269,7 @@ func NewFlagSet() *pflag.FlagSet {
flagSet.Bool("gcp-healthchecks", false, "Enable GCP/GKE healthcheck endpoints")
flagSet.String("user-id-claim", "email", "which claim contains the user ID")
flagSet.StringSlice("allowed-group", []string{}, "restrict logins to members of this group (may be given multiple times)")
flagSet.AddFlagSet(cookieFlagSet())
flagSet.AddFlagSet(loggingFlagSet())
+6 -1
View File
@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"io/ioutil"
"reflect"
"time"
"unicode/utf8"
@@ -24,6 +25,7 @@ type SessionState struct {
RefreshToken string `json:",omitempty" msgpack:"rt,omitempty"`
Email string `json:",omitempty" msgpack:"e,omitempty"`
User string `json:",omitempty" msgpack:"u,omitempty"`
Groups []string `json:",omitempty" msgpack:"g,omitempty"`
PreferredUsername string `json:",omitempty" msgpack:"pu,omitempty"`
}
@@ -61,6 +63,9 @@ func (s *SessionState) String() string {
if s.RefreshToken != "" {
o += " refresh_token:true"
}
if len(s.Groups) > 0 {
o += fmt.Sprintf(" groups:%v", s.Groups)
}
return o + "}"
}
@@ -233,7 +238,7 @@ func (s *SessionState) validate() error {
}
empty := new(SessionState)
if *s == *empty {
if reflect.DeepEqual(*s, *empty) {
return errors.New("invalid empty session unmarshalled")
}
+11
View File
@@ -186,6 +186,17 @@ func TestEncodeAndDecodeSessionState(t *testing.T) {
IDToken: "IDToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
ExpiresOn: &expires,
},
"With groups": {
Email: "username@example.com",
User: "username",
PreferredUsername: "preferred.username",
AccessToken: "AccessToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
IDToken: "IDToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
CreatedAt: &created,
ExpiresOn: &expires,
RefreshToken: "RefreshToken.12349871293847fdsaihf9238h4f91h8fr.1349f831y98fd7",
Groups: []string{"group-a", "group-b"},
},
}
for _, secretSize := range []int{16, 24, 32} {
+5
View File
@@ -152,6 +152,10 @@ func Validate(o *options.Options) error {
}
if o.Scope == "" {
o.Scope = "openid email profile"
if len(o.AllowedGroups) > 0 {
o.Scope += " groups"
}
}
}
@@ -279,6 +283,7 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
case *providers.OIDCProvider:
p.AllowUnverifiedEmail = o.InsecureOIDCAllowUnverifiedEmail
p.UserIDClaim = o.UserIDClaim
p.GroupsClaim = o.OIDCGroupsClaim
if o.GetOIDCVerifier() == nil {
msgs = append(msgs, "oidc provider requires an oidc issuer URL")
} else {