2019-04-24 21:52:08 +00:00
|
|
|
package mocks
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
|
|
|
"testing"
|
2019-11-24 20:27:59 +00:00
|
|
|
"time"
|
2019-04-24 21:52:08 +00:00
|
|
|
|
|
|
|
"github.com/golang/mock/gomock"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/sirupsen/logrus/hooks/test"
|
2020-05-01 06:56:42 +00:00
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
"github.com/stretchr/testify/require"
|
2019-04-24 21:52:08 +00:00
|
|
|
"github.com/valyala/fasthttp"
|
2020-04-05 12:37:21 +00:00
|
|
|
|
|
|
|
"github.com/authelia/authelia/internal/authorization"
|
|
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
|
|
"github.com/authelia/authelia/internal/middlewares"
|
2020-05-01 06:56:42 +00:00
|
|
|
"github.com/authelia/authelia/internal/regulation"
|
2020-04-05 12:37:21 +00:00
|
|
|
"github.com/authelia/authelia/internal/session"
|
2020-05-01 06:56:42 +00:00
|
|
|
"github.com/authelia/authelia/internal/storage"
|
2019-04-24 21:52:08 +00:00
|
|
|
)
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// MockAutheliaCtx a mock of AutheliaCtx.
|
2019-04-24 21:52:08 +00:00
|
|
|
type MockAutheliaCtx struct {
|
2020-04-20 21:03:38 +00:00
|
|
|
// Logger hook.
|
2019-04-24 21:52:08 +00:00
|
|
|
Hook *test.Hook
|
|
|
|
Ctx *middlewares.AutheliaCtx
|
|
|
|
Ctrl *gomock.Controller
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// Providers.
|
2019-04-24 21:52:08 +00:00
|
|
|
UserProviderMock *MockUserProvider
|
2019-11-17 01:05:46 +00:00
|
|
|
StorageProviderMock *storage.MockProvider
|
2019-04-24 21:52:08 +00:00
|
|
|
NotifierMock *MockNotifier
|
|
|
|
|
|
|
|
UserSession *session.UserSession
|
2019-11-24 20:27:59 +00:00
|
|
|
|
|
|
|
Clock TestingClock
|
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// TestingClock implementation of clock for tests.
|
2019-11-24 20:27:59 +00:00
|
|
|
type TestingClock struct {
|
|
|
|
now time.Time
|
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// Now return the stored clock.
|
2019-11-24 20:27:59 +00:00
|
|
|
func (dc *TestingClock) Now() time.Time {
|
|
|
|
return dc.now
|
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// After return a channel receiving the time after duration has elapsed.
|
2019-11-24 20:27:59 +00:00
|
|
|
func (dc *TestingClock) After(d time.Duration) <-chan time.Time {
|
|
|
|
return time.After(d)
|
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// Set set the time of the clock.
|
2019-11-24 20:27:59 +00:00
|
|
|
func (dc *TestingClock) Set(now time.Time) {
|
|
|
|
dc.now = now
|
2019-04-24 21:52:08 +00:00
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// NewMockAutheliaCtx create an instance of AutheliaCtx mock.
|
2019-04-24 21:52:08 +00:00
|
|
|
func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
|
|
|
|
mockAuthelia := new(MockAutheliaCtx)
|
2019-11-24 20:27:59 +00:00
|
|
|
mockAuthelia.Clock = TestingClock{}
|
2019-04-24 21:52:08 +00:00
|
|
|
|
2019-11-30 14:33:45 +00:00
|
|
|
datetime, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
|
|
|
|
mockAuthelia.Clock.Set(datetime)
|
|
|
|
|
2020-02-04 21:18:02 +00:00
|
|
|
configuration := schema.Configuration{}
|
2020-04-03 23:11:33 +00:00
|
|
|
configuration.Session.RememberMeDuration = schema.DefaultSessionConfiguration.RememberMeDuration
|
2019-04-24 21:52:08 +00:00
|
|
|
configuration.Session.Name = "authelia_session"
|
|
|
|
configuration.AccessControl.DefaultPolicy = "deny"
|
2020-04-09 01:05:17 +00:00
|
|
|
configuration.AccessControl.Rules = []schema.ACLRule{{
|
2020-04-16 00:18:11 +00:00
|
|
|
Domains: []string{"bypass.example.com"},
|
|
|
|
Policy: "bypass",
|
2020-04-09 01:05:17 +00:00
|
|
|
}, {
|
2020-04-16 00:18:11 +00:00
|
|
|
Domains: []string{"one-factor.example.com"},
|
|
|
|
Policy: "one_factor",
|
2020-04-09 01:05:17 +00:00
|
|
|
}, {
|
2020-04-16 00:18:11 +00:00
|
|
|
Domains: []string{"two-factor.example.com"},
|
|
|
|
Policy: "two_factor",
|
2020-04-09 01:05:17 +00:00
|
|
|
}, {
|
2020-04-16 00:18:11 +00:00
|
|
|
Domains: []string{"deny.example.com"},
|
|
|
|
Policy: "deny",
|
2020-05-04 19:39:25 +00:00
|
|
|
}, {
|
|
|
|
Domains: []string{"admin.example.com"},
|
|
|
|
Policy: "two_factor",
|
2020-06-25 08:22:42 +00:00
|
|
|
Subjects: [][]string{{"group:admin"}},
|
2020-05-04 19:39:25 +00:00
|
|
|
}, {
|
|
|
|
Domains: []string{"grafana.example.com"},
|
|
|
|
Policy: "two_factor",
|
2020-06-25 08:22:42 +00:00
|
|
|
Subjects: [][]string{{"group:grafana"}},
|
2019-04-24 21:52:08 +00:00
|
|
|
}}
|
|
|
|
|
|
|
|
providers := middlewares.Providers{}
|
|
|
|
|
|
|
|
mockAuthelia.Ctrl = gomock.NewController(t)
|
|
|
|
mockAuthelia.UserProviderMock = NewMockUserProvider(mockAuthelia.Ctrl)
|
|
|
|
providers.UserProvider = mockAuthelia.UserProviderMock
|
|
|
|
|
2019-11-17 01:05:46 +00:00
|
|
|
mockAuthelia.StorageProviderMock = storage.NewMockProvider(mockAuthelia.Ctrl)
|
2019-04-24 21:52:08 +00:00
|
|
|
providers.StorageProvider = mockAuthelia.StorageProviderMock
|
|
|
|
|
|
|
|
mockAuthelia.NotifierMock = NewMockNotifier(mockAuthelia.Ctrl)
|
|
|
|
providers.Notifier = mockAuthelia.NotifierMock
|
|
|
|
|
|
|
|
providers.Authorizer = authorization.NewAuthorizer(
|
2021-06-18 01:38:01 +00:00
|
|
|
&configuration)
|
2019-04-24 21:52:08 +00:00
|
|
|
|
|
|
|
providers.SessionProvider = session.NewProvider(
|
feat(session): add redis sentinel provider (#1768)
* feat(session): add redis sentinel provider
* refactor(session): use int for ports as per go standards
* refactor(configuration): adjust tests and validation
* refactor(configuration): add err format consts
* refactor(configuration): explicitly map redis structs
* refactor(session): merge redis/redis sentinel providers
* refactor(session): add additional checks to redis providers
* feat(session): add redis cluster provider
* fix: update config for new values
* fix: provide nil certpool to affected tests/mocks
* test: add additional tests to cover uncovered code
* docs: expand explanation of host and nodes relation for redis
* ci: add redis-sentinel to suite highavailability, add redis-sentinel quorum
* fix(session): sentinel password
* test: use redis alpine library image for redis sentinel, use expose instead of ports, use redis ip, adjust redis ip range, adjust redis config
* test: make entrypoint.sh executable, fix entrypoint.sh if/elif
* test: add redis failover tests
* test: defer docker start, adjust sleep, attempt logout before login, attempt visit before login and tune timeouts, add additional logging
* test: add sentinel integration test
* test: add secondary node failure to tests, fix password usage, bump test timeout, add sleep
* feat: use sentinel failover cluster
* fix: renamed addrs to sentineladdrs upstream
* test(session): sentinel failover
* test: add redis standard back into testing
* test: move redis standalone test to traefik2
* fix/docs: apply suggestions from code review
2021-03-09 23:03:05 +00:00
|
|
|
configuration.Session, nil)
|
2019-04-24 21:52:08 +00:00
|
|
|
|
2019-11-24 20:27:59 +00:00
|
|
|
providers.Regulator = regulation.NewRegulator(configuration.Regulation, providers.StorageProvider, &mockAuthelia.Clock)
|
2019-04-24 21:52:08 +00:00
|
|
|
|
|
|
|
request := &fasthttp.RequestCtx{}
|
2020-04-20 21:03:38 +00:00
|
|
|
// Set a cookie to identify this client throughout the test.
|
2019-04-24 21:52:08 +00:00
|
|
|
// request.Request.Header.SetCookie("authelia_session", "client_cookie")
|
|
|
|
|
|
|
|
autheliaCtx, _ := middlewares.NewAutheliaCtx(request, configuration, providers)
|
|
|
|
mockAuthelia.Ctx = autheliaCtx
|
|
|
|
|
|
|
|
logger, hook := test.NewNullLogger()
|
|
|
|
mockAuthelia.Hook = hook
|
|
|
|
|
|
|
|
mockAuthelia.Ctx.Logger = logrus.NewEntry(logger)
|
2020-05-05 19:35:32 +00:00
|
|
|
|
2019-04-24 21:52:08 +00:00
|
|
|
return mockAuthelia
|
|
|
|
}
|
|
|
|
|
2021-08-02 06:15:38 +00:00
|
|
|
// NewMockAutheliaCtxWithUserSession create an instance of AutheliaCtx mock with predefined user session.
|
|
|
|
func NewMockAutheliaCtxWithUserSession(t *testing.T, userSession session.UserSession) *MockAutheliaCtx {
|
|
|
|
mock := NewMockAutheliaCtx(t)
|
|
|
|
err := mock.Ctx.SaveSession(userSession)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
return mock
|
|
|
|
}
|
|
|
|
|
2020-04-20 21:03:38 +00:00
|
|
|
// Close close the mock.
|
2019-04-24 21:52:08 +00:00
|
|
|
func (m *MockAutheliaCtx) Close() {
|
|
|
|
m.Hook.Reset()
|
2019-11-24 20:27:59 +00:00
|
|
|
m.Ctrl.Finish()
|
2019-04-24 21:52:08 +00:00
|
|
|
}
|
|
|
|
|
2021-08-02 06:15:38 +00:00
|
|
|
// SetRequestBody set the request body from a struct with json tags.
|
|
|
|
func (m *MockAutheliaCtx) SetRequestBody(t *testing.T, body interface{}) {
|
|
|
|
bodyBytes, err := json.Marshal(body)
|
|
|
|
require.NoError(t, err)
|
|
|
|
m.Ctx.Request.SetBody(bodyBytes)
|
|
|
|
}
|
|
|
|
|
2020-05-05 21:27:38 +00:00
|
|
|
// Assert401KO assert an error response from the service.
|
|
|
|
func (m *MockAutheliaCtx) Assert401KO(t *testing.T, message string) {
|
|
|
|
assert.Equal(t, 401, m.Ctx.Response.StatusCode())
|
|
|
|
assert.Equal(t, fmt.Sprintf("{\"status\":\"KO\",\"message\":\"%s\"}", message), string(m.Ctx.Response.Body()))
|
|
|
|
}
|
|
|
|
|
2019-04-24 21:52:08 +00:00
|
|
|
// Assert200KO assert an error response from the service.
|
|
|
|
func (m *MockAutheliaCtx) Assert200KO(t *testing.T, message string) {
|
|
|
|
assert.Equal(t, 200, m.Ctx.Response.StatusCode())
|
|
|
|
assert.Equal(t, fmt.Sprintf("{\"status\":\"KO\",\"message\":\"%s\"}", message), string(m.Ctx.Response.Body()))
|
|
|
|
}
|
|
|
|
|
|
|
|
// Assert200OK assert a successful response from the service.
|
|
|
|
func (m *MockAutheliaCtx) Assert200OK(t *testing.T, data interface{}) {
|
|
|
|
assert.Equal(t, 200, m.Ctx.Response.StatusCode())
|
2020-05-05 19:35:32 +00:00
|
|
|
|
2019-04-24 21:52:08 +00:00
|
|
|
response := middlewares.OKResponse{
|
|
|
|
Status: "OK",
|
|
|
|
Data: data,
|
|
|
|
}
|
|
|
|
|
|
|
|
b, err := json.Marshal(response)
|
|
|
|
|
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, string(b), string(m.Ctx.Response.Body()))
|
|
|
|
}
|
2019-12-07 11:18:22 +00:00
|
|
|
|
2020-04-21 00:48:24 +00:00
|
|
|
// GetResponseData retrieves a response from the service.
|
2019-12-07 11:18:22 +00:00
|
|
|
func (m *MockAutheliaCtx) GetResponseData(t *testing.T, data interface{}) {
|
|
|
|
okResponse := middlewares.OKResponse{}
|
|
|
|
okResponse.Data = data
|
|
|
|
err := json.Unmarshal(m.Ctx.Response.Body(), &okResponse)
|
|
|
|
require.NoError(t, err)
|
|
|
|
}
|