Authn: Anon session service (#63052)

* add anon sessions package

* add usage stat fn

* implement count for cache

* add anonservice to authn broker

* lint

* add tests for remote cache count

* move anon service to services

* wrap tagging in goroutine

* make func used
pull/63521/head
Jo 2 years ago committed by GitHub
parent 56c8661929
commit ff78103a24
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 7
      .github/CODEOWNERS
  2. 6
      pkg/api/common_test.go
  3. 16
      pkg/infra/remotecache/database_storage.go
  4. 41
      pkg/infra/remotecache/database_storage_test.go
  5. 6
      pkg/infra/remotecache/memcached_storage.go
  6. 1
      pkg/infra/remotecache/memcached_storage_integration_test.go
  7. 9
      pkg/infra/remotecache/redis_storage.go
  8. 1
      pkg/infra/remotecache/redis_storage_integration_test.go
  9. 13
      pkg/infra/remotecache/remotecache.go
  10. 32
      pkg/infra/remotecache/remotecache_test.go
  11. 3
      pkg/middleware/middleware_test.go
  12. 1
      pkg/server/wire.go
  13. 4
      pkg/server/wireexts_oss.go
  14. 91
      pkg/services/anonymous/anonimpl/impl.go
  15. 13
      pkg/services/anonymous/anontest/fake.go
  16. 10
      pkg/services/anonymous/service.go
  17. 6
      pkg/services/authn/authnimpl/service.go
  18. 29
      pkg/services/authn/clients/anonymous.go
  19. 8
      pkg/services/authn/clients/anonymous_test.go
  20. 4
      pkg/services/contexthandler/auth_proxy_test.go
  21. 84
      pkg/services/contexthandler/contexthandler.go

@ -518,17 +518,18 @@ lerna.json @grafana/frontend-ops
# Grafana authentication and authorization
/pkg/login/ @grafana/grafana-authnz-team
/pkg/services/accesscontrol/ @grafana/grafana-authnz-team
/pkg/services/anonymous/ @grafana/grafana-authnz-team
/pkg/services/auth/ @grafana/grafana-authnz-team
/pkg/services/authn/ @grafana/grafana-authnz-team
/pkg/services/dashboards/accesscontrol.go @grafana/grafana-authnz-team
/pkg/services/datasources/permissions/ @grafana/grafana-authnz-team
/pkg/services/guardian/ @grafana/grafana-authnz-team
/pkg/services/ldap/ @grafana/grafana-authnz-team
/pkg/services/login/ @grafana/grafana-authnz-team
/pkg/services/loginattempt/ @grafana/grafana-authnz-team
/pkg/services/oauthtoken/ @grafana/grafana-authnz-team
/pkg/services/teamguardian/ @grafana/grafana-authnz-team
/pkg/services/serviceaccounts/ @grafana/grafana-authnz-team
/pkg/services/loginattempt/ @grafana/grafana-authnz-team
/pkg/services/authn/ @grafana/grafana-authnz-team
/pkg/services/teamguardian/ @grafana/grafana-authnz-team
# Support bundles
/public/app/features/support-bundles/ @grafana/grafana-authnz-team

@ -24,6 +24,7 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
"github.com/grafana/grafana/pkg/services/auth/authtest"
"github.com/grafana/grafana/pkg/services/auth/jwt"
"github.com/grafana/grafana/pkg/services/authn/authntest"
@ -205,7 +206,10 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg) *contexthandler.ContextHa
authProxy := authproxy.ProvideAuthProxy(cfg, remoteCacheSvc, loginservice.LoginServiceMock{}, &usertest.FakeUserService{}, sqlStore, service.NewLDAPFakeService())
loginService := &logintest.LoginServiceFake{}
authenticator := &logintest.AuthenticatorFake{}
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, nil, authenticator, usertest.NewUserServiceFake(), orgtest.NewOrgServiceFake(), nil, featuremgmt.WithFeatures(), &authntest.FakeService{})
ctxHdlr := contexthandler.ProvideService(cfg, userAuthTokenSvc, authJWTSvc,
remoteCacheSvc, renderSvc, sqlStore, tracer, authProxy, loginService, nil,
authenticator, usertest.NewUserServiceFake(), orgtest.NewOrgServiceFake(),
nil, featuremgmt.WithFeatures(), &authntest.FakeService{}, &anontest.FakeAnonymousSessionService{})
return ctxHdlr
}

@ -148,6 +148,22 @@ func (dc *databaseCache) Delete(ctx context.Context, key string) error {
})
}
func (dc *databaseCache) Count(ctx context.Context, prefix string) (int64, error) {
res := int64(0)
err := dc.SQLStore.WithDbSession(ctx, func(session *db.Session) error {
sql := "SELECT COUNT(*) FROM cache_data WHERE cache_key LIKE ?"
_, err := session.SQL(sql, prefix+"%").Get(&res)
if err != nil {
return err
}
return nil
})
return res, err
}
// CacheData is the struct representing the table in the database
type CacheData struct {
CacheKey string

@ -6,6 +6,7 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/log"
@ -77,3 +78,43 @@ func TestSecondSet(t *testing.T) {
err = db.Set(context.Background(), "killa-gorilla", obj, 0)
assert.Equal(t, err, nil)
}
func TestDatabaseStorageCount(t *testing.T) {
sqlstore := db.InitTestDB(t)
db := &databaseCache{
SQLStore: sqlstore,
codec: &gobCodec{},
log: log.New("remotecache.database"),
}
obj := &CacheableStruct{String: "foolbar"}
// set time.now to 2 weeks ago
var err error
getTime = func() time.Time { return time.Now().AddDate(0, 0, -2) }
err = db.Set(context.Background(), "pref-key1", obj, 1000*time.Second)
require.NoError(t, err)
err = db.Set(context.Background(), "pref-key2", obj, 1000*time.Second)
require.NoError(t, err)
err = db.Set(context.Background(), "pref-key3", obj, 1000*time.Second)
require.NoError(t, err)
// insert object that should never expire
err = db.Set(context.Background(), "pref-key4", obj, 0)
require.NoError(t, err)
getTime = time.Now
err = db.Set(context.Background(), "pref-key5", obj, 1000*time.Second)
require.NoError(t, err)
// run GC
db.internalRunGC()
// try to read values
n, errC := db.Count(context.Background(), "pref-")
require.NoError(t, errC)
assert.Equal(t, int64(2), n)
}

@ -12,6 +12,8 @@ import (
const memcachedCacheType = "memcached"
var ErrNotImplemented = errors.New("count not implemented")
type memcachedStorage struct {
c *memcache.Client
codec codec
@ -84,6 +86,10 @@ func (s *memcachedStorage) GetByteArray(ctx context.Context, key string) ([]byte
return memcachedItem.Value, nil
}
func (s *memcachedStorage) Count(ctx context.Context, prefix string) (int64, error) {
return 0, ErrNotImplemented
}
// Delete delete a key from the cache
func (s *memcachedStorage) Delete(ctx context.Context, key string) error {
return s.c.Delete(key)

@ -13,4 +13,5 @@ func TestMemcachedCacheStorage(t *testing.T) {
opts := &setting.RemoteCacheOptions{Name: memcachedCacheType, ConnStr: "localhost:11211"}
client := createTestClient(t, opts, nil)
runTestsForClient(t, client)
runCountTestsForClient(t, opts, nil)
}

@ -134,3 +134,12 @@ func (s *redisStorage) Delete(ctx context.Context, key string) error {
cmd := s.c.Del(ctx, key)
return cmd.Err()
}
func (s *redisStorage) Count(ctx context.Context, prefix string) (int64, error) {
cmd := s.c.Keys(ctx, prefix+"*")
if cmd.Err() != nil {
return 0, cmd.Err()
}
return int64(len(cmd.Val())), nil
}

@ -14,4 +14,5 @@ func TestRedisCacheStorage(t *testing.T) {
opts := &setting.RemoteCacheOptions{Name: redisCacheType, ConnStr: "addr=localhost:6379"}
client := createTestClient(t, opts, nil)
runTestsForClient(t, client)
runCountTestsForClient(t, opts, nil)
}

@ -69,6 +69,10 @@ type CacheStorage interface {
// Delete object from cache
Delete(ctx context.Context, key string) error
// Count returns the number of items in the cache.
// Optionaly a prefix can be provided to only count items with that prefix
Count(ctx context.Context, prefix string) (int64, error)
}
// RemoteCache allows Grafana to cache data outside its own process
@ -108,6 +112,11 @@ func (ds *RemoteCache) Delete(ctx context.Context, key string) error {
return ds.client.Delete(ctx, key)
}
// Count returns the number of items in the cache.
func (ds *RemoteCache) Count(ctx context.Context, prefix string) (int64, error) {
return ds.client.Count(ctx, prefix)
}
// Run starts the backend processes for cache clients.
func (ds *RemoteCache) Run(ctx context.Context) error {
// create new interface if more clients need GC jobs
@ -214,3 +223,7 @@ func (pcs *prefixCacheStorage) SetByteArray(ctx context.Context, key string, val
func (pcs *prefixCacheStorage) Delete(ctx context.Context, key string) error {
return pcs.cache.Delete(ctx, pcs.prefix+key)
}
func (pcs *prefixCacheStorage) Count(ctx context.Context, prefix string) (int64, error) {
return pcs.cache.Count(ctx, pcs.prefix)
}

@ -44,6 +44,7 @@ func TestCachedBasedOnConfig(t *testing.T) {
client := createTestClient(t, cfg.RemoteCacheOptions, db.InitTestDB(t))
runTestsForClient(t, client)
runCountTestsForClient(t, cfg.RemoteCacheOptions, db.InitTestDB(t))
}
func TestInvalidCacheTypeReturnsError(t *testing.T) {
@ -56,6 +57,37 @@ func runTestsForClient(t *testing.T, client CacheStorage) {
canNotFetchExpiredItems(t, client)
}
func runCountTestsForClient(t *testing.T, opts *setting.RemoteCacheOptions, sqlstore db.DB) {
client := createTestClient(t, opts, sqlstore)
expectError := false
if opts.Name == memcachedCacheType {
expectError = true
}
t.Run("can count items", func(t *testing.T) {
cacheableStruct := CacheableStruct{String: "hej", Int64: 2000}
err := client.Set(context.Background(), "pref-key1", cacheableStruct, 0)
require.NoError(t, err)
err = client.Set(context.Background(), "pref-key2", cacheableStruct, 0)
require.NoError(t, err)
err = client.Set(context.Background(), "key3-not-pref", cacheableStruct, 0)
require.NoError(t, err)
n, errC := client.Count(context.Background(), "pref-")
if expectError {
require.ErrorIs(t, ErrNotImplemented, errC)
assert.Equal(t, int64(0), n)
return
}
require.NoError(t, errC)
assert.Equal(t, int64(2), n)
})
}
func canPutGetAndDeleteCachedObjects(t *testing.T, client CacheStorage) {
cacheableStruct := CacheableStruct{String: "hej", Int64: 2000}

@ -25,6 +25,7 @@ import (
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/apikey/apikeytest"
"github.com/grafana/grafana/pkg/services/auth"
@ -959,7 +960,7 @@ func getContextHandler(t *testing.T, cfg *setting.Cfg, mockSQLStore *dbtest.Fake
loginService, apiKeyService, authenticator, userService, orgService,
oauthTokenService,
featuremgmt.WithFeatures(featuremgmt.FlagAccessTokenExpirationCheck),
&authntest.FakeService{})
&authntest.FakeService{}, &anontest.FakeAnonymousSessionService{})
}
type fakeRenderService struct {

@ -218,6 +218,7 @@ var wireBasicSet = wire.NewSet(
wire.Bind(new(correlations.Service), new(*correlations.CorrelationsService)),
quotaimpl.ProvideService,
remotecache.ProvideService,
wire.Bind(new(remotecache.CacheStorage), new(*remotecache.RemoteCache)),
loginservice.ProvideService,
wire.Bind(new(login.Service), new(*loginservice.Implementation)),
authinfoservice.ProvideAuthInfoService,

@ -13,6 +13,8 @@ import (
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
"github.com/grafana/grafana/pkg/services/accesscontrol/ossaccesscontrol"
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/anonymous/anonimpl"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/auth/authimpl"
"github.com/grafana/grafana/pkg/services/datasources"
@ -43,6 +45,8 @@ var wireExtsBasicSet = wire.NewSet(
authimpl.ProvideUserAuthTokenService,
wire.Bind(new(auth.UserTokenService), new(*authimpl.UserAuthTokenService)),
wire.Bind(new(auth.UserTokenBackgroundService), new(*authimpl.UserAuthTokenService)),
anonimpl.ProvideAnonymousSessionService,
wire.Bind(new(anonymous.Service), new(*anonimpl.AnonSessionService)),
licensing.ProvideService,
wire.Bind(new(licensing.Licensing), new(*licensing.OSSLicensingService)),
setting.ProvideProvider,

@ -0,0 +1,91 @@
package anonimpl
import (
"context"
"encoding/hex"
"fmt"
"hash/fnv"
"net/http"
"strings"
"time"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/network"
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/web"
)
const thirtyDays = 30 * 24 * time.Hour
const anonCachePrefix = "anon-session"
type AnonSession struct {
ip string
userAgent string
}
func (a *AnonSession) Key() (string, error) {
key := strings.Builder{}
key.WriteString(a.ip)
key.WriteString(a.userAgent)
hash := fnv.New128a()
if _, err := hash.Write([]byte(key.String())); err != nil {
return "", fmt.Errorf("failed to write to hash: %w", err)
}
return strings.Join([]string{anonCachePrefix, hex.EncodeToString(hash.Sum(nil))}, ":"), nil
}
type AnonSessionService struct {
remoteCache remotecache.CacheStorage
log log.Logger
}
func ProvideAnonymousSessionService(remoteCache remotecache.CacheStorage, usageStats usagestats.Service) *AnonSessionService {
a := &AnonSessionService{
remoteCache: remoteCache,
log: log.New("anonymous-session-service"),
}
usageStats.RegisterMetricsFunc(a.UsageStatFn)
return a
}
func (a *AnonSessionService) UsageStatFn(ctx context.Context) (map[string]interface{}, error) {
sessionCount, err := a.remoteCache.Count(ctx, anonCachePrefix)
if err != nil {
return nil, nil
}
return map[string]interface{}{
"stats.anonymous.session.count": sessionCount,
}, nil
}
func (a *AnonSessionService) TagSession(ctx context.Context, httpReq *http.Request) error {
addr := web.RemoteAddr(httpReq)
ip, err := network.GetIPFromAddress(addr)
if err != nil {
a.log.Debug("failed to parse ip from address", "addr", addr)
return nil
}
clientIPStr := ip.String()
if len(ip) == 0 {
clientIPStr = ""
}
anonSession := &AnonSession{
ip: clientIPStr,
userAgent: httpReq.UserAgent(),
}
key, err := anonSession.Key()
if err != nil {
return err
}
return a.remoteCache.Set(ctx, key, key, thirtyDays)
}

@ -0,0 +1,13 @@
package anontest
import (
"context"
"net/http"
)
type FakeAnonymousSessionService struct {
}
func (f *FakeAnonymousSessionService) TagSession(ctx context.Context, httpReq *http.Request) error {
return nil
}

@ -0,0 +1,10 @@
package anonymous
import (
"context"
"net/http"
)
type Service interface {
TagSession(context.Context, *http.Request) error
}

@ -8,7 +8,6 @@ import (
"github.com/hashicorp/go-multierror"
"go.opentelemetry.io/otel/attribute"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/network"
"github.com/grafana/grafana/pkg/infra/remotecache"
@ -16,6 +15,7 @@ import (
"github.com/grafana/grafana/pkg/infra/usagestats"
"github.com/grafana/grafana/pkg/login/social"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/authn"
@ -54,7 +54,7 @@ func ProvideService(
apikeyService apikey.Service, userService user.Service,
jwtService auth.JWTVerifierService,
usageStats usagestats.Service,
kvstore kvstore.KVStore,
anonSessionService anonymous.Service,
userProtectionService login.UserProtectionService,
loginAttempts loginattempt.Service, quotaService quota.Service,
authInfoService login.AuthInfoService, renderService rendering.Service,
@ -83,7 +83,7 @@ func ProvideService(
}
if s.cfg.AnonymousEnabled {
s.RegisterClient(clients.ProvideAnonymous(cfg, orgService, kvstore))
s.RegisterClient(clients.ProvideAnonymous(cfg, orgService, anonSessionService))
}
var proxyClients []authn.ProxyClient

@ -4,8 +4,8 @@ import (
"context"
"strings"
"github.com/grafana/grafana/pkg/infra/kvstore"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/setting"
@ -13,18 +13,20 @@ import (
var _ authn.ContextAwareClient = new(Anonymous)
func ProvideAnonymous(cfg *setting.Cfg, orgService org.Service, _ kvstore.KVStore) *Anonymous {
func ProvideAnonymous(cfg *setting.Cfg, orgService org.Service, anonSessionService anonymous.Service) *Anonymous {
return &Anonymous{
cfg: cfg,
log: log.New("authn.anonymous"),
orgService: orgService,
cfg: cfg,
log: log.New("authn.anonymous"),
orgService: orgService,
anonSessionService: anonSessionService,
}
}
type Anonymous struct {
cfg *setting.Cfg
log log.Logger
orgService org.Service
cfg *setting.Cfg
log log.Logger
orgService org.Service
anonSessionService anonymous.Service
}
func (a *Anonymous) Name() string {
@ -38,6 +40,17 @@ func (a *Anonymous) Authenticate(ctx context.Context, r *authn.Request) (*authn.
return nil, err
}
go func() {
defer func() {
if err := recover(); err != nil {
a.log.Warn("tag anon session panic", "err", err)
}
}()
if err := a.anonSessionService.TagSession(ctx, r.HTTPRequest); err != nil {
a.log.Warn("Failed to tag anonymous session", "error", err)
}
}()
return &authn.Identity{
IsAnonymous: true,
OrgID: o.ID,

@ -9,6 +9,7 @@ import (
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
"github.com/grafana/grafana/pkg/services/authn"
"github.com/grafana/grafana/pkg/services/org"
"github.com/grafana/grafana/pkg/services/org/orgtest"
@ -45,9 +46,10 @@ func TestAnonymous_Authenticate(t *testing.T) {
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.err},
cfg: tt.cfg,
log: log.NewNopLogger(),
orgService: &orgtest.FakeOrgService{ExpectedOrg: tt.org, ExpectedError: tt.err},
anonSessionService: &anontest.FakeAnonymousSessionService{},
}
identity, err := c.Authenticate(context.Background(), &authn.Request{})

@ -13,6 +13,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/infra/remotecache"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/anonymous/anontest"
"github.com/grafana/grafana/pkg/services/auth/authtest"
"github.com/grafana/grafana/pkg/services/auth/jwt"
"github.com/grafana/grafana/pkg/services/authn/authntest"
@ -116,7 +117,8 @@ func getContextHandler(t *testing.T) *ContextHandler {
return ProvideService(cfg, userAuthTokenSvc, authJWTSvc, remoteCacheSvc,
renderSvc, sqlStore, tracer, authProxy, loginService, nil, authenticator,
&userService, orgService, nil, featuremgmt.WithFeatures(), &authntest.FakeService{})
&userService, orgService, nil, featuremgmt.WithFeatures(),
&authntest.FakeService{}, &anontest.FakeAnonymousSessionService{})
}
type fakeAuthenticator struct{}

@ -22,6 +22,7 @@ import (
"github.com/grafana/grafana/pkg/infra/tracing"
loginpkg "github.com/grafana/grafana/pkg/login"
"github.com/grafana/grafana/pkg/middleware/cookies"
"github.com/grafana/grafana/pkg/services/anonymous"
"github.com/grafana/grafana/pkg/services/apikey"
"github.com/grafana/grafana/pkg/services/auth"
"github.com/grafana/grafana/pkg/services/auth/jwt"
@ -53,48 +54,50 @@ func ProvideService(cfg *setting.Cfg, tokenService auth.UserTokenService, jwtSer
tracer tracing.Tracer, authProxy *authproxy.AuthProxy, loginService login.Service,
apiKeyService apikey.Service, authenticator loginpkg.Authenticator, userService user.Service,
orgService org.Service, oauthTokenService oauthtoken.OAuthTokenService, features *featuremgmt.FeatureManager,
authnService authn.Service,
authnService authn.Service, anonSessionService anonymous.Service,
) *ContextHandler {
return &ContextHandler{
Cfg: cfg,
AuthTokenService: tokenService,
JWTAuthService: jwtService,
RemoteCache: remoteCache,
RenderService: renderService,
SQLStore: sqlStore,
tracer: tracer,
authProxy: authProxy,
authenticator: authenticator,
loginService: loginService,
apiKeyService: apiKeyService,
userService: userService,
orgService: orgService,
oauthTokenService: oauthTokenService,
features: features,
authnService: authnService,
singleflight: new(singleflight.Group),
Cfg: cfg,
AuthTokenService: tokenService,
JWTAuthService: jwtService,
RemoteCache: remoteCache,
RenderService: renderService,
SQLStore: sqlStore,
tracer: tracer,
authProxy: authProxy,
authenticator: authenticator,
loginService: loginService,
apiKeyService: apiKeyService,
userService: userService,
orgService: orgService,
oauthTokenService: oauthTokenService,
features: features,
authnService: authnService,
anonSessionService: anonSessionService,
singleflight: new(singleflight.Group),
}
}
// ContextHandler is a middleware.
type ContextHandler struct {
Cfg *setting.Cfg
AuthTokenService auth.UserTokenService
JWTAuthService auth.JWTVerifierService
RemoteCache *remotecache.RemoteCache
RenderService rendering.Service
SQLStore db.DB
tracer tracing.Tracer
authProxy *authproxy.AuthProxy
authenticator loginpkg.Authenticator
loginService login.Service
apiKeyService apikey.Service
userService user.Service
orgService org.Service
oauthTokenService oauthtoken.OAuthTokenService
features *featuremgmt.FeatureManager
authnService authn.Service
singleflight *singleflight.Group
Cfg *setting.Cfg
AuthTokenService auth.UserTokenService
JWTAuthService auth.JWTVerifierService
RemoteCache *remotecache.RemoteCache
RenderService rendering.Service
SQLStore db.DB
tracer tracing.Tracer
authProxy *authproxy.AuthProxy
authenticator loginpkg.Authenticator
loginService login.Service
apiKeyService apikey.Service
userService user.Service
orgService org.Service
oauthTokenService oauthtoken.OAuthTokenService
features *featuremgmt.FeatureManager
authnService authn.Service
singleflight *singleflight.Group
anonSessionService anonymous.Service
// GetTime returns the current time.
// Stubbable by tests.
GetTime func() time.Time
@ -234,6 +237,17 @@ func (h *ContextHandler) initContextWithAnonymousUser(reqContext *contextmodel.R
return false
}
go func() {
defer func() {
if err := recover(); err != nil {
reqContext.Logger.Warn("tag anon session panic", "err", err)
}
}()
if err := h.anonSessionService.TagSession(reqContext.Req.Context(), reqContext.Req); err != nil {
reqContext.Logger.Warn("Failed to tag anonymous session", "error", err)
}
}()
reqContext.IsSignedIn = false
reqContext.AllowAnonymous = true
reqContext.SignedInUser = &user.SignedInUser{IsAnonymous: true}

Loading…
Cancel
Save