package server

import (
	"context"
	"errors"
	"fmt"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/influxdata/influxdb/v2/chronograf"
	"github.com/influxdata/influxdb/v2/chronograf/mocks"
	"github.com/influxdata/influxdb/v2/chronograf/oauth2"
	"github.com/influxdata/influxdb/v2/chronograf/roles"
)

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 := &mocks.Authenticator{
			Principal:   test.Principal,
			ValidateErr: test.ValidateErr,
		}

		logger := &chronograf.NoopLogger{}
		handler := 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
		OrganizationsStore chronograf.OrganizationsStore
		Logger             chronograf.Logger
	}
	type args struct {
		principal *oauth2.Principal
		scheme    string
		useAuth   bool
		role      string
	}
	tests := []struct {
		name                   string
		fields                 fields
		args                   args
		hasOrganizationContext bool
		hasSuperAdminContext   bool
		hasRoleContext         bool
		hasServerContext       bool
		authorized             bool
	}{
		{
			name: "Not using auth",
			fields: fields{
				UsersStore: &mocks.UsersStore{},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				useAuth: false,
			},
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         false,
			hasServerContext:       true,
			authorized:             true,
		},
		{
			name: "User with member role is member 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{
								{
									Name:         roles.MemberRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "member",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "User with viewer role is member 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{
								{
									Name:         roles.ViewerRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "member",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "User with editor role is member 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{
								{
									Name:         roles.EditorRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "member",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "User with admin role is member 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{
								{
									Name:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "member",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.ViewerRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "viewer",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.EditorRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "viewer",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "viewer",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.ViewerRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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{
								{
									Name:         roles.EditorRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "editor",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "editor",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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{
								{
									Name:         roles.ViewerRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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{
								{
									Name:         roles.EditorRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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{
								{
									Name:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   false,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				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
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "User with viewer role is SuperAdmin 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:         roles.ViewerRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "superadmin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "User with editor role is SuperAdmin 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:         roles.EditorRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "superadmin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "User with admin role is SuperAdmin 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:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "superadmin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "SuperAdmin 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",
							SuperAdmin: true,
							Roles: []chronograf.Role{
								{
									Name:         roles.MemberRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "viewer",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   true,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "SuperAdmin 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",
							SuperAdmin: true,
							Roles: []chronograf.Role{
								{
									Name:         roles.MemberRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "editor",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   true,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "SuperAdmin 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",
							SuperAdmin: true,
							Roles: []chronograf.Role{
								{
									Name:         roles.MemberRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   true,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "SuperAdmin is SuperAdmin 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",
							SuperAdmin: true,
							Roles: []chronograf.Role{
								{
									Name:         roles.MemberRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "superadmin",
				useAuth: true,
			},
			authorized:             true,
			hasOrganizationContext: true,
			hasSuperAdminContext:   true,
			hasRoleContext:         true,
			hasServerContext:       false,
		},
		{
			name: "Invalid principal – principal is nil",
			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:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: nil,
				scheme:    "oauth2",
				role:      "admin",
				useAuth:   true,
			},
			authorized: false,
		},
		{
			name: "Invalid principal - missing organization",
			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:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject: "billysteve",
					Issuer:  "google",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "Invalid principal - organization id not uint64",
			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:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1ee7",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "Failed to retrieve organization",
			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:         roles.AdminRoleName,
									Organization: "1337",
								},
							},
						}, nil
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						switch *q.ID {
						case "1338":
							return &chronograf.Organization{
								ID:   "1338",
								Name: "The ShillBillThrilliettas",
							}, nil
						default:
							return nil, chronograf.ErrOrganizationNotFound
						}
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billysteve",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized: false,
		},
		{
			name: "Failed to retrieve user",
			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")
						}
						switch *q.Name {
						case "billysteve":
							return &chronograf.User{
								ID:       1337,
								Name:     "billysteve",
								Provider: "google",
								Scheme:   "oauth2",
								Roles: []chronograf.Role{
									{
										Name:         roles.AdminRoleName,
										Organization: "1337",
									},
								},
							}, nil
						default:
							return nil, chronograf.ErrUserNotFound
						}
					},
				},
				OrganizationsStore: &mocks.OrganizationsStore{
					DefaultOrganizationF: func(ctx context.Context) (*chronograf.Organization, error) {
						return &chronograf.Organization{
							ID: "0",
						}, nil
					},
					GetF: func(ctx context.Context, q chronograf.OrganizationQuery) (*chronograf.Organization, error) {
						if q.ID == nil {
							return nil, fmt.Errorf("invalid organization query: missing ID")
						}
						return &chronograf.Organization{
							ID:   "1337",
							Name: "The ShillBillThrilliettas",
						}, nil
					},
				},
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				principal: &oauth2.Principal{
					Subject:      "billietta",
					Issuer:       "google",
					Organization: "1337",
				},
				scheme:  "oauth2",
				role:    "admin",
				useAuth: true,
			},
			authorized: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var authorized bool
			var hasServerCtx bool
			var hasSuperAdminCtx bool
			var hasOrganizationCtx bool
			var hasRoleCtx bool
			next := func(w http.ResponseWriter, r *http.Request) {
				ctx := r.Context()
				hasServerCtx = hasServerContext(ctx)
				hasSuperAdminCtx = hasSuperAdminContext(ctx)
				_, hasOrganizationCtx = hasOrganizationContext(ctx)
				_, hasRoleCtx = hasRoleContext(ctx)
				authorized = true
			}
			fn := AuthorizedUser(
				&Store{
					UsersStore:         tt.fields.UsersStore,
					OrganizationsStore: tt.fields.OrganizationsStore,
				},
				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,
			)
			if tt.args.principal == nil {
				r = r.WithContext(context.WithValue(r.Context(), oauth2.PrincipalKey, nil))
			} else {
				r = r.WithContext(context.WithValue(r.Context(), oauth2.PrincipalKey, *tt.args.principal))
			}
			fn(w, r)

			if authorized != tt.authorized {
				t.Errorf("%q. AuthorizedUser() = %v, expected %v", tt.name, authorized, tt.authorized)
			}

			if !authorized && w.Code != http.StatusForbidden {
				t.Errorf("%q. AuthorizedUser() Status Code = %v, expected %v", tt.name, w.Code, http.StatusForbidden)
			}

			if hasServerCtx != tt.hasServerContext {
				t.Errorf("%q. AuthorizedUser().Context().Server = %v, expected %v", tt.name, hasServerCtx, tt.hasServerContext)
			}

			if hasSuperAdminCtx != tt.hasSuperAdminContext {
				t.Errorf("%q. AuthorizedUser().Context().SuperAdmin = %v, expected %v", tt.name, hasSuperAdminCtx, tt.hasSuperAdminContext)
			}

			if hasOrganizationCtx != tt.hasOrganizationContext {
				t.Errorf("%q. AuthorizedUser.Context().Organization = %v, expected %v", tt.name, hasOrganizationCtx, tt.hasOrganizationContext)
			}

			if hasRoleCtx != tt.hasRoleContext {
				t.Errorf("%q. AuthorizedUser().Context().Role = %v, expected %v", tt.name, hasRoleCtx, tt.hasRoleContext)
			}

		})
	}
}

func TestRawStoreAccess(t *testing.T) {
	type fields struct {
		Logger chronograf.Logger
	}
	type args struct {
		principal     *oauth2.Principal
		serverContext bool
		user          *chronograf.User
	}
	type wants struct {
		authorized       bool
		hasServerContext bool
	}
	tests := []struct {
		name   string
		fields fields
		args   args
		wants  wants
	}{
		{
			name: "middleware already has server context",
			fields: fields{
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				serverContext: true,
			},
			wants: wants{
				authorized:       true,
				hasServerContext: true,
			},
		},
		{
			name: "user on context is a SuperAdmin",
			fields: fields{
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				user: &chronograf.User{
					SuperAdmin: true,
				},
			},
			wants: wants{
				authorized:       true,
				hasServerContext: true,
			},
		},
		{
			name: "user on context is a not SuperAdmin",
			fields: fields{
				Logger: &chronograf.NoopLogger{},
			},
			args: args{
				user: &chronograf.User{
					SuperAdmin: false,
				},
			},
			wants: wants{
				authorized:       false,
				hasServerContext: false,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			var authorized bool
			var hasServerCtx bool
			next := func(w http.ResponseWriter, r *http.Request) {
				ctx := r.Context()
				hasServerCtx = hasServerContext(ctx)
				authorized = true
			}
			fn := RawStoreAccess(
				tt.fields.Logger,
				next,
			)

			w := httptest.NewRecorder()
			url := "http://any.url"
			r := httptest.NewRequest(
				"GET",
				url,
				nil,
			)
			if tt.args.principal == nil {
				r = r.WithContext(context.WithValue(r.Context(), oauth2.PrincipalKey, nil))
			} else {
				r = r.WithContext(context.WithValue(r.Context(), oauth2.PrincipalKey, *tt.args.principal))
			}

			if tt.args.serverContext {
				r = r.WithContext(serverContext(r.Context()))
			}
			if tt.args.user != nil {
				r = r.WithContext(context.WithValue(r.Context(), UserContextKey, tt.args.user))
			}
			fn(w, r)

			if authorized != tt.wants.authorized {
				t.Errorf("%q. RawStoreAccess() = %v, expected %v", tt.name, authorized, tt.wants.authorized)
			}

			if !authorized && w.Code != http.StatusForbidden {
				t.Errorf("%q. RawStoreAccess() Status Code = %v, expected %v", tt.name, w.Code, http.StatusForbidden)
			}

			if hasServerCtx != tt.wants.hasServerContext {
				t.Errorf("%q. RawStoreAccess().Context().Server = %v, expected %v", tt.name, hasServerCtx, tt.wants.hasServerContext)
			}

		})
	}
}
