authelia/internal/mocks/authelia_ctx.go

204 lines
5.9 KiB
Go
Raw Normal View History

package mocks
import (
"encoding/json"
"fmt"
"testing"
"time"
"github.com/golang/mock/gomock"
"github.com/sirupsen/logrus"
"github.com/sirupsen/logrus/hooks/test"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/valyala/fasthttp"
"github.com/authelia/authelia/v4/internal/authorization"
"github.com/authelia/authelia/v4/internal/configuration/schema"
"github.com/authelia/authelia/v4/internal/middlewares"
"github.com/authelia/authelia/v4/internal/regulation"
"github.com/authelia/authelia/v4/internal/session"
"github.com/authelia/authelia/v4/internal/templates"
)
// MockAutheliaCtx a mock of AutheliaCtx.
type MockAutheliaCtx struct {
// Logger hook.
Hook *test.Hook
Ctx *middlewares.AutheliaCtx
Ctrl *gomock.Controller
// Providers.
UserProviderMock *MockUserProvider
StorageMock *MockStorage
NotifierMock *MockNotifier
TOTPMock *MockTOTP
UserSession *session.UserSession
Clock TestingClock
}
// TestingClock implementation of clock for tests.
type TestingClock struct {
now time.Time
}
// Now return the stored clock.
func (dc *TestingClock) Now() time.Time {
return dc.now
}
// After return a channel receiving the time after duration has elapsed.
func (dc *TestingClock) After(d time.Duration) <-chan time.Time {
return time.After(d)
}
// Set set the time of the clock.
func (dc *TestingClock) Set(now time.Time) {
dc.now = now
}
// NewMockAutheliaCtx create an instance of AutheliaCtx mock.
func NewMockAutheliaCtx(t *testing.T) *MockAutheliaCtx {
mockAuthelia := new(MockAutheliaCtx)
mockAuthelia.Clock = TestingClock{}
2019-11-30 21:33:45 +07:00
datetime, _ := time.Parse("2006-Jan-02", "2013-Feb-03")
mockAuthelia.Clock.Set(datetime)
configuration := schema.Configuration{}
[FEATURE] Remember Me Configuration (#813) * [FEATURE] Remember Me Configuration * allow users to specify the duration of remember me using remember_me_duration in session config * setting the duration to 0 disables remember me * only render the remember me element if remember me is enabled * prevent malicious users from faking remember me functionality in the backend * add string to duration helper called ParseDurationString to parse a string into a duration * added tests to the helper function * use the SessionProvider to store the time.Duration instead of parsing it over and over again * add sec doc, adjust month/min, consistency * renamed internal/utils/constants.go to internal/utils/const.go to be consistent * added security measure docs * adjusted default remember me duration to be 1 month instead of 1 year * utilize default remember me duration in the autheliaCtx mock * adjust order of keys in session configuration examples * add notes on session security measures secret only being redis * add TODO items for duration notation for both Expiration and Inactivity (will be removed soon) * fix error text for Inactivity in the validator * add session validator tests * deref check bodyJSON.KeepMeLoggedIn and derive the value based on conf and user input and store it (DRY) * remove unnecessary regex for the simplified ParseDurationString utility * ParseDurationString only accepts decimals without leading zeros now * comprehensively test all unit types * remove unnecessary type unions in web * add test to check sanity of time duration consts, this is just so they can't be accidentally changed * simplify deref check and assignment * fix reset password padding/margins * adjust some doc wording * adjust the handler configuration suite test * actually run the handler configuration suite test (whoops) * reduce the number of regex's used by ParseDurationString to 1, thanks to Clement * adjust some error wording
2020-04-04 06:11:33 +07:00
configuration.Session.RememberMeDuration = schema.DefaultSessionConfiguration.RememberMeDuration
configuration.Session.Name = "authelia_session"
configuration.AccessControl.DefaultPolicy = "deny"
configuration.AccessControl.Rules = []schema.ACLRule{{
Domains: []string{"bypass.example.com"},
Policy: "bypass",
}, {
Domains: []string{"one-factor.example.com"},
Policy: "one_factor",
}, {
Domains: []string{"two-factor.example.com"},
Policy: "two_factor",
}, {
Domains: []string{"deny.example.com"},
Policy: "deny",
[FEATURE] Automatic Profile Refresh - LDAP (#912) * [FIX] LDAP Not Checking for Updated Groups * refactor handlers verifyFromSessionCookie * refactor authorizer selectMatchingObjectRules * refactor authorizer isDomainMatching * add authorizer URLHasGroupSubjects method * add user provider ProviderType method * update tests * check for new LDAP groups and update session when: * user provider type is LDAP * authorization is forbidden * URL has rule with group subjects * Implement Refresh Interval * add default values for LDAP user provider * add default for refresh interval * add schema validator for refresh interval * add various tests * rename hasUserBeenInactiveLongEnough to hasUserBeenInactiveTooLong * use Authelia ctx clock * add check to determine if user is deleted, if so destroy the * make ldap user not found error a const * implement GetRefreshSettings in mock * Use user not found const with FileProvider * comment exports * use ctx.Clock instead of time pkg * add debug logging * use ptr to reference userSession so we don't have to retrieve it again * add documenation * add check for 0 refresh interval to reduce CPU cost * remove badly copied debug msg * add group change delta message * add SliceStringDelta * refactor ldap refresh to use the new func * improve delta add/remove log message * fix incorrect logic in SliceStringDelta * add tests to SliceStringDelta * add always config option * add tests for always config option * update docs * apply suggestions from code review Co-Authored-By: Amir Zarrinkafsh <nightah@me.com> * complete mocks and fix an old one * show warning when LDAP details failed to update for an unknown reason * golint fix * actually fix existing mocks * use mocks for LDAP refresh testing * use mocks for LDAP refresh testing for both added and removed groups * use test mock to verify disabled refresh behaviour * add information to threat model * add time const for default Unix() value * misc adjustments to mocks * Suggestions from code review * requested changes * update emails * docs updates * test updates * misc * golint fix * set debug for dev testing * misc docs and logging updates * misc grammar/spelling * use built function for VerifyGet * fix reviewdog suggestions * requested changes * Apply suggestions from code review Co-authored-by: Amir Zarrinkafsh <nightah@me.com> Co-authored-by: Clément Michaud <clement.michaud34@gmail.com>
2020-05-05 02:39:25 +07:00
}, {
Domains: []string{"admin.example.com"},
Policy: "two_factor",
Subjects: [][]string{{"group:admin"}},
[FEATURE] Automatic Profile Refresh - LDAP (#912) * [FIX] LDAP Not Checking for Updated Groups * refactor handlers verifyFromSessionCookie * refactor authorizer selectMatchingObjectRules * refactor authorizer isDomainMatching * add authorizer URLHasGroupSubjects method * add user provider ProviderType method * update tests * check for new LDAP groups and update session when: * user provider type is LDAP * authorization is forbidden * URL has rule with group subjects * Implement Refresh Interval * add default values for LDAP user provider * add default for refresh interval * add schema validator for refresh interval * add various tests * rename hasUserBeenInactiveLongEnough to hasUserBeenInactiveTooLong * use Authelia ctx clock * add check to determine if user is deleted, if so destroy the * make ldap user not found error a const * implement GetRefreshSettings in mock * Use user not found const with FileProvider * comment exports * use ctx.Clock instead of time pkg * add debug logging * use ptr to reference userSession so we don't have to retrieve it again * add documenation * add check for 0 refresh interval to reduce CPU cost * remove badly copied debug msg * add group change delta message * add SliceStringDelta * refactor ldap refresh to use the new func * improve delta add/remove log message * fix incorrect logic in SliceStringDelta * add tests to SliceStringDelta * add always config option * add tests for always config option * update docs * apply suggestions from code review Co-Authored-By: Amir Zarrinkafsh <nightah@me.com> * complete mocks and fix an old one * show warning when LDAP details failed to update for an unknown reason * golint fix * actually fix existing mocks * use mocks for LDAP refresh testing * use mocks for LDAP refresh testing for both added and removed groups * use test mock to verify disabled refresh behaviour * add information to threat model * add time const for default Unix() value * misc adjustments to mocks * Suggestions from code review * requested changes * update emails * docs updates * test updates * misc * golint fix * set debug for dev testing * misc docs and logging updates * misc grammar/spelling * use built function for VerifyGet * fix reviewdog suggestions * requested changes * Apply suggestions from code review Co-authored-by: Amir Zarrinkafsh <nightah@me.com> Co-authored-by: Clément Michaud <clement.michaud34@gmail.com>
2020-05-05 02:39:25 +07:00
}, {
Domains: []string{"grafana.example.com"},
Policy: "two_factor",
Subjects: [][]string{{"group:grafana"}},
}}
providers := middlewares.Providers{}
mockAuthelia.Ctrl = gomock.NewController(t)
mockAuthelia.UserProviderMock = NewMockUserProvider(mockAuthelia.Ctrl)
providers.UserProvider = mockAuthelia.UserProviderMock
mockAuthelia.StorageMock = NewMockStorage(mockAuthelia.Ctrl)
providers.StorageProvider = mockAuthelia.StorageMock
mockAuthelia.NotifierMock = NewMockNotifier(mockAuthelia.Ctrl)
providers.Notifier = mockAuthelia.NotifierMock
providers.Authorizer = authorization.NewAuthorizer(
&configuration)
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-10 06:03:05 +07:00
configuration.Session, nil)
providers.Regulator = regulation.NewRegulator(configuration.Regulation, providers.StorageProvider, &mockAuthelia.Clock)
mockAuthelia.TOTPMock = NewMockTOTP(mockAuthelia.Ctrl)
providers.TOTP = mockAuthelia.TOTPMock
var err error
if providers.Templates, err = templates.New(templates.Config{}); err != nil {
panic(err)
}
request := &fasthttp.RequestCtx{}
// Set a cookie to identify this client throughout the test.
// request.Request.Header.SetCookie("authelia_session", "client_cookie").
ctx := middlewares.NewAutheliaCtx(request, configuration, providers)
mockAuthelia.Ctx = ctx
logger, hook := test.NewNullLogger()
mockAuthelia.Hook = hook
mockAuthelia.Ctx.Logger = logrus.NewEntry(logger)
return mockAuthelia
}
// 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
}
// Close close the mock.
func (m *MockAutheliaCtx) Close() {
m.Hook.Reset()
m.Ctrl.Finish()
}
// 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)
}
// 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()))
}
// 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())
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()))
}
// GetResponseData retrieves a response from the service.
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)
}
// GetResponseError retrieves an error response from the service.
func (m *MockAutheliaCtx) GetResponseError(t *testing.T) (errResponse middlewares.ErrorResponse) {
err := json.Unmarshal(m.Ctx.Response.Body(), &errResponse)
require.NoError(t, err)
return errResponse
}