mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-06-21 19:00:19 +00:00
188 lines
5.7 KiB
Go
188 lines
5.7 KiB
Go
package controller
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/tinyauthapp/tinyauth/internal/test"
|
|
"github.com/tinyauthapp/tinyauth/internal/utils/logger"
|
|
)
|
|
|
|
func TestOAuthControllerIsRedirectSafe(t *testing.T) {
|
|
log := logger.NewLogger().WithTestConfig()
|
|
log.Init()
|
|
|
|
cfg, runtime := test.CreateTestConfigs(t)
|
|
|
|
type testCase struct {
|
|
description string
|
|
appURL string
|
|
cookieDomain string
|
|
subdomainsEnabled bool
|
|
redirectURI string
|
|
expected bool
|
|
}
|
|
|
|
tests := []testCase{
|
|
{
|
|
description: "Exact host match returns true",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://tinyauth.example.com",
|
|
expected: true,
|
|
},
|
|
{
|
|
description: "Exact host match is case insensitive",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://TinyAuth.Example.com",
|
|
expected: true,
|
|
},
|
|
{
|
|
description: "Exact host match with subdomains disabled returns true",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: false,
|
|
redirectURI: "https://tinyauth.example.com",
|
|
expected: true,
|
|
},
|
|
{
|
|
description: "Subdomain of cookie domain returns true when subdomains enabled",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://sub.example.com",
|
|
expected: true,
|
|
},
|
|
{
|
|
description: "Subdomain of cookie domain is case insensitive",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "Example.COM",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://SUB.example.com",
|
|
expected: true,
|
|
},
|
|
{
|
|
description: "Subdomain not matching cookie domain returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://sub.evil.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Subdomain returns false when subdomains disabled",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: false,
|
|
redirectURI: "https://sub.example.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Cookie domain itself is not a subdomain match",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://example.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Different scheme returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "http://tinyauth.example.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Different port returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://tinyauth.example.com:8080",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Empty redirect URI returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Redirect URI without host returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https:/malicious",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Redirect URI without scheme returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "tinyauth.example.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Relative redirect URI returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "/some/path",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Userinfo trick with malicious host returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://malicious.example.com@evil.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Unparseable redirect URI returns false",
|
|
appURL: "https://tinyauth.example.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://exa\x7fmple.com",
|
|
expected: false,
|
|
},
|
|
{
|
|
description: "Unparseable app URL returns false",
|
|
appURL: "https://tinyauth.\x7fexample.com",
|
|
cookieDomain: "example.com",
|
|
subdomainsEnabled: true,
|
|
redirectURI: "https://tinyauth.example.com",
|
|
expected: false,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.description, func(t *testing.T) {
|
|
router := gin.Default()
|
|
group := router.Group("/api")
|
|
gin.SetMode(gin.TestMode)
|
|
|
|
// Overwrite the app URL, cookie domain and subdomain setting for each test case
|
|
runtime.AppURL = tc.appURL
|
|
runtime.CookieDomain = tc.cookieDomain
|
|
cfg.Auth.SubdomainsEnabled = tc.subdomainsEnabled
|
|
|
|
ctrl := NewOAuthController(OAuthControllerInput{
|
|
Log: log,
|
|
Config: &cfg,
|
|
RuntimeConfig: &runtime,
|
|
RouterGroup: group,
|
|
})
|
|
|
|
assert.Equal(t, tc.expected, ctrl.isRedirectSafe(tc.redirectURI))
|
|
})
|
|
}
|
|
}
|