mirror of
https://github.com/steveiliop56/tinyauth.git
synced 2026-04-28 16:38:12 +00:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a736c4ad90 | |||
| 74901dd88f |
@@ -57,6 +57,16 @@ export default defineConfig({
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/robots.txt/, ""),
|
||||
},
|
||||
"/authorize": {
|
||||
target: "http://tinyauth-backend:3000/authorize",
|
||||
changeOrigin: true,
|
||||
rewrite: (path) => path.replace(/^\/authorize/, ""),
|
||||
bypass: (req) => {
|
||||
if (req.method === "GET") {
|
||||
return "/index.html";
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
allowedHosts: true,
|
||||
},
|
||||
|
||||
@@ -87,7 +87,7 @@ func (app *BootstrapApp) setupRouter() (*gin.Engine, error) {
|
||||
|
||||
oauthController.SetupRoutes()
|
||||
|
||||
oidcController := controller.NewOIDCController(controller.OIDCControllerConfig{}, app.services.oidcService, apiRouter)
|
||||
oidcController := controller.NewOIDCController(controller.OIDCControllerConfig{}, app.services.oidcService, apiRouter, engine)
|
||||
|
||||
oidcController.SetupRoutes()
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ package controller
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"slices"
|
||||
"strings"
|
||||
@@ -21,6 +22,7 @@ type OIDCController struct {
|
||||
config OIDCControllerConfig
|
||||
router *gin.RouterGroup
|
||||
oidc *service.OIDCService
|
||||
engine *gin.Engine
|
||||
}
|
||||
|
||||
type AuthorizeCallback struct {
|
||||
@@ -57,11 +59,12 @@ type ClientCredentials struct {
|
||||
ClientSecret string
|
||||
}
|
||||
|
||||
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup) *OIDCController {
|
||||
func NewOIDCController(config OIDCControllerConfig, oidcService *service.OIDCService, router *gin.RouterGroup, engine *gin.Engine) *OIDCController {
|
||||
return &OIDCController{
|
||||
config: config,
|
||||
oidc: oidcService,
|
||||
router: router,
|
||||
engine: engine,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +75,7 @@ func (controller *OIDCController) SetupRoutes() {
|
||||
oidcGroup.POST("/token", controller.Token)
|
||||
oidcGroup.GET("/userinfo", controller.Userinfo)
|
||||
oidcGroup.POST("/userinfo", controller.Userinfo)
|
||||
controller.engine.POST("/authorize", controller.AuthorizePseudoPost)
|
||||
}
|
||||
|
||||
func (controller *OIDCController) GetClientInfo(c *gin.Context) {
|
||||
@@ -195,6 +199,18 @@ func (controller *OIDCController) Authorize(c *gin.Context) {
|
||||
})
|
||||
}
|
||||
|
||||
// Pseudo handler that will just redirect to get in frontend then back to backend
|
||||
func (controller *OIDCController) AuthorizePseudoPost(c *gin.Context) {
|
||||
body, err := io.ReadAll(c.Request.Body)
|
||||
if err != nil {
|
||||
tlog.App.Error().Err(err).Msg("Failed to read request body")
|
||||
c.Redirect(http.StatusFound, fmt.Sprintf("%s/authorize", controller.oidc.GetIssuer()))
|
||||
return
|
||||
}
|
||||
redirectUrl := fmt.Sprintf("%s/authorize?%s", controller.oidc.GetIssuer(), body)
|
||||
c.Redirect(http.StatusFound, redirectUrl)
|
||||
}
|
||||
|
||||
func (controller *OIDCController) Token(c *gin.Context) {
|
||||
if !controller.oidc.IsConfigured() {
|
||||
tlog.App.Warn().Msg("OIDC not configured")
|
||||
|
||||
@@ -12,14 +12,14 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tinyauthapp/tinyauth/internal/bootstrap"
|
||||
"github.com/tinyauthapp/tinyauth/internal/config"
|
||||
"github.com/tinyauthapp/tinyauth/internal/controller"
|
||||
"github.com/tinyauthapp/tinyauth/internal/repository"
|
||||
"github.com/tinyauthapp/tinyauth/internal/service"
|
||||
"github.com/tinyauthapp/tinyauth/internal/utils/tlog"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestOIDCController(t *testing.T) {
|
||||
@@ -846,6 +846,34 @@ func TestOIDCController(t *testing.T) {
|
||||
assert.Equal(t, "invalid_grant", res["error"])
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "Test authorize request with POST method",
|
||||
middlewares: []gin.HandlerFunc{
|
||||
simpleCtx,
|
||||
},
|
||||
run: func(t *testing.T, router *gin.Engine, recorder *httptest.ResponseRecorder) {
|
||||
body := service.AuthorizeRequest{
|
||||
Scope: "openid",
|
||||
ResponseType: "code",
|
||||
ClientID: "some-client-id",
|
||||
RedirectURI: "https://test.example.com/callback",
|
||||
State: "some-state",
|
||||
Nonce: "some-nonce",
|
||||
CodeChallenge: "some-challenge",
|
||||
CodeChallengeMethod: "plain",
|
||||
}
|
||||
queries, err := query.Values(body)
|
||||
assert.NoError(t, err)
|
||||
|
||||
req := httptest.NewRequest("POST", "/authorize", strings.NewReader(string(queries.Encode())))
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
router.ServeHTTP(recorder, req)
|
||||
assert.Equal(t, 302, recorder.Code)
|
||||
location := recorder.Header().Get("Location")
|
||||
assert.NotEmpty(t, location)
|
||||
assert.Equal(t, "https://tinyauth.example.com/authorize?client_id=some-client-id&code_challenge=some-challenge&code_challenge_method=plain&nonce=some-nonce&redirect_uri=https%3A%2F%2Ftest.example.com%2Fcallback&response_type=code&scope=openid&state=some-state", location)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
app := bootstrap.NewBootstrapApp(config.Config{})
|
||||
@@ -869,7 +897,7 @@ func TestOIDCController(t *testing.T) {
|
||||
group := router.Group("/api")
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
oidcController := controller.NewOIDCController(controllerCfg, oidcService, group)
|
||||
oidcController := controller.NewOIDCController(controllerCfg, oidcService, group, router)
|
||||
oidcController.SetupRoutes()
|
||||
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
@@ -39,6 +39,7 @@ func (m *UIMiddleware) Init() error {
|
||||
func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
path := strings.TrimPrefix(c.Request.URL.Path, "/")
|
||||
method := c.Request.Method
|
||||
|
||||
tlog.App.Debug().Str("path", path).Msg("path")
|
||||
|
||||
@@ -52,6 +53,12 @@ func (m *UIMiddleware) Middleware() gin.HandlerFunc {
|
||||
c.Writer.Write([]byte("User-agent: *\nDisallow: /\n"))
|
||||
return
|
||||
default:
|
||||
// For OIDC post authentication, we need to redirect the POST to /authorize to the backend
|
||||
if method == http.MethodPost && strings.HasPrefix(path, "authorize") {
|
||||
c.Next()
|
||||
return
|
||||
}
|
||||
|
||||
_, err := fs.Stat(m.uiFs, path)
|
||||
|
||||
// Enough for one authentication flow
|
||||
|
||||
@@ -100,14 +100,15 @@ type TokenResponse struct {
|
||||
}
|
||||
|
||||
type AuthorizeRequest struct {
|
||||
Scope string `json:"scope" binding:"required"`
|
||||
ResponseType string `json:"response_type" binding:"required"`
|
||||
ClientID string `json:"client_id" binding:"required"`
|
||||
RedirectURI string `json:"redirect_uri" binding:"required"`
|
||||
State string `json:"state"`
|
||||
Nonce string `json:"nonce"`
|
||||
CodeChallenge string `json:"code_challenge"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method"`
|
||||
Scope string `json:"scope" binding:"required" url:"scope"`
|
||||
ResponseType string `json:"response_type" binding:"required" url:"response_type"`
|
||||
ClientID string `json:"client_id" binding:"required" url:"client_id"`
|
||||
RedirectURI string `json:"redirect_uri" binding:"required" url:"redirect_uri"`
|
||||
State string `json:"state" url:"state"`
|
||||
Nonce string `json:"nonce" url:"nonce"`
|
||||
CodeChallenge string `json:"code_challenge" url:"code_challenge"`
|
||||
CodeChallengeMethod string `json:"code_challenge_method" url:"code_challenge_method"`
|
||||
Request string `json:"request" url:"request"`
|
||||
}
|
||||
|
||||
type OIDCServiceConfig struct {
|
||||
|
||||
Reference in New Issue
Block a user