mirror of
https://github.com/warmbly/warmbly.git
synced 2026-10-05 16:02:10 +00:00
105 lines
4.0 KiB
Go
105 lines
4.0 KiB
Go
package handler
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/warmbly/warmbly/internal/app/poollink"
|
|
"github.com/warmbly/warmbly/internal/errx"
|
|
"github.com/warmbly/warmbly/internal/models"
|
|
)
|
|
|
|
type fakeBroker struct {
|
|
poollink.Service
|
|
bound, completedWith string
|
|
}
|
|
|
|
func (f *fakeBroker) DescribeOAuthConsent(context.Context, string) (*models.PoolLinkOAuthConsent, *errx.Error) {
|
|
return &models.PoolLinkOAuthConsent{Provider: models.InboxProviderGoogle, InstanceHost: "warmbly.acme.io", WorkspaceName: "Acme"}, nil
|
|
}
|
|
|
|
func (f *fakeBroker) ContinueOAuth(_ context.Context, _ string, binding string) (string, *errx.Error) {
|
|
f.bound = binding
|
|
return "https://accounts.google.com/o/oauth2/auth?x=1", nil
|
|
}
|
|
|
|
func (f *fakeBroker) CompleteOAuthCallback(_ context.Context, _, _, _, _, binding string) (string, *errx.Error) {
|
|
f.completedWith = binding
|
|
if binding == "" {
|
|
return "", poollink.ErrOAuthBrowser
|
|
}
|
|
return "https://warmbly.acme.io/cloud-oauth/done?status=ok", nil
|
|
}
|
|
|
|
func serve(t *testing.T, fn gin.HandlerFunc, target string, cookies ...*http.Cookie) *httptest.ResponseRecorder {
|
|
t.Helper()
|
|
gin.SetMode(gin.TestMode)
|
|
w := httptest.NewRecorder()
|
|
c, _ := gin.CreateTestContext(w)
|
|
c.Request = httptest.NewRequest(http.MethodGet, target, nil)
|
|
for _, ck := range cookies {
|
|
c.Request.AddCookie(ck)
|
|
}
|
|
fn(c)
|
|
return w
|
|
}
|
|
|
|
func TestBrokeredSigninCompletesOnlyInTheBrowserThatContinued(t *testing.T) {
|
|
f := &fakeBroker{}
|
|
h := &Handler{PoolLinkService: f}
|
|
|
|
page := serve(t, h.PoolLinkOAuthConsentPage, "/addresses/connect?state=pl_x")
|
|
body := page.Body.String()
|
|
if page.Code != http.StatusOK || !strings.Contains(body, "warmbly.acme.io") || !strings.Contains(body, "Acme") || strings.Contains(body, "accounts.google.com") {
|
|
t.Fatalf("consent page = %d %s", page.Code, body)
|
|
}
|
|
cookies := page.Result().Cookies()
|
|
if len(cookies) != 1 || cookies[0].Name != brokerCookieName || !cookies[0].HttpOnly || cookies[0].SameSite != http.SameSiteLaxMode {
|
|
t.Fatalf("cookie = %+v", cookies)
|
|
}
|
|
token := cookies[0].Value
|
|
|
|
if w := serve(t, h.PoolLinkOAuthContinue, "/addresses/connect/continue?state=pl_x&t="+token); w.Code == http.StatusFound || f.bound != "" {
|
|
t.Fatalf("continue without the cookie = %d", w.Code)
|
|
}
|
|
if w := serve(t, h.PoolLinkOAuthContinue, "/addresses/connect/continue?state=pl_x&t=wrong", cookies[0]); w.Code == http.StatusFound || f.bound != "" {
|
|
t.Fatalf("continue with a token the page did not render = %d", w.Code)
|
|
}
|
|
if w := serve(t, h.PoolLinkOAuthContinue, "/addresses/connect/continue?state=pl_x&t="+token, cookies[0]); w.Code != http.StatusFound || f.bound != token {
|
|
t.Fatalf("continue from the page = %d, bound %q", w.Code, f.bound)
|
|
}
|
|
|
|
if w := serve(t, h.EmailOAuthCallbackGmail, "/addresses/google/callback?state=pl_x&code=c"); w.Code == http.StatusFound || strings.Contains(w.Body.String(), "postMessage") {
|
|
t.Fatalf("callback in another browser = %d %s", w.Code, w.Body.String())
|
|
}
|
|
if w := serve(t, h.EmailOAuthCallbackGmail, "/addresses/google/callback?state=pl_x&code=c", cookies[0]); w.Code != http.StatusFound || f.completedWith != token {
|
|
t.Fatalf("callback in the bound browser = %d", w.Code)
|
|
}
|
|
}
|
|
|
|
func TestCallbackPostsOnlyToAConfiguredOrigin(t *testing.T) {
|
|
t.Setenv("APP_ORIGIN", "")
|
|
t.Setenv("APP_URL", "")
|
|
t.Setenv("FRONTEND_BASE_URL", "")
|
|
t.Setenv("CORS_ALLOW_ORIGINS", "")
|
|
t.Setenv("PUBLIC_HOST", "")
|
|
t.Setenv("DEPLOYMENT_MODE", "self_hosted")
|
|
h := &Handler{}
|
|
for _, fn := range []gin.HandlerFunc{h.EmailOAuthCallbackGmail, h.IntegrationOAuthCallback} {
|
|
body := serve(t, fn, "/cb?state=s&code=c").Body.String()
|
|
if strings.Contains(body, `"*"`) || !strings.Contains(body, "APP_URL") {
|
|
t.Fatalf("unconfigured origin page = %s", body)
|
|
}
|
|
}
|
|
|
|
t.Setenv("APP_ORIGIN", "https://app.acme.io")
|
|
body := serve(t, h.EmailOAuthCallbackGmail, "/cb?state=s&code=c").Body.String()
|
|
if !strings.Contains(body, `"https://app.acme.io"`) || strings.Contains(body, `"*"`) {
|
|
t.Fatalf("configured origin page = %s", body)
|
|
}
|
|
}
|