Anon: Add support to resolve anonymous identity (#87486)

This commit is contained in:
Karl Persson
2024-05-13 11:06:14 +02:00
committed by GitHub
parent 1983043b71
commit 7125a2e455
2 changed files with 107 additions and 9 deletions

View File

@@ -9,12 +9,20 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/anonymous/anonimpl/anonstore"
"github.com/grafana/grafana/pkg/services/auth/identity"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/util/errutil"
)
var (
errInvalidOrg = errutil.Unauthorized("anonymous.invalid-org")
errInvalidID = errutil.Unauthorized("anonymous.invalid-id")
)
var _ authn.ContextAwareClient = new(Anonymous)
var _ authn.IdentityResolverClient = new(Anonymous)
type Anonymous struct {
cfg *setting.Cfg
@@ -49,13 +57,7 @@ func (a *Anonymous) Authenticate(ctx context.Context, r *authn.Request) (*authn.
a.log.Warn("Failed to tag anonymous session", "error", err)
}
return &authn.Identity{
ID: authn.AnonymousNamespaceID,
OrgID: o.ID,
OrgName: o.Name,
OrgRoles: map[int64]org.RoleType{o.ID: org.RoleType(a.cfg.AnonymousOrgRole)},
ClientParams: authn.ClientParams{SyncPermissions: true},
}, nil
return a.newAnonymousIdentity(o), nil
}
func (a *Anonymous) IsEnabled() bool {
@@ -67,8 +69,26 @@ func (a *Anonymous) Test(ctx context.Context, r *authn.Request) bool {
return true
}
func (a *Anonymous) Priority() uint {
return 100
func (a *Anonymous) Namespace() string {
return authn.NamespaceAnonymous.String()
}
func (a *Anonymous) ResolveIdentity(ctx context.Context, orgID int64, namespaceID identity.NamespaceID) (*authn.Identity, error) {
o, err := a.orgService.GetByName(ctx, &org.GetOrgByNameQuery{Name: a.cfg.AnonymousOrgName})
if err != nil {
return nil, err
}
if o.ID != orgID {
return nil, errInvalidOrg.Errorf("anonymous user cannot authenticate in org %d", o.ID)
}
// Anonymous identities should always have the same namespace id.
if namespaceID != authn.AnonymousNamespaceID {
return nil, errInvalidID
}
return a.newAnonymousIdentity(o), nil
}
func (a *Anonymous) UsageStatFn(ctx context.Context) (map[string]any, error) {
@@ -82,3 +102,17 @@ func (a *Anonymous) UsageStatFn(ctx context.Context) (map[string]any, error) {
return m, nil
}
func (a *Anonymous) Priority() uint {
return 100
}
func (a *Anonymous) newAnonymousIdentity(o *org.Org) *authn.Identity {
return &authn.Identity{
ID: authn.AnonymousNamespaceID,
OrgID: o.ID,
OrgName: o.Name,
OrgRoles: map[int64]org.RoleType{o.ID: org.RoleType(a.cfg.AnonymousOrgRole)},
ClientParams: authn.ClientParams{SyncPermissions: true},
}
}

View File

@@ -67,3 +67,67 @@ func TestAnonymous_Authenticate(t *testing.T) {
})
}
}
func TestAnonymous_ResolveIdentity(t *testing.T) {
type TestCase struct {
desc string
cfg *setting.Cfg
orgID int64
namespaceID authn.NamespaceID
org *org.Org
orgErr error
expectedErr error
}
tests := []TestCase{
{
desc: "should return error when org id is not the configured one",
org: &org.Org{ID: 2, Name: "some org"},
cfg: &setting.Cfg{
AnonymousOrgName: "some org",
},
orgID: 1,
namespaceID: authn.AnonymousNamespaceID,
expectedErr: errInvalidOrg,
},
{
desc: "should return error when namespace id does not match anonymous namespace id",
org: &org.Org{ID: 1, Name: "some org"},
cfg: &setting.Cfg{
AnonymousOrgName: "some org",
},
orgID: 1,
namespaceID: authn.MustParseNamespaceID("anonymous:1"),
expectedErr: errInvalidID,
},
{
desc: "should resolve identity",
org: &org.Org{ID: 1, Name: "some org"},
cfg: &setting.Cfg{
AnonymousOrgName: "some org",
},
orgID: 1,
namespaceID: authn.AnonymousNamespaceID,
},
}
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
c := Anonymous{
cfg: tt.cfg,
log: log.NewNopLogger(),
orgService: &orgtest.FakeOrgService{ExpectedOrg: tt.org, ExpectedError: tt.orgErr},
anonDeviceService: anontest.NewFakeService(),
}
identity, err := c.ResolveIdentity(context.Background(), tt.orgID, tt.namespaceID)
if tt.expectedErr != nil {
assert.ErrorIs(t, err, tt.expectedErr)
assert.Nil(t, identity)
} else {
assert.NoError(t, err)
assert.EqualValues(t, c.newAnonymousIdentity(tt.org), identity)
}
})
}
}