influxdb/server/auth_test.go

609 lines
16 KiB
Go

package server_test
import (
"context"
"errors"
"fmt"
"net/http"
"net/http/httptest"
"testing"
"github.com/influxdata/chronograf"
clog "github.com/influxdata/chronograf/log"
"github.com/influxdata/chronograf/mocks"
"github.com/influxdata/chronograf/oauth2"
"github.com/influxdata/chronograf/server"
)
type MockAuthenticator struct {
Principal oauth2.Principal
ValidateErr error
ExtendErr error
Serialized string
}
func (m *MockAuthenticator) Validate(context.Context, *http.Request) (oauth2.Principal, error) {
return m.Principal, m.ValidateErr
}
func (m *MockAuthenticator) Extend(ctx context.Context, w http.ResponseWriter, p oauth2.Principal) (oauth2.Principal, error) {
cookie := http.Cookie{}
http.SetCookie(w, &cookie)
return m.Principal, m.ExtendErr
}
func (m *MockAuthenticator) Authorize(ctx context.Context, w http.ResponseWriter, p oauth2.Principal) error {
cookie := http.Cookie{}
http.SetCookie(w, &cookie)
return nil
}
func (m *MockAuthenticator) Expire(http.ResponseWriter) {}
func (m *MockAuthenticator) ValidAuthorization(ctx context.Context, serializedAuthorization string) (oauth2.Principal, error) {
return oauth2.Principal{}, nil
}
func (m *MockAuthenticator) Serialize(context.Context, oauth2.Principal) (string, error) {
return m.Serialized, nil
}
func TestAuthorizedToken(t *testing.T) {
var tests = []struct {
Desc string
Code int
Principal oauth2.Principal
ValidateErr error
Expected string
}{
{
Desc: "Error in validate",
Code: http.StatusForbidden,
ValidateErr: errors.New("error"),
},
{
Desc: "Authorized ok",
Code: http.StatusOK,
Principal: oauth2.Principal{
Subject: "Principal Strickland",
},
Expected: "Principal Strickland",
},
}
for _, test := range tests {
// next is a sentinel StatusOK and
// principal recorder.
var principal oauth2.Principal
next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
principal = r.Context().Value(oauth2.PrincipalKey).(oauth2.Principal)
})
req, _ := http.NewRequest("GET", "", nil)
w := httptest.NewRecorder()
a := &MockAuthenticator{
Principal: test.Principal,
ValidateErr: test.ValidateErr,
}
logger := clog.New(clog.DebugLevel)
handler := server.AuthorizedToken(a, logger, next)
handler.ServeHTTP(w, req)
if w.Code != test.Code {
t.Errorf("Status code expected: %d actual %d", test.Code, w.Code)
} else if principal != test.Principal {
t.Errorf("Principal mismatch expected: %s actual %s", test.Principal, principal)
}
}
}
func TestAuthorizedUser(t *testing.T) {
type fields struct {
UsersStore chronograf.UsersStore
Logger chronograf.Logger
}
type args struct {
username string
provider string
scheme string
useAuth bool
role string
}
tests := []struct {
name string
fields fields
args args
authorized bool
}{
{
name: "Not using auth",
fields: fields{
UsersStore: &mocks.UsersStore{},
Logger: clog.New(clog.DebugLevel),
},
args: args{
useAuth: false,
},
authorized: true,
},
{
name: "User with viewer role is viewer authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.ViewerRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "viewer",
useAuth: true,
},
authorized: true,
},
{
name: "User with editor role is viewer authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.EditorRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "viewer",
useAuth: true,
},
authorized: true,
},
{
name: "User with admin role is viewer authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.AdminRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "viewer",
useAuth: true,
},
authorized: true,
},
{
name: "User with viewer role is editor unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.ViewerRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "editor",
useAuth: true,
},
authorized: false,
},
{
name: "User with editor role is editor authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.EditorRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "editor",
useAuth: true,
},
authorized: true,
},
{
name: "User with admin role is editor authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.AdminRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "editor",
useAuth: true,
},
authorized: true,
},
{
name: "User with viewer role is admin unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.ViewerRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "admin",
useAuth: true,
},
authorized: false,
},
{
name: "User with editor role is admin unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.EditorRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "admin",
useAuth: true,
},
authorized: false,
},
{
name: "User with admin role is admin authorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
server.AdminRole,
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "admin",
useAuth: true,
},
authorized: true,
},
{
name: "User with no role is viewer unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "view",
useAuth: true,
},
authorized: false,
},
{
name: "User with no role is editor unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "editor",
useAuth: true,
},
authorized: false,
},
{
name: "User with no role is admin unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "admin",
useAuth: true,
},
authorized: false,
},
{
name: "User with unknown role is viewer unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
{
Name: "sweet_role",
},
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "viewer",
useAuth: true,
},
authorized: false,
},
{
name: "User with unknown role is editor unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
{
Name: "sweet_role",
},
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "editor",
useAuth: true,
},
authorized: false,
},
{
name: "User with unknown role is admin unauthorized",
fields: fields{
UsersStore: &mocks.UsersStore{
GetF: func(ctx context.Context, q chronograf.UserQuery) (*chronograf.User, error) {
if q.Name == nil || q.Provider == nil || q.Scheme == nil {
return nil, fmt.Errorf("Invalid user query: missing Name, Provider, and/or Scheme")
}
return &chronograf.User{
ID: 1337,
Name: "billysteve",
Provider: "google",
Scheme: "oauth2",
Roles: []chronograf.Role{
{
Name: "sweet_role",
},
},
}, nil
},
},
Logger: clog.New(clog.DebugLevel),
},
args: args{
username: "billysteve",
provider: "google",
scheme: "oauth2",
role: "admin",
useAuth: true,
},
authorized: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var authorized bool
next := func(w http.ResponseWriter, r *http.Request) {
authorized = true
}
fn := server.AuthorizedUser(tt.fields.UsersStore, tt.args.useAuth, tt.args.role, tt.fields.Logger, next)
w := httptest.NewRecorder()
r := httptest.NewRequest(
"GET",
"http://any.url", // can be any valid URL as we are bypassing mux
nil,
)
r = r.WithContext(context.WithValue(r.Context(), oauth2.PrincipalKey, oauth2.Principal{
Subject: tt.args.username,
Issuer: tt.args.provider,
}))
fn(w, r)
if authorized != tt.authorized {
t.Errorf("%q. AuthorizedUser() = %v, expected %v", tt.name, authorized, tt.authorized)
}
})
}
}