mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Anon: Add support to resolve anonymous identity (#87486)
This commit is contained in:
@@ -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},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user