mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
841de2b75d
Instead of checking the value of the cookie expiration we rely on the boolean stored in the user session to check whether inactivity timeout should be disabled.
506 lines
16 KiB
Go
506 lines
16 KiB
Go
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"net"
|
|
"net/url"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/authelia/authelia/internal/authentication"
|
|
"github.com/authelia/authelia/internal/authorization"
|
|
"github.com/authelia/authelia/internal/configuration/schema"
|
|
"github.com/authelia/authelia/internal/mocks"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/suite"
|
|
)
|
|
|
|
// Test getOriginalURL
|
|
func TestShouldGetOriginalURLFromOriginalURLHeader(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://home.example.com")
|
|
originalURL, err := getOriginalURL(mock.Ctx)
|
|
assert.NoError(t, err)
|
|
|
|
expectedURL, err := url.ParseRequestURI("https://home.example.com")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expectedURL, originalURL)
|
|
}
|
|
|
|
func TestShouldGetOriginalURLFromForwardedHeadersWithoutURI(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
mock.Ctx.Request.Header.Set("X-Forwarded-Proto", "https")
|
|
mock.Ctx.Request.Header.Set("X-Forwarded-Host", "home.example.com")
|
|
originalURL, err := getOriginalURL(mock.Ctx)
|
|
assert.NoError(t, err)
|
|
|
|
expectedURL, err := url.ParseRequestURI("https://home.example.com")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expectedURL, originalURL)
|
|
}
|
|
|
|
func TestShouldGetOriginalURLFromForwardedHeadersWithURI(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "htt-ps//home?-.example.com")
|
|
_, err := getOriginalURL(mock.Ctx)
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "parse htt-ps//home?-.example.com: invalid URI for request", err.Error())
|
|
}
|
|
|
|
func TestShouldRaiseWhenTargetUrlIsMalformed(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
mock.Ctx.Request.Header.Set("X-Forwarded-Proto", "https")
|
|
mock.Ctx.Request.Header.Set("X-Forwarded-Host", "home.example.com")
|
|
mock.Ctx.Request.Header.Set("X-Forwarded-URI", "/abc")
|
|
originalURL, err := getOriginalURL(mock.Ctx)
|
|
assert.NoError(t, err)
|
|
|
|
expectedURL, err := url.ParseRequestURI("https://home.example.com/abc")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, expectedURL, originalURL)
|
|
}
|
|
|
|
func TestShouldRaiseWhenNoHeaderProvidedToDetectTargetURL(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
_, err := getOriginalURL(mock.Ctx)
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "Missing headers for detecting target URL", err.Error())
|
|
}
|
|
|
|
// Test parseBasicAuth
|
|
func TestShouldRaiseWhenHeaderDoesNotContainBasicPrefix(t *testing.T) {
|
|
_, _, err := parseBasicAuth("alzefzlfzemjfej==")
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "Basic prefix not found in authorization header", err.Error())
|
|
}
|
|
|
|
func TestShouldRaiseWhenCredentialsAreNotInBase64(t *testing.T) {
|
|
_, _, err := parseBasicAuth("Basic alzefzlfzemjfej==")
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "illegal base64 data at input byte 16", err.Error())
|
|
}
|
|
|
|
func TestShouldRaiseWhenCredentialsAreNotInCorrectForm(t *testing.T) {
|
|
// the decoded format should be user:password.
|
|
_, _, err := parseBasicAuth("Basic am9obiBwYXNzd29yZA==")
|
|
assert.Error(t, err)
|
|
assert.Equal(t, "Format for basic auth must be user:password", err.Error())
|
|
}
|
|
|
|
func TestShouldReturnUsernameAndPassword(t *testing.T) {
|
|
// the decoded format should be user:password.
|
|
user, password, err := parseBasicAuth("Basic am9objpwYXNzd29yZA==")
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, "john", user)
|
|
assert.Equal(t, "password", password)
|
|
}
|
|
|
|
// Test isTargetURLAuthorized
|
|
func TestShouldCheckAuthorizationMatching(t *testing.T) {
|
|
type Rule struct {
|
|
Policy string
|
|
AuthLevel authentication.Level
|
|
ExpectedMatching authorizationMatching
|
|
}
|
|
rules := []Rule{
|
|
Rule{"bypass", authentication.NotAuthenticated, Authorized},
|
|
Rule{"bypass", authentication.OneFactor, Authorized},
|
|
Rule{"bypass", authentication.TwoFactor, Authorized},
|
|
|
|
Rule{"one_factor", authentication.NotAuthenticated, NotAuthorized},
|
|
Rule{"one_factor", authentication.OneFactor, Authorized},
|
|
Rule{"one_factor", authentication.TwoFactor, Authorized},
|
|
|
|
Rule{"two_factor", authentication.NotAuthenticated, NotAuthorized},
|
|
Rule{"two_factor", authentication.OneFactor, NotAuthorized},
|
|
Rule{"two_factor", authentication.TwoFactor, Authorized},
|
|
|
|
Rule{"deny", authentication.NotAuthenticated, NotAuthorized},
|
|
Rule{"deny", authentication.OneFactor, Forbidden},
|
|
Rule{"deny", authentication.TwoFactor, Forbidden},
|
|
}
|
|
|
|
url, _ := url.ParseRequestURI("https://test.example.com")
|
|
|
|
for _, rule := range rules {
|
|
authorizer := authorization.NewAuthorizer(schema.AccessControlConfiguration{
|
|
DefaultPolicy: "deny",
|
|
Rules: []schema.ACLRule{schema.ACLRule{
|
|
Domain: "test.example.com",
|
|
Policy: rule.Policy,
|
|
}},
|
|
})
|
|
|
|
username := ""
|
|
if rule.AuthLevel > authentication.NotAuthenticated {
|
|
username = "john"
|
|
}
|
|
|
|
matching := isTargetURLAuthorized(authorizer, *url, username, []string{}, net.ParseIP("127.0.0.1"), rule.AuthLevel)
|
|
assert.Equal(t, rule.ExpectedMatching, matching, "policy=%s, authLevel=%v, expected=%v, actual=%v",
|
|
rule.Policy, rule.AuthLevel, rule.ExpectedMatching, matching)
|
|
}
|
|
}
|
|
|
|
// Test verifyBasicAuth
|
|
func TestShouldVerifyWrongCredentials(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(false, nil)
|
|
|
|
url, _ := url.ParseRequestURI("https://test.example.com")
|
|
_, _, _, err := verifyBasicAuth([]byte("Basic am9objpwYXNzd29yZA=="), *url, mock.Ctx)
|
|
|
|
assert.Error(t, err)
|
|
}
|
|
|
|
type TestCase struct {
|
|
URL string
|
|
Authorization string
|
|
ExpectedStatusCode int
|
|
}
|
|
|
|
func (tc TestCase) String() string {
|
|
return fmt.Sprintf("url=%s, auth=%s, exp_status=%d", tc.URL, tc.Authorization, tc.ExpectedStatusCode)
|
|
}
|
|
|
|
type BasicAuthorizationSuite struct {
|
|
suite.Suite
|
|
}
|
|
|
|
func NewBasicAuthorizationSuite() *BasicAuthorizationSuite {
|
|
return &BasicAuthorizationSuite{}
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldNotBeAbleToParseBasicAuth() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpaaaaaaaaaaaaaaaa")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldApplyDefaultPolicy() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com")
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(&authentication.UserDetails{
|
|
Emails: []string{"john@example.com"},
|
|
Groups: []string{"dev", "admins"},
|
|
}, nil)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 403, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfBypassDomain() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://bypass.example.com")
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(&authentication.UserDetails{
|
|
Emails: []string{"john@example.com"},
|
|
Groups: []string{"dev", "admins"},
|
|
}, nil)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 200, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfOneFactorDomain() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://one-factor.example.com")
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(&authentication.UserDetails{
|
|
Emails: []string{"john@example.com"},
|
|
Groups: []string{"dev", "admins"},
|
|
}, nil)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 200, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfTwoFactorDomain() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(&authentication.UserDetails{
|
|
Emails: []string{"john@example.com"},
|
|
Groups: []string{"dev", "admins"},
|
|
}, nil)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 401, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func (s *BasicAuthorizationSuite) TestShouldApplyPolicyOfDenyDomain() {
|
|
mock := mocks.NewMockAutheliaCtx(s.T())
|
|
defer mock.Close()
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://deny.example.com")
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(&authentication.UserDetails{
|
|
Emails: []string{"john@example.com"},
|
|
Groups: []string{"dev", "admins"},
|
|
}, nil)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
assert.Equal(s.T(), 403, mock.Ctx.Response.StatusCode())
|
|
}
|
|
|
|
func TestShouldVerifyAuthorizationsUsingBasicAuth(t *testing.T) {
|
|
suite.Run(t, NewBasicAuthorizationSuite())
|
|
}
|
|
|
|
func TestShouldVerifyWrongCredentialsInBasicAuth(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("wrongpass")).
|
|
Return(false, nil)
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode()
|
|
assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d",
|
|
"https://test.example.com", actualStatus, expStatus)
|
|
}
|
|
|
|
func TestShouldVerifyFailingPasswordCheckingInBasicAuth(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("wrongpass")).
|
|
Return(false, fmt.Errorf("Failed"))
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objp3cm9uZ3Bhc3M=")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode()
|
|
assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d",
|
|
"https://test.example.com", actualStatus, expStatus)
|
|
}
|
|
|
|
func TestShouldVerifyFailingDetailsFetchingInBasicAuth(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
|
|
Return(true, nil)
|
|
|
|
mock.UserProviderMock.EXPECT().
|
|
GetDetails(gomock.Eq("john")).
|
|
Return(nil, fmt.Errorf("Failed"))
|
|
|
|
mock.Ctx.Request.Header.Set("Proxy-Authorization", "Basic am9objpwYXNzd29yZA==")
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://test.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
expStatus, actualStatus := 401, mock.Ctx.Response.StatusCode()
|
|
assert.Equal(t, expStatus, actualStatus, "URL=%s -> StatusCode=%d != ExpectedStatusCode=%d",
|
|
"https://test.example.com", actualStatus, expStatus)
|
|
}
|
|
|
|
type Pair struct {
|
|
URL string
|
|
Username string
|
|
AuthenticationLevel authentication.Level
|
|
ExpectedStatusCode int
|
|
}
|
|
|
|
func (p Pair) String() string {
|
|
return fmt.Sprintf("url=%s, username=%s, auth_lvl=%d, exp_status=%d",
|
|
p.URL, p.Username, p.AuthenticationLevel, p.ExpectedStatusCode)
|
|
}
|
|
|
|
func TestShouldVerifyAuthorizationsUsingSessionCookie(t *testing.T) {
|
|
testCases := []Pair{
|
|
Pair{"https://test.example.com", "", authentication.NotAuthenticated, 401},
|
|
Pair{"https://bypass.example.com", "", authentication.NotAuthenticated, 200},
|
|
Pair{"https://one-factor.example.com", "", authentication.NotAuthenticated, 401},
|
|
Pair{"https://two-factor.example.com", "", authentication.NotAuthenticated, 401},
|
|
Pair{"https://deny.example.com", "", authentication.NotAuthenticated, 401},
|
|
|
|
Pair{"https://test.example.com", "john", authentication.OneFactor, 403},
|
|
Pair{"https://bypass.example.com", "john", authentication.OneFactor, 200},
|
|
Pair{"https://one-factor.example.com", "john", authentication.OneFactor, 200},
|
|
Pair{"https://two-factor.example.com", "john", authentication.OneFactor, 401},
|
|
Pair{"https://deny.example.com", "john", authentication.OneFactor, 403},
|
|
|
|
Pair{"https://test.example.com", "john", authentication.TwoFactor, 403},
|
|
Pair{"https://bypass.example.com", "john", authentication.TwoFactor, 200},
|
|
Pair{"https://one-factor.example.com", "john", authentication.TwoFactor, 200},
|
|
Pair{"https://two-factor.example.com", "john", authentication.TwoFactor, 200},
|
|
Pair{"https://deny.example.com", "john", authentication.TwoFactor, 403},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
testCase := testCase
|
|
t.Run(testCase.String(), func(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
userSession := mock.Ctx.GetSession()
|
|
userSession.Username = testCase.Username
|
|
userSession.AuthenticationLevel = testCase.AuthenticationLevel
|
|
mock.Ctx.SaveSession(userSession)
|
|
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", testCase.URL)
|
|
|
|
VerifyGet(mock.Ctx)
|
|
expStatus, actualStatus := testCase.ExpectedStatusCode, mock.Ctx.Response.StatusCode()
|
|
assert.Equal(t, expStatus, actualStatus, "URL=%s -> AuthLevel=%d, StatusCode=%d != ExpectedStatusCode=%d",
|
|
testCase.URL, testCase.AuthenticationLevel, actualStatus, expStatus)
|
|
|
|
if testCase.ExpectedStatusCode == 200 && testCase.Username != "" {
|
|
assert.Equal(t, []byte(testCase.Username), mock.Ctx.Response.Header.Peek("Remote-User"))
|
|
} else {
|
|
assert.Equal(t, []byte(nil), mock.Ctx.Response.Header.Peek("Remote-User"))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestShouldDestroySessionWhenInactiveForTooLong(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
clock := mocks.TestingClock{}
|
|
clock.Set(time.Now())
|
|
|
|
mock.Ctx.Configuration.Session.Inactivity = 10
|
|
|
|
userSession := mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = authentication.TwoFactor
|
|
userSession.LastActivity = clock.Now().Add(-1 * time.Hour).Unix()
|
|
mock.Ctx.SaveSession(userSession)
|
|
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
// The session has been destroyed
|
|
newUserSession := mock.Ctx.GetSession()
|
|
assert.Equal(t, "", newUserSession.Username)
|
|
assert.Equal(t, authentication.NotAuthenticated, newUserSession.AuthenticationLevel)
|
|
}
|
|
|
|
func TestShouldKeepSessionWhenUserCheckedRememberMeAndIsInactiveForTooLong(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
clock := mocks.TestingClock{}
|
|
clock.Set(time.Now())
|
|
|
|
mock.Ctx.Configuration.Session.Inactivity = 10
|
|
|
|
userSession := mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = authentication.TwoFactor
|
|
userSession.LastActivity = clock.Now().Add(-1 * time.Hour).Unix()
|
|
userSession.KeepMeLoggedIn = true
|
|
mock.Ctx.SaveSession(userSession)
|
|
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
// The session has been destroyed
|
|
newUserSession := mock.Ctx.GetSession()
|
|
assert.Equal(t, "john", newUserSession.Username)
|
|
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
|
|
}
|
|
|
|
func TestShouldKeepSessionWhenInactivityTimeoutHasNotBeenExceeded(t *testing.T) {
|
|
mock := mocks.NewMockAutheliaCtx(t)
|
|
defer mock.Close()
|
|
|
|
clock := mocks.TestingClock{}
|
|
clock.Set(time.Now())
|
|
|
|
mock.Ctx.Configuration.Session.Inactivity = 10
|
|
|
|
userSession := mock.Ctx.GetSession()
|
|
userSession.Username = "john"
|
|
userSession.AuthenticationLevel = authentication.TwoFactor
|
|
userSession.LastActivity = clock.Now().Add(-1 * time.Second).Unix()
|
|
mock.Ctx.SaveSession(userSession)
|
|
|
|
mock.Ctx.Request.Header.Set("X-Original-URL", "https://two-factor.example.com")
|
|
|
|
VerifyGet(mock.Ctx)
|
|
|
|
// The session has been destroyed
|
|
newUserSession := mock.Ctx.GetSession()
|
|
assert.Equal(t, "john", newUserSession.Username)
|
|
assert.Equal(t, authentication.TwoFactor, newUserSession.AuthenticationLevel)
|
|
}
|