summaryrefslogtreecommitdiff
path: root/internal/handlers/handler_authz_test.go
diff options
context:
space:
mode:
authorJames Elliott <james-d-elliott@users.noreply.github.com>2025-02-24 18:49:15 +1100
committerGitHub <noreply@github.com>2025-02-24 18:49:15 +1100
commit05fa254f27e6a1eee89abe8c5512d27de77cd7e7 (patch)
tree8f56e80b855f611000fe142303026f0ed71ef7ed /internal/handlers/handler_authz_test.go
parent194dd221ab7a5f2c9667b967532152df4914226a (diff)
feat(handlers): basic authz caching (#8320)
This adds the ability to cache successful basic authz attempts. This is done via a memory store that uses the HMAC-SHA256 algorithm to perform irreversible comparison of input parameters and has a maximum lifetime. Closes #5006 Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>
Diffstat (limited to 'internal/handlers/handler_authz_test.go')
-rw-r--r--internal/handlers/handler_authz_test.go495
1 files changed, 480 insertions, 15 deletions
diff --git a/internal/handlers/handler_authz_test.go b/internal/handlers/handler_authz_test.go
index e3161cb90..27400db87 100644
--- a/internal/handlers/handler_authz_test.go
+++ b/internal/handlers/handler_authz_test.go
@@ -84,11 +84,28 @@ func (s *AuthzSuite) Builder() (builder *AuthzBuilder) {
func (s *AuthzSuite) BuilderWithBearerScheme() (builder *AuthzBuilder) {
switch s.implementation {
case AuthzImplExtAuthz:
- return NewAuthzBuilder().WithImplementationExtAuthz().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ return NewAuthzBuilder().WithImplementationExtAuthz().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(time.Duration(0), model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
case AuthzImplForwardAuth:
- return NewAuthzBuilder().WithImplementationForwardAuth().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ return NewAuthzBuilder().WithImplementationForwardAuth().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(time.Duration(0), model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
case AuthzImplAuthRequest:
- return NewAuthzBuilder().WithImplementationAuthRequest().WithStrategies(NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ return NewAuthzBuilder().WithImplementationAuthRequest().WithStrategies(NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Duration(0), model.AuthorizationSchemeBasic.String(), model.AuthorizationSchemeBearer.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ case AuthzImplLegacy:
+ return NewAuthzBuilder().WithImplementationLegacy().WithStrategies(NewHeaderLegacyAuthnStrategy(), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ default:
+ s.T().FailNow()
+ }
+
+ return nil
+}
+
+func (s *AuthzSuite) BuilderWithProxyAuthorizationBasicSchemeCached() (builder *AuthzBuilder) {
+ switch s.implementation {
+ case AuthzImplExtAuthz:
+ return NewAuthzBuilder().WithImplementationExtAuthz().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(time.Minute, model.AuthorizationSchemeBasic.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ case AuthzImplForwardAuth:
+ return NewAuthzBuilder().WithImplementationForwardAuth().WithStrategies(NewHeaderProxyAuthorizationAuthnStrategy(time.Minute, model.AuthorizationSchemeBasic.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
+ case AuthzImplAuthRequest:
+ return NewAuthzBuilder().WithImplementationAuthRequest().WithStrategies(NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Minute, model.AuthorizationSchemeBasic.String()), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
case AuthzImplLegacy:
return NewAuthzBuilder().WithImplementationLegacy().WithStrategies(NewHeaderLegacyAuthnStrategy(), NewCookieSessionAuthnStrategy(schema.NewRefreshIntervalDurationAlways()))
default:
@@ -378,6 +395,348 @@ func (s *AuthzSuite) TestShouldVerifyFailureToGetDetailsUsingBasicScheme() {
}
}
+func (s *AuthzSuite) TestShouldVerifyFailureToGetDetailsUsingBasicSchemeCached() {
+ if s.setRequest == nil {
+ s.T().Skip()
+ }
+
+ authz := s.BuilderWithProxyAuthorizationBasicSchemeCached().Build()
+
+ mock := mocks.NewMockAutheliaCtx(s.T())
+
+ defer mock.Close()
+
+ setUpMockClock(mock)
+
+ s.ConfigureMockSessionProviderWithAutomaticAutheliaURLs(mock)
+
+ targetURI := s.RequireParseRequestURI("https://one-factor.example.com")
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ attempt := model.AuthenticationAttempt{
+ Time: mock.Ctx.Clock.Now(),
+ Successful: true,
+ Banned: false,
+ Username: "john",
+ Type: regulation.AuthType1FA,
+ RemoteIP: model.NewNullIP(mock.Ctx.RemoteIP()),
+ RequestURI: "https://one-factor.example.com",
+ RequestMethod: fasthttp.MethodGet,
+ }
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(true, nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(nil, fmt.Errorf("generic failure")),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(true, nil),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(nil, fmt.Errorf("generic failure")),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+
+ mock.Ctx.Request.Reset()
+ mock.Ctx.Response.Reset()
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(true, nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(nil, fmt.Errorf("generic failure")),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(nil, fmt.Errorf("generic failure")),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+}
+
+func (s *AuthzSuite) TestShouldVerifyFailureToCheckPasswordUsingBasicSchemeCached() {
+ if s.setRequest == nil {
+ s.T().Skip()
+ }
+
+ authz := s.BuilderWithProxyAuthorizationBasicSchemeCached().Build()
+
+ mock := mocks.NewMockAutheliaCtx(s.T())
+
+ defer mock.Close()
+
+ setUpMockClock(mock)
+
+ s.ConfigureMockSessionProviderWithAutomaticAutheliaURLs(mock)
+
+ targetURI := s.RequireParseRequestURI("https://one-factor.example.com")
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ attempt := model.AuthenticationAttempt{
+ Time: mock.Ctx.Clock.Now(),
+ Successful: false,
+ Banned: false,
+ Username: "john",
+ Type: regulation.AuthType1FA,
+ RemoteIP: model.NewNullIP(mock.Ctx.RemoteIP()),
+ RequestURI: "https://one-factor.example.com",
+ RequestMethod: fasthttp.MethodGet,
+ }
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, nil),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, nil),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+
+ mock.Ctx.Request.Reset()
+ mock.Ctx.Response.Reset()
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, nil),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, nil),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+}
+
+func (s *AuthzSuite) TestShouldVerifyErrorToCheckPasswordUsingBasicSchemeCached() {
+ if s.setRequest == nil {
+ s.T().Skip()
+ }
+
+ authz := s.BuilderWithProxyAuthorizationBasicSchemeCached().Build()
+
+ mock := mocks.NewMockAutheliaCtx(s.T())
+
+ defer mock.Close()
+
+ setUpMockClock(mock)
+
+ s.ConfigureMockSessionProviderWithAutomaticAutheliaURLs(mock)
+
+ targetURI := s.RequireParseRequestURI("https://one-factor.example.com")
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ attempt := model.AuthenticationAttempt{
+ Time: mock.Ctx.Clock.Now(),
+ Successful: false,
+ Banned: false,
+ Username: "john",
+ Type: regulation.AuthType1FA,
+ RemoteIP: model.NewNullIP(mock.Ctx.RemoteIP()),
+ RequestURI: "https://one-factor.example.com",
+ RequestMethod: fasthttp.MethodGet,
+ }
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, fmt.Errorf("bad data")),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, fmt.Errorf("bad data")),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+
+ mock.Ctx.Request.Reset()
+ mock.Ctx.Response.Reset()
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, fmt.Errorf("bad data")),
+ )
+ } else {
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(false, fmt.Errorf("bad data")),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ switch s.implementation {
+ case AuthzImplAuthRequest, AuthzImplLegacy:
+ s.Equal(fasthttp.StatusUnauthorized, mock.Ctx.Response.StatusCode())
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate)))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+ default:
+ s.Equal(fasthttp.StatusProxyAuthRequired, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal(`Basic realm="Authorization Required"`, string(mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate)))
+ }
+}
+
func (s *AuthzSuite) TestShouldVerifyBypassWithErrorToGetDetailsUsingBasicScheme() {
if s.setRequest == nil {
s.T().Skip()
@@ -654,6 +1013,114 @@ func (s *AuthzSuite) TestShouldApplyPolicyOfOneFactorDomain() {
s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
}
+func (s *AuthzSuite) TestShouldApplyPolicyOfOneFactorDomainCached() {
+ if s.setRequest == nil {
+ s.T().Skip()
+ }
+
+ authz := s.BuilderWithProxyAuthorizationBasicSchemeCached().Build()
+
+ mock := mocks.NewMockAutheliaCtx(s.T())
+
+ defer mock.Close()
+
+ setUpMockClock(mock)
+
+ s.ConfigureMockSessionProviderWithAutomaticAutheliaURLs(mock)
+
+ targetURI := s.RequireParseRequestURI("https://one-factor.example.com")
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ if s.implementation == AuthzImplLegacy {
+ gomock.InOrder(
+ 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),
+ 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),
+ )
+ } else {
+ attempt := model.AuthenticationAttempt{
+ Time: mock.Ctx.Clock.Now(),
+ Successful: true,
+ Banned: false,
+ Username: "john",
+ Type: regulation.AuthType1FA,
+ RemoteIP: model.NewNullIP(mock.Ctx.RemoteIP()),
+ RequestURI: "https://one-factor.example.com",
+ RequestMethod: fasthttp.MethodGet,
+ }
+
+ gomock.InOrder(
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ CheckUserPassword(gomock.Eq("john"), gomock.Eq("password")).
+ Return(true, nil),
+ mock.StorageMock.
+ EXPECT().
+ AppendAuthenticationLog(gomock.Eq(mock.Ctx), gomock.Eq(attempt)).Return(nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(&authentication.UserDetails{
+ Emails: []string{"john@example.com"},
+ Groups: []string{"dev", "admins"},
+ }, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedIP(gomock.Eq(mock.Ctx), gomock.Eq(model.NewIP(mock.Ctx.RemoteIP()))).Return(nil, nil),
+ mock.StorageMock.
+ EXPECT().
+ LoadBannedUser(gomock.Eq(mock.Ctx), gomock.Eq("john")).Return(nil, nil),
+ mock.UserProviderMock.EXPECT().
+ GetDetails(gomock.Eq("john")).
+ Return(&authentication.UserDetails{
+ Emails: []string{"john@example.com"},
+ Groups: []string{"dev", "admins"},
+ }, nil),
+ )
+ }
+
+ authz.Handler(mock.Ctx)
+
+ s.Equal(fasthttp.StatusOK, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+
+ mock.Ctx.Request.Reset()
+ mock.Ctx.Response.Reset()
+
+ s.setRequest(mock.Ctx, fasthttp.MethodGet, targetURI, true, false)
+
+ mock.Ctx.Request.Header.Set(fasthttp.HeaderProxyAuthorization, "Basic am9objpwYXNzd29yZA==")
+
+ authz.Handler(mock.Ctx)
+
+ s.Equal(fasthttp.StatusOK, mock.Ctx.Response.StatusCode())
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderWWWAuthenticate))
+ s.Equal([]byte(nil), mock.Ctx.Response.Header.Peek(fasthttp.HeaderProxyAuthenticate))
+}
+
func (s *AuthzSuite) TestShouldHandleAnyCaseSchemeParameter() {
if s.setRequest == nil {
s.T().Skip()
@@ -676,9 +1143,7 @@ func (s *AuthzSuite) TestShouldHandleAnyCaseSchemeParameter() {
defer mock.Close()
- mock.Ctx.Clock = &mock.Clock
-
- mock.Clock.Set(time.Now())
+ setUpMockClock(mock)
s.ConfigureMockSessionProviderWithAutomaticAutheliaURLs(mock)
@@ -885,8 +1350,8 @@ func (s *AuthzSuite) TestShouldApplyPolicyOfOneFactorDomainWithAuthorizationHead
builder := NewAuthzBuilder().WithImplementationLegacy()
builder = builder.WithStrategies(
- NewHeaderAuthorizationAuthnStrategy("basic"),
- NewHeaderProxyAuthorizationAuthRequestAuthnStrategy("basic"),
+ NewHeaderAuthorizationAuthnStrategy(time.Duration(0), "basic"),
+ NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Duration(0), "basic"),
NewCookieSessionAuthnStrategy(builder.config.RefreshInterval),
)
@@ -967,8 +1432,8 @@ func (s *AuthzSuite) TestShouldHandleAuthzWithoutHeaderNoCookie() {
builder := NewAuthzBuilder().WithImplementationLegacy()
builder = builder.WithStrategies(
- NewHeaderAuthorizationAuthnStrategy("basic"),
- NewHeaderProxyAuthorizationAuthRequestAuthnStrategy("basic"),
+ NewHeaderAuthorizationAuthnStrategy(time.Duration(0), "basic"),
+ NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Duration(0), "basic"),
)
authz := builder.Build()
@@ -1000,8 +1465,8 @@ func (s *AuthzSuite) TestShouldHandleAuthzWithEmptyAuthorizationHeader() {
builder := NewAuthzBuilder().WithImplementationLegacy()
builder = builder.WithStrategies(
- NewHeaderAuthorizationAuthnStrategy("basic"),
- NewHeaderProxyAuthorizationAuthRequestAuthnStrategy("basic"),
+ NewHeaderAuthorizationAuthnStrategy(time.Duration(0), "basic"),
+ NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Duration(0), "basic"),
)
authz := builder.Build()
@@ -1033,8 +1498,8 @@ func (s *AuthzSuite) TestShouldHandleAuthzWithAuthorizationHeaderInvalidPassword
builder := NewAuthzBuilder().WithImplementationLegacy()
builder = builder.WithStrategies(
- NewHeaderAuthorizationAuthnStrategy("basic"),
- NewHeaderProxyAuthorizationAuthRequestAuthnStrategy("basic"),
+ NewHeaderAuthorizationAuthnStrategy(time.Duration(0), "basic"),
+ NewHeaderProxyAuthorizationAuthRequestAuthnStrategy(time.Duration(0), "basic"),
)
authz := builder.Build()
@@ -1105,7 +1570,7 @@ func (s *AuthzSuite) TestShouldHandleAuthzWithIncorrectAuthHeader() { // TestSho
builder := s.Builder()
builder = builder.WithStrategies(
- NewHeaderAuthorizationAuthnStrategy("basic"),
+ NewHeaderAuthorizationAuthnStrategy(time.Duration(0), "basic"),
)
authz := builder.Build()