Merge a7937a81a7 into 110d51d1d7
This commit is contained in:
commit
f5a8d15807
|
|
@ -25,6 +25,7 @@ func CreateTokenToSessionFunc(verify VerifyFunc) TokenToSessionFunc {
|
||||||
Verified *bool `json:"email_verified"`
|
Verified *bool `json:"email_verified"`
|
||||||
PreferredUsername string `json:"preferred_username"`
|
PreferredUsername string `json:"preferred_username"`
|
||||||
Groups []string `json:"groups"`
|
Groups []string `json:"groups"`
|
||||||
|
ACR string `json:"acr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
idToken, err := verify(ctx, token)
|
idToken, err := verify(ctx, token)
|
||||||
|
|
@ -49,6 +50,7 @@ func CreateTokenToSessionFunc(verify VerifyFunc) TokenToSessionFunc {
|
||||||
User: claims.Subject,
|
User: claims.Subject,
|
||||||
Groups: claims.Groups,
|
Groups: claims.Groups,
|
||||||
PreferredUsername: claims.PreferredUsername,
|
PreferredUsername: claims.PreferredUsername,
|
||||||
|
ACR: claims.ACR,
|
||||||
AccessToken: token,
|
AccessToken: token,
|
||||||
IDToken: token,
|
IDToken: token,
|
||||||
RefreshToken: "",
|
RefreshToken: "",
|
||||||
|
|
|
||||||
|
|
@ -272,6 +272,8 @@ type OIDCOptions struct {
|
||||||
// ExtraAudiences is a list of additional audiences that are allowed
|
// ExtraAudiences is a list of additional audiences that are allowed
|
||||||
// to pass verification in addition to the client id.
|
// to pass verification in addition to the client id.
|
||||||
ExtraAudiences []string `json:"extraAudiences,omitempty"`
|
ExtraAudiences []string `json:"extraAudiences,omitempty"`
|
||||||
|
// to pass acr values to the provider
|
||||||
|
ACRs string `json:"acr,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoginGovOptions struct {
|
type LoginGovOptions struct {
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ type SessionState struct {
|
||||||
User string `msgpack:"u,omitempty"`
|
User string `msgpack:"u,omitempty"`
|
||||||
Groups []string `msgpack:"g,omitempty"`
|
Groups []string `msgpack:"g,omitempty"`
|
||||||
PreferredUsername string `msgpack:"pu,omitempty"`
|
PreferredUsername string `msgpack:"pu,omitempty"`
|
||||||
|
ACR string `msgpack:"acr,omitempty"`
|
||||||
|
|
||||||
// Internal helpers, not serialized
|
// Internal helpers, not serialized
|
||||||
Clock func() time.Time `msgpack:"-"` // override for time.Now, for testing
|
Clock func() time.Time `msgpack:"-"` // override for time.Now, for testing
|
||||||
|
|
@ -154,6 +155,8 @@ func (s *SessionState) GetClaim(claim string) []string {
|
||||||
return groups
|
return groups
|
||||||
case "preferred_username":
|
case "preferred_username":
|
||||||
return []string{s.PreferredUsername}
|
return []string{s.PreferredUsername}
|
||||||
|
case "acr":
|
||||||
|
return []string{s.ACR}
|
||||||
default:
|
default:
|
||||||
return []string{}
|
return []string{}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ func NewOIDCProvider(p *ProviderData, opts options.OIDCOptions) *OIDCProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
p.setProviderDefaults(oidcProviderDefaults)
|
p.setProviderDefaults(oidcProviderDefaults)
|
||||||
|
p.setAllowedACR(opts.ACRs)
|
||||||
p.getAuthorizationHeaderFunc = makeOIDCHeader
|
p.getAuthorizationHeaderFunc = makeOIDCHeader
|
||||||
|
|
||||||
return &OIDCProvider{
|
return &OIDCProvider{
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ import (
|
||||||
const (
|
const (
|
||||||
// This is not exported as it's not currently user configurable
|
// This is not exported as it's not currently user configurable
|
||||||
oidcUserClaim = "sub"
|
oidcUserClaim = "sub"
|
||||||
|
oidcAcrClaim = "acr"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ProviderData contains information required to configure all implementations
|
// ProviderData contains information required to configure all implementations
|
||||||
|
|
@ -55,6 +56,7 @@ type ProviderData struct {
|
||||||
// Universal Group authorization data structure
|
// Universal Group authorization data structure
|
||||||
// any provider can set to consume
|
// any provider can set to consume
|
||||||
AllowedGroups map[string]struct{}
|
AllowedGroups map[string]struct{}
|
||||||
|
AllowedACRs map[string]struct{}
|
||||||
|
|
||||||
getAuthorizationHeaderFunc func(string) http.Header
|
getAuthorizationHeaderFunc func(string) http.Header
|
||||||
loginURLParameterDefaults url.Values
|
loginURLParameterDefaults url.Values
|
||||||
|
|
@ -183,6 +185,14 @@ func (p *ProviderData) setAllowedGroups(groups []string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *ProviderData) setAllowedACR(acrs string) {
|
||||||
|
p.AllowedACRs = make(map[string]struct{})
|
||||||
|
var resultingACRs = strings.Split(acrs, ",")
|
||||||
|
for _, acr := range resultingACRs {
|
||||||
|
p.AllowedACRs[acr] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type providerDefaults struct {
|
type providerDefaults struct {
|
||||||
name string
|
name string
|
||||||
loginURL *url.URL
|
loginURL *url.URL
|
||||||
|
|
@ -260,6 +270,7 @@ func (p *ProviderData) buildSessionFromClaims(rawIDToken, accessToken string) (*
|
||||||
{p.UserClaim, &ss.User},
|
{p.UserClaim, &ss.User},
|
||||||
{p.EmailClaim, &ss.Email},
|
{p.EmailClaim, &ss.Email},
|
||||||
{p.GroupsClaim, &ss.Groups},
|
{p.GroupsClaim, &ss.Groups},
|
||||||
|
{oidcAcrClaim, &ss.ACR},
|
||||||
// TODO (@NickMeves) Deprecate for dynamic claim to session mapping
|
// TODO (@NickMeves) Deprecate for dynamic claim to session mapping
|
||||||
{"preferred_username", &ss.PreferredUsername},
|
{"preferred_username", &ss.PreferredUsername},
|
||||||
} {
|
} {
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,12 @@ func (p *ProviderData) EnrichSession(_ context.Context, _ *sessions.SessionState
|
||||||
// Authorize performs global authorization on an authenticated session.
|
// Authorize performs global authorization on an authenticated session.
|
||||||
// This is not used for fine-grained per route authorization rules.
|
// This is not used for fine-grained per route authorization rules.
|
||||||
func (p *ProviderData) Authorize(_ context.Context, s *sessions.SessionState) (bool, error) {
|
func (p *ProviderData) Authorize(_ context.Context, s *sessions.SessionState) (bool, error) {
|
||||||
|
if len(p.AllowedACRs) > 0 {
|
||||||
|
if _, ok := p.AllowedACRs[s.ACR]; !ok {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(p.AllowedGroups) == 0 {
|
if len(p.AllowedGroups) == 0 {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,8 @@ func TestProviderDataAuthorize(t *testing.T) {
|
||||||
name string
|
name string
|
||||||
allowedGroups []string
|
allowedGroups []string
|
||||||
groups []string
|
groups []string
|
||||||
|
acr string
|
||||||
|
userAcr string
|
||||||
expectedAuthZ bool
|
expectedAuthZ bool
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
|
@ -102,6 +104,23 @@ func TestProviderDataAuthorize(t *testing.T) {
|
||||||
groups: []string{"baz", "foo"},
|
groups: []string{"baz", "foo"},
|
||||||
expectedAuthZ: false,
|
expectedAuthZ: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "UserNotAllowedForACRLevel",
|
||||||
|
acr: "1",
|
||||||
|
expectedAuthZ: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "UserNotAllowedForACRLevel",
|
||||||
|
acr: "1",
|
||||||
|
userAcr: "1",
|
||||||
|
expectedAuthZ: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "UserNotAllowedForACRLevel",
|
||||||
|
acr: "2",
|
||||||
|
userAcr: "somethingElse",
|
||||||
|
expectedAuthZ: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
|
@ -110,9 +129,11 @@ func TestProviderDataAuthorize(t *testing.T) {
|
||||||
|
|
||||||
session := &sessions.SessionState{
|
session := &sessions.SessionState{
|
||||||
Groups: tc.groups,
|
Groups: tc.groups,
|
||||||
|
ACR: tc.userAcr,
|
||||||
}
|
}
|
||||||
p := &ProviderData{}
|
p := &ProviderData{}
|
||||||
p.setAllowedGroups(tc.allowedGroups)
|
p.setAllowedGroups(tc.allowedGroups)
|
||||||
|
p.setAllowedACR(tc.acr)
|
||||||
|
|
||||||
authorized, err := p.Authorize(context.Background(), session)
|
authorized, err := p.Authorize(context.Background(), session)
|
||||||
g.Expect(err).ToNot(HaveOccurred())
|
g.Expect(err).ToNot(HaveOccurred())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue