2017-07-06 17:28:13 +03:00
package integration
2016-04-20 21:54:57 +03:00
import (
2018-01-24 20:18:03 +03:00
"crypto/md5"
"crypto/rand"
2023-11-17 03:50:06 +03:00
"encoding/hex"
2023-09-27 16:22:06 +03:00
"encoding/json"
2016-04-20 21:54:57 +03:00
"fmt"
2018-01-24 20:18:03 +03:00
"io"
2016-04-20 21:54:57 +03:00
"net/http"
"os"
2019-11-14 18:40:05 +03:00
"strconv"
2016-04-20 21:54:57 +03:00
"strings"
2024-01-09 19:00:07 +03:00
"testing"
2016-04-20 21:54:57 +03:00
"time"
2024-01-09 19:00:07 +03:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
2020-09-16 16:46:04 +03:00
"github.com/traefik/traefik/v2/integration/try"
"github.com/traefik/traefik/v2/pkg/log"
"github.com/traefik/traefik/v2/pkg/middlewares/accesslog"
2016-04-20 21:54:57 +03:00
)
2017-07-10 17:58:12 +03:00
const (
traefikTestLogFile = "traefik.log"
traefikTestAccessLogFile = "access.log"
)
2020-05-11 13:06:07 +03:00
// AccessLogSuite tests suite.
2016-04-20 21:54:57 +03:00
type AccessLogSuite struct { BaseSuite }
2024-01-09 19:00:07 +03:00
func TestAccessLogSuite ( t * testing . T ) {
suite . Run ( t , new ( AccessLogSuite ) )
}
2018-01-11 12:04:03 +03:00
type accessLogValue struct {
2019-01-18 17:18:04 +03:00
formatOnly bool
code string
user string
routerName string
serviceURL string
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) SetupSuite ( ) {
s . BaseSuite . SetupSuite ( )
s . createComposeProject ( "access_log" )
s . composeUp ( )
}
func ( s * AccessLogSuite ) TearDownSuite ( ) {
s . BaseSuite . TearDownSuite ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TearDownTest ( ) {
s . displayTraefikLogFile ( traefikTestLogFile )
2019-09-13 20:28:04 +03:00
_ = os . Remove ( traefikTestAccessLogFile )
2018-02-05 11:48:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLog ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
2016-04-20 21:54:57 +03:00
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-02-05 11:48:03 +03:00
2019-01-18 17:18:04 +03:00
defer func ( ) {
2021-03-04 22:08:03 +03:00
traefikLog , err := os . ReadFile ( traefikTestLogFile )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-09-13 20:28:04 +03:00
log . WithoutContext ( ) . Info ( string ( traefikLog ) )
2019-01-18 17:18:04 +03:00
} ( )
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "server1" )
2017-05-17 16:22:44 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
// Make some requests
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "frontend1.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req , err = http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "frontend2.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogOutput ( )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , 3 , count )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogAuthFrontend ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "401" ,
user : "-" ,
routerName : "rt-authFrontend" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
2020-06-18 17:02:04 +03:00
{
formatOnly : false ,
code : "401" ,
user : "test" ,
routerName : "rt-authFrontend" ,
serviceURL : "-" ,
} ,
{
formatOnly : false ,
code : "200" ,
user : "test" ,
routerName : "rt-authFrontend" ,
2021-11-25 13:10:06 +03:00
serviceURL : "http://172.31.42" ,
2020-06-18 17:02:04 +03:00
} ,
2018-01-11 12:04:03 +03:00
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "authFrontend" )
2016-04-20 21:54:57 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
2020-06-18 17:02:04 +03:00
// Test auth entrypoint
2018-01-11 12:04:03 +03:00
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8006/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "frontend.auth.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusUnauthorized ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
2020-06-18 17:02:04 +03:00
req . SetBasicAuth ( "test" , "" )
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusUnauthorized ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2020-06-18 17:02:04 +03:00
req . SetBasicAuth ( "test" , "test" )
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2020-06-18 17:02:04 +03:00
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogDigestAuthMiddleware ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "401" ,
user : "-" ,
routerName : "rt-digestAuthMiddleware" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
2020-06-18 17:02:04 +03:00
{
formatOnly : false ,
code : "401" ,
user : "test" ,
routerName : "rt-digestAuthMiddleware" ,
serviceURL : "-" ,
} ,
2018-01-24 20:18:03 +03:00
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "200" ,
user : "test" ,
routerName : "rt-digestAuthMiddleware" ,
2021-11-25 13:10:06 +03:00
serviceURL : "http://172.31.42" ,
2018-01-24 20:18:03 +03:00
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-01-24 20:18:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-24 20:18:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "digestAuthMiddleware" )
2018-01-24 20:18:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-24 20:18:03 +03:00
// Test auth entrypoint
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8008/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-24 20:18:03 +03:00
req . Host = "entrypoint.digest.auth.docker.local"
resp , err := try . ResponseUntilStatusCode ( req , 500 * time . Millisecond , http . StatusUnauthorized )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-24 20:18:03 +03:00
2020-06-18 17:02:04 +03:00
digest := digestParts ( resp )
digest [ "uri" ] = "/"
digest [ "method" ] = http . MethodGet
digest [ "username" ] = "test"
digest [ "password" ] = "wrong"
2018-01-24 20:18:03 +03:00
2020-06-18 17:02:04 +03:00
req . Header . Set ( "Authorization" , getDigestAuthorization ( digest ) )
2018-01-24 20:18:03 +03:00
req . Header . Set ( "Content-Type" , "application/json" )
2020-06-18 17:02:04 +03:00
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusUnauthorized ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2020-06-18 17:02:04 +03:00
digest [ "password" ] = "test"
req . Header . Set ( "Authorization" , getDigestAuthorization ( digest ) )
2018-01-24 20:18:03 +03:00
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-24 20:18:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-24 20:18:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-24 20:18:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-24 20:18:03 +03:00
}
// Thanks to mvndaai for digest authentication
// https://stackoverflow.com/questions/39474284/how-do-you-do-a-http-post-with-digest-authentication-in-golang/39481441#39481441
func digestParts ( resp * http . Response ) map [ string ] string {
result := map [ string ] string { }
if len ( resp . Header [ "Www-Authenticate" ] ) > 0 {
wantedHeaders := [ ] string { "nonce" , "realm" , "qop" , "opaque" }
responseHeaders := strings . Split ( resp . Header [ "Www-Authenticate" ] [ 0 ] , "," )
for _ , r := range responseHeaders {
for _ , w := range wantedHeaders {
if strings . Contains ( r , w ) {
result [ w ] = strings . Split ( r , ` " ` ) [ 1 ]
}
}
}
}
return result
}
func getMD5 ( data string ) string {
digest := md5 . New ( )
2018-08-06 21:00:03 +03:00
if _ , err := digest . Write ( [ ] byte ( data ) ) ; err != nil {
2019-09-13 20:28:04 +03:00
log . WithoutContext ( ) . Error ( err )
2018-08-06 21:00:03 +03:00
}
2023-11-17 03:50:06 +03:00
return hex . EncodeToString ( digest . Sum ( nil ) )
2018-01-24 20:18:03 +03:00
}
func getCnonce ( ) string {
b := make ( [ ] byte , 8 )
2018-08-06 21:00:03 +03:00
if _ , err := io . ReadFull ( rand . Reader , b ) ; err != nil {
2019-09-13 20:28:04 +03:00
log . WithoutContext ( ) . Error ( err )
2018-08-06 21:00:03 +03:00
}
2023-11-17 03:50:06 +03:00
return hex . EncodeToString ( b ) [ : 16 ]
2018-01-24 20:18:03 +03:00
}
func getDigestAuthorization ( digestParts map [ string ] string ) string {
d := digestParts
ha1 := getMD5 ( d [ "username" ] + ":" + d [ "realm" ] + ":" + d [ "password" ] )
ha2 := getMD5 ( d [ "method" ] + ":" + d [ "uri" ] )
nonceCount := "00000001"
cnonce := getCnonce ( )
response := getMD5 ( fmt . Sprintf ( "%s:%s:%s:%s:%s:%s" , ha1 , d [ "nonce" ] , nonceCount , cnonce , d [ "qop" ] , ha2 ) )
authorization := fmt . Sprintf ( ` Digest username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop=%s, response="%s", opaque="%s", algorithm="MD5" ` ,
d [ "username" ] , d [ "realm" ] , d [ "nonce" ] , d [ "uri" ] , cnonce , nonceCount , d [ "qop" ] , response , d [ "opaque" ] )
return authorization
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogFrontendRedirect ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "302" ,
user : "-" ,
routerName : "rt-frontendRedirect" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
{
formatOnly : true ,
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-02-05 11:48:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "frontendRedirect" )
2018-01-11 12:04:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
// Test frontend redirect
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8005/test" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = ""
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogJSONFrontendRedirect ( ) {
2023-09-27 16:22:06 +03:00
ensureWorkingDirectoryIsClean ( )
type logLine struct {
DownstreamStatus int ` json:"downstreamStatus" `
OriginStatus int ` json:"originStatus" `
RouterName string ` json:"routerName" `
ServiceName string ` json:"serviceName" `
}
expected := [ ] logLine {
{
DownstreamStatus : 302 ,
OriginStatus : 0 ,
RouterName : "rt-frontendRedirect@docker" ,
ServiceName : "" ,
} ,
{
DownstreamStatus : 200 ,
OriginStatus : 200 ,
RouterName : "rt-server0@docker" ,
ServiceName : "service1@docker" ,
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_json_config.toml" ) )
2023-09-27 16:22:06 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2023-09-27 16:22:06 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "frontendRedirect" )
2023-09-27 16:22:06 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2023-09-27 16:22:06 +03:00
// Test frontend redirect
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8005/test" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-27 16:22:06 +03:00
req . Host = ""
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-27 16:22:06 +03:00
2024-01-09 19:00:07 +03:00
lines := s . extractLines ( )
assert . GreaterOrEqual ( s . T ( ) , len ( lines ) , len ( expected ) )
2023-09-27 16:22:06 +03:00
for i , line := range lines {
if line == "" {
continue
}
var logline logLine
err := json . Unmarshal ( [ ] byte ( line ) , & logline )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Equal ( s . T ( ) , expected [ i ] . DownstreamStatus , logline . DownstreamStatus )
assert . Equal ( s . T ( ) , expected [ i ] . OriginStatus , logline . OriginStatus )
assert . Equal ( s . T ( ) , expected [ i ] . RouterName , logline . RouterName )
assert . Equal ( s . T ( ) , expected [ i ] . ServiceName , logline . ServiceName )
2023-09-27 16:22:06 +03:00
}
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogRateLimit ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
formatOnly : true ,
} ,
{
formatOnly : true ,
} ,
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "429" ,
user : "-" ,
routerName : "rt-rateLimit" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "rateLimit" )
2018-01-11 12:04:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
// Test rate limit
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8007/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "ratelimit.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusTooManyRequests ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogBackendNotFound ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "404" ,
user : "-" ,
routerName : "-" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-02-05 11:48:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "server1" )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
// Test rate limit
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "backendnotfound.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusNotFound ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogFrontendWhitelist ( ) {
2018-01-11 12:04:03 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "403" ,
user : "-" ,
routerName : "rt-frontendWhitelist" ,
serviceURL : "-" ,
2018-01-11 12:04:03 +03:00
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "frontendWhitelist" )
2018-01-11 12:04:03 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-01-11 12:04:03 +03:00
// Test rate limit
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8000/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
req . Host = "frontend.whitelist.docker.local"
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusForbidden ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-01-11 12:04:03 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-01-11 12:04:03 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogAuthFrontendSuccess ( ) {
2018-10-25 19:00:05 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
2019-01-18 17:18:04 +03:00
formatOnly : false ,
code : "200" ,
user : "test" ,
routerName : "rt-authFrontend" ,
2021-11-25 13:10:06 +03:00
serviceURL : "http://172.31.42" ,
2018-10-25 19:00:05 +03:00
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2018-10-25 19:00:05 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2018-10-25 19:00:05 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "authFrontend" )
2018-10-25 19:00:05 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2018-10-25 19:00:05 +03:00
// Test auth entrypoint
req , err := http . NewRequest ( http . MethodGet , "http://127.0.0.1:8006/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-10-25 19:00:05 +03:00
req . Host = "frontend.auth.docker.local"
req . SetBasicAuth ( "test" , "test" )
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) , try . HasBody ( ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-29 13:18:06 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2023-09-29 13:18:06 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2023-09-29 13:18:06 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2023-09-29 13:18:06 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) TestAccessLogPreflightHeadersMiddleware ( ) {
2023-09-29 13:18:06 +03:00
ensureWorkingDirectoryIsClean ( )
expected := [ ] accessLogValue {
{
formatOnly : false ,
code : "200" ,
user : "-" ,
routerName : "rt-preflightCORS" ,
serviceURL : "-" ,
} ,
}
// Start Traefik
2024-01-09 19:00:07 +03:00
s . traefikCmd ( withConfigFile ( "fixtures/access_log_config.toml" ) )
2023-09-29 13:18:06 +03:00
2024-01-09 19:00:07 +03:00
s . checkStatsForLogFile ( )
2023-09-29 13:18:06 +03:00
2024-01-09 19:00:07 +03:00
s . waitForTraefik ( "preflightCORS" )
2023-09-29 13:18:06 +03:00
// Verify Traefik started OK
2024-01-09 19:00:07 +03:00
s . checkTraefikStarted ( )
2023-09-29 13:18:06 +03:00
// Test preflight response
req , err := http . NewRequest ( http . MethodOptions , "http://127.0.0.1:8009/" , nil )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2023-09-29 13:18:06 +03:00
req . Host = "preflight.docker.local"
req . Header . Set ( "Origin" , "whatever" )
req . Header . Set ( "Access-Control-Request-Method" , "GET" )
err = try . Request ( req , 500 * time . Millisecond , try . StatusCodeIs ( http . StatusOK ) )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-10-25 19:00:05 +03:00
// Verify access.log output as expected
2024-01-09 19:00:07 +03:00
count := s . checkAccessLogExactValuesOutput ( expected )
2018-10-25 19:00:05 +03:00
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , len ( expected ) )
2018-10-25 19:00:05 +03:00
// Verify no other Traefik problems
2024-01-09 19:00:07 +03:00
s . checkNoOtherTraefikProblems ( )
2018-10-25 19:00:05 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkNoOtherTraefikProblems ( ) {
2021-03-04 22:08:03 +03:00
traefikLog , err := os . ReadFile ( traefikTestLogFile )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
if len ( traefikLog ) > 0 {
fmt . Printf ( "%s\n" , string ( traefikLog ) )
}
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkAccessLogOutput ( ) int {
lines := s . extractLines ( )
2016-04-28 13:53:02 +03:00
count := 0
for i , line := range lines {
if len ( line ) > 0 {
count ++
2024-01-09 19:00:07 +03:00
s . CheckAccessLogFormat ( line , i )
2016-04-20 21:54:57 +03:00
}
}
2018-01-11 12:04:03 +03:00
return count
}
2016-04-20 21:54:57 +03:00
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkAccessLogExactValuesOutput ( values [ ] accessLogValue ) int {
lines := s . extractLines ( )
2018-01-11 12:04:03 +03:00
count := 0
for i , line := range lines {
2019-01-18 17:18:04 +03:00
fmt . Println ( line )
2018-01-11 12:04:03 +03:00
if len ( line ) > 0 {
count ++
if values [ i ] . formatOnly {
2024-01-09 19:00:07 +03:00
s . CheckAccessLogFormat ( line , i )
2018-01-11 12:04:03 +03:00
} else {
2024-01-09 19:00:07 +03:00
s . checkAccessLogExactValues ( line , i , values [ i ] )
2018-01-11 12:04:03 +03:00
}
}
}
return count
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) extractLines ( ) [ ] string {
2021-03-04 22:08:03 +03:00
accessLog , err := os . ReadFile ( traefikTestAccessLogFile )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2019-11-14 18:40:05 +03:00
2018-01-11 12:04:03 +03:00
lines := strings . Split ( string ( accessLog ) , "\n" )
2019-11-14 18:40:05 +03:00
var clean [ ] string
for _ , line := range lines {
if ! strings . Contains ( line , "/api/rawdata" ) {
clean = append ( clean , line )
}
}
return clean
2018-01-11 12:04:03 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkStatsForLogFile ( ) {
2018-01-11 12:04:03 +03:00
err := try . Do ( 1 * time . Second , func ( ) error {
if _ , errStat := os . Stat ( traefikTestLogFile ) ; errStat != nil {
2020-05-11 13:06:07 +03:00
return fmt . Errorf ( "could not get stats for log file: %w" , errStat )
2018-01-11 12:04:03 +03:00
}
return nil
} )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2018-01-11 12:04:03 +03:00
}
func ensureWorkingDirectoryIsClean ( ) {
os . Remove ( traefikTestAccessLogFile )
os . Remove ( traefikTestLogFile )
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkTraefikStarted ( ) [ ] byte {
2021-03-04 22:08:03 +03:00
traefikLog , err := os . ReadFile ( traefikTestLogFile )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
2016-04-28 13:53:02 +03:00
if len ( traefikLog ) > 0 {
2016-04-20 21:54:57 +03:00
fmt . Printf ( "%s\n" , string ( traefikLog ) )
}
2018-01-11 12:04:03 +03:00
return traefikLog
2016-04-20 21:54:57 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * BaseSuite ) CheckAccessLogFormat ( line string , i int ) {
2018-03-14 16:12:04 +03:00
results , err := accesslog . ParseAccessLog ( line )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Len ( s . T ( ) , results , 14 )
assert . Regexp ( s . T ( ) , ` ^(-|\d { 3})$ ` , results [ accesslog . OriginStatus ] )
2019-11-14 18:40:05 +03:00
count , _ := strconv . Atoi ( results [ accesslog . RequestCount ] )
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , i + 1 )
assert . Regexp ( s . T ( ) , ` "(rt-.+@docker|api@internal)" ` , results [ accesslog . RouterName ] )
assert . True ( s . T ( ) , strings . HasPrefix ( results [ accesslog . ServiceURL ] , ` "http:// ` ) )
assert . Regexp ( s . T ( ) , ` ^\d+ms$ ` , results [ accesslog . Duration ] )
2017-08-11 13:04:58 +03:00
}
2024-01-09 19:00:07 +03:00
func ( s * AccessLogSuite ) checkAccessLogExactValues ( line string , i int , v accessLogValue ) {
2018-03-14 16:12:04 +03:00
results , err := accesslog . ParseAccessLog ( line )
2024-01-09 19:00:07 +03:00
require . NoError ( s . T ( ) , err )
assert . Len ( s . T ( ) , results , 14 )
2018-01-24 20:18:03 +03:00
if len ( v . user ) > 0 {
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , v . user , results [ accesslog . ClientUsername ] )
2018-01-24 20:18:03 +03:00
}
2024-01-09 19:00:07 +03:00
assert . Equal ( s . T ( ) , v . code , results [ accesslog . OriginStatus ] )
2019-11-14 18:40:05 +03:00
count , _ := strconv . Atoi ( results [ accesslog . RequestCount ] )
2024-01-09 19:00:07 +03:00
assert . GreaterOrEqual ( s . T ( ) , count , i + 1 )
assert . Regexp ( s . T ( ) , ` ^"? ` + v . routerName + ` .*(@docker)?$ ` , results [ accesslog . RouterName ] )
assert . Regexp ( s . T ( ) , ` ^"? ` + v . serviceURL + ` .*$ ` , results [ accesslog . ServiceURL ] )
assert . Regexp ( s . T ( ) , ` ^\d+ms$ ` , results [ accesslog . Duration ] )
2018-02-05 11:48:03 +03:00
}