diff --git a/internal/controller/proxy_controller.go b/internal/controller/proxy_controller.go index ffafaffd..4ee15a0a 100644 --- a/internal/controller/proxy_controller.go +++ b/internal/controller/proxy_controller.go @@ -86,15 +86,38 @@ func NewProxyController(i ProxyControllerInput) *ProxyController { return controller } +// Proxy godoc +// +// @Summary Proxy +// @Description Forward-Auth Proxy Endpoint +// @Tags forward-auth +// @Produce json +// @Param proxy path string true "Proxy Name" +// @Success 200 {object} SimpleResponse +// @Failure 302 +// @Failure 400 {object} SimpleResponse +// @Failure 401 {object} SimpleResponse +// @Failure 403 {object} SimpleResponse +// @Failure 500 {object} SimpleResponse +// @Router /api/auth/traefik [get] +// @Router /api/auth/caddy [get] +// @Router /api/auth/nginx [get] +// @Router /api/auth/envoy [get] +// @Router /api/auth/envoy [post] +// @Router /api/auth/envoy [head] +// @Router /api/auth/envoy [put] +// @Router /api/auth/envoy [patch] +// @Router /api/auth/envoy [delete] +// @Router /api/auth/envoy [options] func (controller *ProxyController) proxyHandler(c *gin.Context) { // Load proxy context based on the request type proxyCtx, err := controller.getProxyContext(c) if err != nil { controller.log.App.Error().Err(err).Msg("Failed to get proxy context from request") - c.JSON(400, gin.H{ - "status": 400, - "message": "Bad request", + c.JSON(400, SimpleResponse{ + Status: 400, + Message: "Bad request", }) return } @@ -118,9 +141,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if controller.policyEngine.Evaluate(service.RuleIPBypassed, aclsCtx) { controller.setHeaders(c, acls) - c.JSON(200, gin.H{ - "status": 200, - "message": "Authenticated", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Authenticated", }) return } @@ -128,9 +151,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if controller.policyEngine.Evaluate(service.RuleAuthEnabled, aclsCtx) { controller.log.App.Debug().Msg("Authentication is disabled for this resource, allowing access without authentication") controller.setHeaders(c, acls) - c.JSON(200, gin.H{ - "status": 200, - "message": "Authenticated", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Authenticated", }) return } @@ -151,9 +174,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if !controller.useBrowserResponse(proxyCtx) { c.Header("x-tinyauth-location", redirectURL) - c.JSON(403, gin.H{ - "status": 403, - "message": "Forbidden", + c.JSON(403, SimpleResponse{ + Status: 403, + Message: "Forbidden", }) return } @@ -200,9 +223,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if !controller.useBrowserResponse(proxyCtx) { c.Header("x-tinyauth-location", redirectURL) - c.JSON(403, gin.H{ - "status": 403, - "message": "Forbidden", + c.JSON(403, SimpleResponse{ + Status: 403, + Message: "Forbidden", }) return } @@ -244,9 +267,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if !controller.useBrowserResponse(proxyCtx) { c.Header("x-tinyauth-location", redirectURL) - c.JSON(403, gin.H{ - "status": 403, - "message": "Forbidden", + c.JSON(403, SimpleResponse{ + Status: 403, + Message: "Forbidden", }) return } @@ -271,9 +294,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { controller.setHeaders(c, acls) - c.JSON(200, gin.H{ - "status": 200, - "message": "Authenticated", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Authenticated", }) return } @@ -293,9 +316,9 @@ func (controller *ProxyController) proxyHandler(c *gin.Context) { if !controller.useBrowserResponse(proxyCtx) { c.Header("x-tinyauth-location", redirectURL) - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -329,9 +352,9 @@ func (controller *ProxyController) handleError(c *gin.Context, proxyCtx ProxyCon if !controller.useBrowserResponse(proxyCtx) { c.Header("x-tinyauth-location", redirectURL) - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } diff --git a/internal/controller/resources_controller.go b/internal/controller/resources_controller.go index f4b720ed..cb6a60c5 100644 --- a/internal/controller/resources_controller.go +++ b/internal/controller/resources_controller.go @@ -33,18 +33,28 @@ func NewResourcesController(i ResourcesControllerInput) *ResourcesController { return controller } +// Resources godoc +// +// @Summary Resources Endpoint +// @Description Get a resource by file name +// @Tags resources +// @Param resource path string true "Resource Name" +// @Success 200 +// @Failure 404 {object} SimpleResponse +// @Failure 403 {object} SimpleResponse +// @Router /resources/{resource} [get] func (controller *ResourcesController) resourcesHandler(c *gin.Context) { if controller.config.Resources.Path == "" { - c.JSON(404, gin.H{ - "status": 404, - "message": "Resource not found", + c.JSON(404, SimpleResponse{ + Status: 404, + Message: "Resource not found", }) return } if !controller.config.Resources.Enabled { - c.JSON(403, gin.H{ - "status": 403, - "message": "Resources are disabled", + c.JSON(403, SimpleResponse{ + Status: 403, + Message: "Resources are disabled", }) return } diff --git a/internal/controller/user_controller.go b/internal/controller/user_controller.go index ae6c23bf..fd7bf12a 100644 --- a/internal/controller/user_controller.go +++ b/internal/controller/user_controller.go @@ -32,6 +32,11 @@ type UserController struct { auth *service.AuthService } +type TotpPendingResponse struct { + SimpleResponse + TotpPending bool `json:"totpPending"` +} + type UserControllerInput struct { dig.In @@ -57,15 +62,29 @@ func NewUserController(i UserControllerInput) *UserController { return controller } +// Login godoc +// +// @Summary Login +// @Description Login Endpoint +// @Tags accounts +// @Accept json +// @Produce json +// @Success 200 {object} SimpleResponse +// @Success 200 {object} TotpPendingResponse +// @Failure 400 {object} SimpleResponse +// @Failure 401 {object} SimpleResponse +// @Failure 500 {object} SimpleResponse +// @Failure 429 {object} SimpleResponse +// @Router /api/user/login [post] func (controller *UserController) loginHandler(c *gin.Context) { var req LoginRequest err := c.ShouldBindJSON(&req) if err != nil { controller.log.App.Error().Err(err).Msg("Failed to bind JSON") - c.JSON(400, gin.H{ - "status": 400, - "message": "Bad Request", + c.JSON(400, SimpleResponse{ + Status: 400, + Message: "Bad Request", }) return } @@ -79,9 +98,9 @@ func (controller *UserController) loginHandler(c *gin.Context) { controller.log.AuditLoginFailure(req.Username, "local", c.ClientIP(), "account locked") c.Writer.Header().Add("x-tinyauth-lock-locked", "true") c.Writer.Header().Add("x-tinyauth-lock-reset", time.Now().Add(time.Duration(remaining)*time.Second).Format(time.RFC3339)) - c.JSON(429, gin.H{ - "status": 429, - "message": fmt.Sprintf("Too many failed login attempts. Try again in %d seconds", remaining), + c.JSON(429, SimpleResponse{ + Status: 429, + Message: fmt.Sprintf("Too many failed login attempts. Try again in %d seconds", remaining), }) return } @@ -93,16 +112,16 @@ func (controller *UserController) loginHandler(c *gin.Context) { controller.log.App.Warn().Str("username", req.Username).Msg("User not found during login attempt") controller.auth.RecordLoginAttempt(req.Username, false) controller.log.AuditLoginFailure(req.Username, "unknown", c.ClientIP(), "user not found") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } controller.log.App.Error().Err(err).Str("username", req.Username).Msg("Error searching for user during login attempt") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -115,9 +134,9 @@ func (controller *UserController) loginHandler(c *gin.Context) { } else { controller.log.AuditLoginFailure(req.Username, "ldap", c.ClientIP(), "invalid password") } - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -129,9 +148,9 @@ func (controller *UserController) loginHandler(c *gin.Context) { if localUser == nil { controller.log.App.Error().Str("username", req.Username).Msg("Local user not found after successful password verification") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -159,19 +178,21 @@ func (controller *UserController) loginHandler(c *gin.Context) { if err != nil { controller.log.App.Error().Err(err).Str("username", req.Username).Msg("Failed to create pending TOTP session") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } http.SetCookie(c.Writer, cookie) - c.JSON(200, gin.H{ - "status": 200, - "message": "TOTP required", - "totpPending": true, + c.JSON(200, TotpPendingResponse{ + SimpleResponse: SimpleResponse{ + Status: 200, + Message: "TOTP required", + }, + TotpPending: true, }) return } @@ -204,9 +225,9 @@ func (controller *UserController) loginHandler(c *gin.Context) { if err != nil { controller.log.App.Error().Err(err).Str("username", req.Username).Msg("Failed to create session cookie after successful login") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -223,12 +244,21 @@ func (controller *UserController) loginHandler(c *gin.Context) { controller.auth.RecordLoginAttempt(req.Username, true) - c.JSON(200, gin.H{ - "status": 200, - "message": "Login successful", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Login successful", }) } +// Logout godoc +// +// @Summary Logout +// @Description Logout Endpoint +// @Tags accounts +// @Produce json +// @Success 200 {object} SimpleResponse +// @Failure 500 {object} SimpleResponse +// @Router /api/user/logout [post] func (controller *UserController) logoutHandler(c *gin.Context) { controller.log.App.Debug().Msg("Logout attempt") @@ -237,16 +267,16 @@ func (controller *UserController) logoutHandler(c *gin.Context) { if err != nil { if errors.Is(err, http.ErrNoCookie) { controller.log.App.Warn().Msg("Logout attempt without session cookie, treating as successful logout") - c.JSON(200, gin.H{ - "status": 200, - "message": "Logout successful", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Logout successful", }) return } controller.log.App.Error().Err(err).Msg("Error retrieving session cookie on logout") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -255,9 +285,9 @@ func (controller *UserController) logoutHandler(c *gin.Context) { if err != nil { controller.log.App.Error().Err(err).Msg("Error deleting session on logout") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -273,21 +303,34 @@ func (controller *UserController) logoutHandler(c *gin.Context) { http.SetCookie(c.Writer, cookie) - c.JSON(200, gin.H{ - "status": 200, - "message": "Logout successful", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Logout successful", }) } +// TOTP godoc +// +// @Summary TOTP +// @Description TOTP Endpoint +// @Tags accounts +// @Accept json +// @Produce json +// @Success 200 {object} SimpleResponse +// @Failure 400 {object} SimpleResponse +// @Failure 401 {object} SimpleResponse +// @Failure 429 {object} SimpleResponse +// @Failure 500 {object} SimpleResponse +// @Router /api/user/totp [post] func (controller *UserController) totpHandler(c *gin.Context) { var req TotpRequest err := c.ShouldBindJSON(&req) if err != nil { controller.log.App.Error().Err(err).Msg("Failed to bind JSON for TOTP verification") - c.JSON(400, gin.H{ - "status": 400, - "message": "Bad Request", + c.JSON(400, SimpleResponse{ + Status: 400, + Message: "Bad Request", }) return } @@ -297,25 +340,25 @@ func (controller *UserController) totpHandler(c *gin.Context) { if err != nil { if errors.Is(err, model.ErrUserContextNotFound) { controller.log.App.Warn().Msg("TOTP verification attempt without user context") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } controller.log.App.Error().Err(err).Msg("Failed to create user context from request for TOTP verification") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } if !context.TOTPPending() { controller.log.App.Warn().Str("username", context.GetUsername()).Msg("TOTP verification attempt without pending TOTP session") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -329,9 +372,9 @@ func (controller *UserController) totpHandler(c *gin.Context) { controller.log.AuditLoginFailure(context.GetUsername(), "local", c.ClientIP(), "account locked") c.Writer.Header().Add("x-tinyauth-lock-locked", "true") c.Writer.Header().Add("x-tinyauth-lock-reset", time.Now().Add(time.Duration(remaining)*time.Second).Format(time.RFC3339)) - c.JSON(429, gin.H{ - "status": 429, - "message": fmt.Sprintf("Too many failed TOTP attempts. Try again in %d seconds", remaining), + c.JSON(429, SimpleResponse{ + Status: 429, + Message: fmt.Sprintf("Too many failed TOTP attempts. Try again in %d seconds", remaining), }) return } @@ -340,9 +383,9 @@ func (controller *UserController) totpHandler(c *gin.Context) { if user == nil { controller.log.App.Error().Str("username", context.GetUsername()).Msg("Local user not found during TOTP verification") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -353,9 +396,9 @@ func (controller *UserController) totpHandler(c *gin.Context) { controller.log.App.Warn().Str("username", context.GetUsername()).Msg("Invalid TOTP code during verification attempt") controller.auth.RecordLoginAttempt(context.GetUsername(), false) controller.log.AuditLoginFailure(context.GetUsername(), "local", c.ClientIP(), "invalid TOTP code") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -391,9 +434,9 @@ func (controller *UserController) totpHandler(c *gin.Context) { if err != nil { controller.log.App.Error().Err(err).Str("username", context.GetUsername()).Msg("Failed to create session cookie after successful TOTP verification") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -403,37 +446,48 @@ func (controller *UserController) totpHandler(c *gin.Context) { controller.log.App.Info().Str("username", context.GetUsername()).Msg("TOTP verification successful, login complete") controller.log.AuditLoginSuccess(context.GetUsername(), "local", c.ClientIP()) - c.JSON(200, gin.H{ - "status": 200, - "message": "Login successful", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Login successful", }) } +// Tailscale godoc +// +// @Summary Tailscale +// @Description Tailscale Auth Endpoint (Experimental) +// @Tags accounts +// @Accept json +// @Produce json +// @Success 200 {object} SimpleResponse +// @Failure 401 {object} SimpleResponse +// @Failure 500 {object} SimpleResponse +// @Router /api/user/tailscale [post] func (controller *UserController) tailscaleHandler(c *gin.Context) { context, err := new(model.UserContext).NewFromGin(c) if err != nil { if errors.Is(err, model.ErrUserContextNotFound) { controller.log.App.Warn().Msg("Tailscale login attempt without user context") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } controller.log.App.Error().Err(err).Msg("Failed to create user context from request") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } if context.Tailscale == nil { controller.log.App.Warn().Msg("Tailscale login attempt without Tailscale context") - c.JSON(401, gin.H{ - "status": 401, - "message": "Unauthorized", + c.JSON(401, SimpleResponse{ + Status: 401, + Message: "Unauthorized", }) return } @@ -449,9 +503,9 @@ func (controller *UserController) tailscaleHandler(c *gin.Context) { if err != nil { controller.log.App.Error().Err(err).Str("username", context.GetUsername()).Msg("Failed to create session cookie after successful Tailscale login") - c.JSON(500, gin.H{ - "status": 500, - "message": "Internal Server Error", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "Internal Server Error", }) return } @@ -461,8 +515,8 @@ func (controller *UserController) tailscaleHandler(c *gin.Context) { controller.log.App.Info().Str("username", context.GetUsername()).Msg("Tailscale login successful, login complete") controller.log.AuditLoginSuccess(context.GetUsername(), "tailscale", c.ClientIP()) - c.JSON(200, gin.H{ - "status": 200, - "message": "Login successful", + c.JSON(200, SimpleResponse{ + Status: 200, + Message: "Login successful", }) } diff --git a/internal/controller/well_known_controller.go b/internal/controller/well_known_controller.go index a32c3a06..65d647dc 100644 --- a/internal/controller/well_known_controller.go +++ b/internal/controller/well_known_controller.go @@ -58,18 +58,27 @@ func NewWellKnownController(i WellKnownControllerInput) *WellKnownController { oidc: i.OIDCService, } - i.RouterGroup.GET("/.well-known/openid-configuration", controller.OpenIDConnectConfiguration) - i.RouterGroup.GET("/.well-known/jwks.json", controller.JWKS) - i.RouterGroup.GET("/.well-known/webfinger", controller.WebFinger) + i.RouterGroup.GET("/.well-known/openid-configuration", controller.openIDConnectConfiguration) + i.RouterGroup.GET("/.well-known/jwks.json", controller.jwks) + i.RouterGroup.GET("/.well-known/webfinger", controller.webFinger) return controller } -func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context) { +// OpenIDConnectConfiguration godoc +// +// @Summary OpenID Connect Configuration +// @Description OpenID Connect Configuration Discovery Endpoint +// @Tags well-known +// @Produce json +// @Success 200 {object} OpenIDConnectConfiguration +// @Failure 500 {object} SimpleResponse +// @Router /.well-known/openid-configuration [get] +func (controller *WellKnownController) openIDConnectConfiguration(c *gin.Context) { if controller.oidc == nil { - c.JSON(500, gin.H{ - "status": 500, - "message": "OIDC service not configured", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "OIDC service not configured", }) return } @@ -94,11 +103,20 @@ func (controller *WellKnownController) OpenIDConnectConfiguration(c *gin.Context }) } -func (controller *WellKnownController) JWKS(c *gin.Context) { +// JWKS godoc +// +// @Summary JWKS +// @Description JWKS Endpoint +// @Tags well-known +// @Produce json +// @Success 200 +// @Failure 500 {object} SimpleResponse +// @Router /.well-known/jwks.json [get] +func (controller *WellKnownController) jwks(c *gin.Context) { if controller.oidc == nil { - c.JSON(500, gin.H{ - "status": 500, - "message": "OIDC service not configured", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "OIDC service not configured", }) return } @@ -106,9 +124,9 @@ func (controller *WellKnownController) JWKS(c *gin.Context) { jwks, err := controller.oidc.GetJWK() if err != nil { - c.JSON(500, gin.H{ - "status": 500, - "message": "failed to get JWK", + c.JSON(500, SimpleResponse{ + Status: 500, + Message: "failed to get JWK", }) return } @@ -122,16 +140,27 @@ func (controller *WellKnownController) JWKS(c *gin.Context) { c.Status(http.StatusOK) } -func (controller *WellKnownController) WebFinger(c *gin.Context) { +// WebFinger godoc +// +// @Summary WebFinger +// @Description WebFinger Endpoint +// @Tags well-known +// @Produce json +// @Param resource query string true "Resource" +// @Param rel query string false "Rel" +// @Success 200 {object} WebfingerResponse +// @Failure 400 {object} SimpleResponse +// @Router /.well-known/webfinger [get] +func (controller *WellKnownController) webFinger(c *gin.Context) { c.Header("Content-Type", "application/jrd+json") c.Header("Access-Control-Allow-Origin", "*") resource := c.Query("resource") if !controller.validateWebFingerResource(resource) { - c.JSON(400, gin.H{ - "status": 400, - "message": "invalid resource", + c.JSON(400, SimpleResponse{ + Status: 400, + Message: "invalid resource", }) return } diff --git a/internal/swagger/docs.go b/internal/swagger/docs.go index 30ac535b..a3f09176 100644 --- a/internal/swagger/docs.go +++ b/internal/swagger/docs.go @@ -19,6 +19,554 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { + "/.well-known/jwks.json": { + "get": { + "description": "JWKS Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "JWKS", + "responses": { + "200": { + "description": "OK" + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/.well-known/openid-configuration": { + "get": { + "description": "OpenID Connect Configuration Discovery Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "OpenID Connect Configuration", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.OpenIDConnectConfiguration" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/.well-known/webfinger": { + "get": { + "description": "WebFinger Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "WebFinger", + "parameters": [ + { + "type": "string", + "description": "Resource", + "name": "resource", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Rel", + "name": "rel", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.WebfingerResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/caddy": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/envoy": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "put": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "post": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "delete": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "options": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "head": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "patch": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/nginx": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/traefik": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, "/api/context/app": { "get": { "description": "Get the app context", @@ -231,6 +779,161 @@ const docTemplate = `{ } } }, + "/api/user/login": { + "post": { + "description": "Login Endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Login", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.TotpPendingResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/logout": { + "post": { + "description": "Logout Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Logout", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/tailscale": { + "post": { + "description": "Tailscale Auth Endpoint (Experimental)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Tailscale", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/totp": { + "post": { + "description": "TOTP Endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "TOTP", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, "/authorize": { "get": { "description": "OpenID Connect Authorize Endpoint", @@ -724,6 +1427,41 @@ const docTemplate = `{ } } } + }, + "/resources/{resource}": { + "get": { + "description": "Get a resource by file name", + "tags": [ + "resources" + ], + "summary": "Resources Endpoint", + "parameters": [ + { + "type": "string", + "description": "Resource Name", + "name": "resource", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } } }, "definitions": { @@ -836,6 +1574,80 @@ const docTemplate = `{ } } }, + "controller.OpenIDConnectConfiguration": { + "type": "object", + "properties": { + "authorization_endpoint": { + "type": "string" + }, + "claims_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "grant_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "id_token_signing_alg_values_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "issuer": { + "type": "string" + }, + "jwks_uri": { + "type": "string" + }, + "request_object_signing_alg_values_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "request_parameter_supported": { + "type": "boolean" + }, + "response_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "scopes_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "service_documentation": { + "type": "string" + }, + "subject_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "token_endpoint": { + "type": "string" + }, + "token_endpoint_auth_methods_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "userinfo_endpoint": { + "type": "string" + } + } + }, "controller.SimpleResponse": { "type": "object", "properties": { @@ -847,6 +1659,20 @@ const docTemplate = `{ } } }, + "controller.TotpPendingResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "totpPending": { + "type": "boolean" + } + } + }, "controller.UCRAuth": { "type": "object", "properties": { @@ -917,6 +1743,31 @@ const docTemplate = `{ } } }, + "controller.WebfingerResponse": { + "type": "object", + "properties": { + "links": { + "type": "array", + "items": { + "$ref": "#/definitions/controller.WebfingerResponseLink" + } + }, + "subject": { + "type": "string" + } + } + }, + "controller.WebfingerResponseLink": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "rel": { + "type": "string" + } + } + }, "model.AddressClaim": { "type": "object", "properties": { diff --git a/internal/swagger/swagger.json b/internal/swagger/swagger.json index de6cceb8..cd12591d 100644 --- a/internal/swagger/swagger.json +++ b/internal/swagger/swagger.json @@ -12,6 +12,554 @@ }, "basePath": "/", "paths": { + "/.well-known/jwks.json": { + "get": { + "description": "JWKS Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "JWKS", + "responses": { + "200": { + "description": "OK" + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/.well-known/openid-configuration": { + "get": { + "description": "OpenID Connect Configuration Discovery Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "OpenID Connect Configuration", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.OpenIDConnectConfiguration" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/.well-known/webfinger": { + "get": { + "description": "WebFinger Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "well-known" + ], + "summary": "WebFinger", + "parameters": [ + { + "type": "string", + "description": "Resource", + "name": "resource", + "in": "query", + "required": true + }, + { + "type": "string", + "description": "Rel", + "name": "rel", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.WebfingerResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/caddy": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/envoy": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "put": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "post": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "delete": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "options": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "head": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + }, + "patch": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/nginx": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/auth/traefik": { + "get": { + "description": "Forward-Auth Proxy Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "forward-auth" + ], + "summary": "Proxy", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "302": { + "description": "Found" + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, "/api/context/app": { "get": { "description": "Get the app context", @@ -224,6 +772,161 @@ } } }, + "/api/user/login": { + "post": { + "description": "Login Endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Login", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.TotpPendingResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/logout": { + "post": { + "description": "Logout Endpoint", + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Logout", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/tailscale": { + "post": { + "description": "Tailscale Auth Endpoint (Experimental)", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "Tailscale", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, + "/api/user/totp": { + "post": { + "description": "TOTP Endpoint", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "accounts" + ], + "summary": "TOTP", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "429": { + "description": "Too Many Requests", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } + }, "/authorize": { "get": { "description": "OpenID Connect Authorize Endpoint", @@ -717,6 +1420,41 @@ } } } + }, + "/resources/{resource}": { + "get": { + "description": "Get a resource by file name", + "tags": [ + "resources" + ], + "summary": "Resources Endpoint", + "parameters": [ + { + "type": "string", + "description": "Resource Name", + "name": "resource", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK" + }, + "403": { + "description": "Forbidden", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + }, + "404": { + "description": "Not Found", + "schema": { + "$ref": "#/definitions/controller.SimpleResponse" + } + } + } + } } }, "definitions": { @@ -829,6 +1567,80 @@ } } }, + "controller.OpenIDConnectConfiguration": { + "type": "object", + "properties": { + "authorization_endpoint": { + "type": "string" + }, + "claims_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "grant_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "id_token_signing_alg_values_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "issuer": { + "type": "string" + }, + "jwks_uri": { + "type": "string" + }, + "request_object_signing_alg_values_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "request_parameter_supported": { + "type": "boolean" + }, + "response_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "scopes_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "service_documentation": { + "type": "string" + }, + "subject_types_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "token_endpoint": { + "type": "string" + }, + "token_endpoint_auth_methods_supported": { + "type": "array", + "items": { + "type": "string" + } + }, + "userinfo_endpoint": { + "type": "string" + } + } + }, "controller.SimpleResponse": { "type": "object", "properties": { @@ -840,6 +1652,20 @@ } } }, + "controller.TotpPendingResponse": { + "type": "object", + "properties": { + "message": { + "type": "string" + }, + "status": { + "type": "integer" + }, + "totpPending": { + "type": "boolean" + } + } + }, "controller.UCRAuth": { "type": "object", "properties": { @@ -910,6 +1736,31 @@ } } }, + "controller.WebfingerResponse": { + "type": "object", + "properties": { + "links": { + "type": "array", + "items": { + "$ref": "#/definitions/controller.WebfingerResponseLink" + } + }, + "subject": { + "type": "string" + } + } + }, + "controller.WebfingerResponseLink": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "rel": { + "type": "string" + } + } + }, "model.AddressClaim": { "type": "object", "properties": { diff --git a/internal/swagger/swagger.yaml b/internal/swagger/swagger.yaml index 88593164..87e6252b 100644 --- a/internal/swagger/swagger.yaml +++ b/internal/swagger/swagger.yaml @@ -70,6 +70,55 @@ definitions: error: type: string type: object + controller.OpenIDConnectConfiguration: + properties: + authorization_endpoint: + type: string + claims_supported: + items: + type: string + type: array + grant_types_supported: + items: + type: string + type: array + id_token_signing_alg_values_supported: + items: + type: string + type: array + issuer: + type: string + jwks_uri: + type: string + request_object_signing_alg_values_supported: + items: + type: string + type: array + request_parameter_supported: + type: boolean + response_types_supported: + items: + type: string + type: array + scopes_supported: + items: + type: string + type: array + service_documentation: + type: string + subject_types_supported: + items: + type: string + type: array + token_endpoint: + type: string + token_endpoint_auth_methods_supported: + items: + type: string + type: array + userinfo_endpoint: + type: string + type: object controller.SimpleResponse: properties: message: @@ -77,6 +126,15 @@ definitions: status: type: integer type: object + controller.TotpPendingResponse: + properties: + message: + type: string + status: + type: integer + totpPending: + type: boolean + type: object controller.UCRAuth: properties: authenticated: @@ -122,6 +180,22 @@ definitions: totp: $ref: '#/definitions/controller.UCRTOTP' type: object + controller.WebfingerResponse: + properties: + links: + items: + $ref: '#/definitions/controller.WebfingerResponseLink' + type: array + subject: + type: string + type: object + controller.WebfingerResponseLink: + properties: + href: + type: string + rel: + type: string + type: object model.AddressClaim: properties: country: @@ -217,6 +291,369 @@ info: title: Tinyauth API version: development paths: + /.well-known/jwks.json: + get: + description: JWKS Endpoint + produces: + - application/json + responses: + "200": + description: OK + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: JWKS + tags: + - well-known + /.well-known/openid-configuration: + get: + description: OpenID Connect Configuration Discovery Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.OpenIDConnectConfiguration' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: OpenID Connect Configuration + tags: + - well-known + /.well-known/webfinger: + get: + description: WebFinger Endpoint + parameters: + - description: Resource + in: query + name: resource + required: true + type: string + - description: Rel + in: query + name: rel + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.WebfingerResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: WebFinger + tags: + - well-known + /api/auth/caddy: + get: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + /api/auth/envoy: + delete: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + get: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + head: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + options: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + patch: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + post: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + put: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + /api/auth/nginx: + get: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth + /api/auth/traefik: + get: + description: Forward-Auth Proxy Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "302": + description: Found + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Proxy + tags: + - forward-auth /api/context/app: get: description: Get the app context @@ -358,6 +795,108 @@ paths: summary: Authorize Complete tags: - oidc + /api/user/login: + post: + consumes: + - application/json + description: Login Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.TotpPendingResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Login + tags: + - accounts + /api/user/logout: + post: + description: Logout Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Logout + tags: + - accounts + /api/user/tailscale: + post: + consumes: + - application/json + description: Tailscale Auth Endpoint (Experimental) + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Tailscale + tags: + - accounts + /api/user/totp: + post: + consumes: + - application/json + description: TOTP Endpoint + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/controller.SimpleResponse' + "400": + description: Bad Request + schema: + $ref: '#/definitions/controller.SimpleResponse' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/controller.SimpleResponse' + "429": + description: Too Many Requests + schema: + $ref: '#/definitions/controller.SimpleResponse' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: TOTP + tags: + - accounts /authorize: get: consumes: @@ -687,4 +1226,27 @@ paths: summary: Userinfo tags: - oidc + /resources/{resource}: + get: + description: Get a resource by file name + parameters: + - description: Resource Name + in: path + name: resource + required: true + type: string + responses: + "200": + description: OK + "403": + description: Forbidden + schema: + $ref: '#/definitions/controller.SimpleResponse' + "404": + description: Not Found + schema: + $ref: '#/definitions/controller.SimpleResponse' + summary: Resources Endpoint + tags: + - resources swagger: "2.0"