package clients import ( "context" "net" "net/http" "testing" "time" "github.com/grafana/grafana/pkg/models/roletype" "github.com/grafana/grafana/pkg/models/usertoken" "github.com/grafana/grafana/pkg/services/auth" "github.com/grafana/grafana/pkg/services/auth/authtest" "github.com/grafana/grafana/pkg/services/authn" "github.com/grafana/grafana/pkg/services/user" "github.com/grafana/grafana/pkg/services/user/usertest" "github.com/grafana/grafana/pkg/web" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestSession_Test(t *testing.T) { cookieName := "grafana_session" validHTTPReq := &http.Request{ Header: map[string][]string{}, } validHTTPReq.AddCookie(&http.Cookie{Name: cookieName, Value: "bob-the-high-entropy-token"}) s := ProvideSession(&authtest.FakeUserAuthTokenService{}, &usertest.FakeUserService{}, "", 20*time.Second) disabled := s.Test(context.Background(), &authn.Request{HTTPRequest: validHTTPReq}) assert.False(t, disabled) s.loginCookieName = cookieName good := s.Test(context.Background(), &authn.Request{HTTPRequest: validHTTPReq}) assert.True(t, good) invalidHTTPReq := &http.Request{Header: map[string][]string{}} bad := s.Test(context.Background(), &authn.Request{HTTPRequest: invalidHTTPReq}) assert.False(t, bad) } func TestSession_Authenticate(t *testing.T) { cookieName := "grafana_session" validHTTPReq := &http.Request{ Header: map[string][]string{}, } validHTTPReq.AddCookie(&http.Cookie{Name: cookieName, Value: "bob-the-high-entropy-token"}) sampleToken := &usertoken.UserToken{ Id: 1, UserId: 1, AuthToken: "hashyToken", PrevAuthToken: "prevHashyToken", AuthTokenSeen: true, } sampleUser := &user.SignedInUser{ UserID: 1, Name: "sample user", Login: "sample_user", Email: "sample_user@samples.iwz", OrgID: 1, OrgRole: roletype.RoleEditor, } type fields struct { sessionService auth.UserTokenService userService user.Service } type args struct { r *authn.Request } tests := []struct { name string fields fields args args wantID *authn.Identity wantErr bool }{ { name: "cookie not found", fields: fields{sessionService: &authtest.FakeUserAuthTokenService{}, userService: &usertest.FakeUserService{}}, args: args{r: &authn.Request{HTTPRequest: &http.Request{}}}, wantID: nil, wantErr: true, }, { name: "success", fields: fields{sessionService: &authtest.FakeUserAuthTokenService{LookupTokenProvider: func(ctx context.Context, unhashedToken string) (*auth.UserToken, error) { return sampleToken, nil }}, userService: &usertest.FakeUserService{ExpectedSignedInUser: sampleUser}}, args: args{r: &authn.Request{HTTPRequest: validHTTPReq}}, wantID: &authn.Identity{ SessionToken: sampleToken, ID: "user:1", Name: "sample user", Login: "sample_user", Email: "sample_user@samples.iwz", OrgID: 1, OrgRoles: map[int64]roletype.RoleType{1: roletype.RoleEditor}, IsGrafanaAdmin: boolPtr(false), }, wantErr: false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { s := ProvideSession(tt.fields.sessionService, tt.fields.userService, cookieName, 20*time.Second) got, err := s.Authenticate(context.Background(), tt.args.r) require.True(t, (err != nil) == tt.wantErr, err) if err != nil { return } require.EqualValues(t, tt.wantID, got) }) } } type fakeResponseWriter struct { Status int HeaderStore http.Header } func (f *fakeResponseWriter) Header() http.Header { return f.HeaderStore } func (f *fakeResponseWriter) Write([]byte) (int, error) { return 0, nil } func (f *fakeResponseWriter) WriteHeader(statusCode int) { f.Status = statusCode } func TestSession_RefreshHook(t *testing.T) { s := ProvideSession(&authtest.FakeUserAuthTokenService{ TryRotateTokenProvider: func(ctx context.Context, token *auth.UserToken, clientIP net.IP, userAgent string) (bool, error) { token.UnhashedToken = "new-token" return true, nil }, }, &usertest.FakeUserService{}, "grafana-session", 20*time.Second) sampleID := &authn.Identity{ SessionToken: &auth.UserToken{ Id: 1, UserId: 1, }, } mockResponseWriter := &fakeResponseWriter{ Status: 0, HeaderStore: map[string][]string{}, } resp := &authn.Request{ HTTPRequest: &http.Request{ Header: map[string][]string{}, }, Resp: web.NewResponseWriter(http.MethodConnect, mockResponseWriter), } err := s.RefreshTokenHook(context.Background(), sampleID, resp) require.NoError(t, err) resp.Resp.WriteHeader(201) require.Equal(t, 201, mockResponseWriter.Status) assert.Equal(t, "new-token", sampleID.SessionToken.UnhashedToken) require.Len(t, mockResponseWriter.HeaderStore, 1) assert.Equal(t, "grafana-session=new-token; Path=/; Max-Age=20; HttpOnly", mockResponseWriter.HeaderStore.Get("set-cookie"), mockResponseWriter.HeaderStore) }