feat(routes): add vault token authentication fallback for secret APIs
Implements dual authentication strategy for secret management endpoints (PUT, restore, list versions, rollback). When Gitea user authentication is not available, the system now falls back to vault token authentication. This enables both user-based and token-based access patterns. Changes include: - Add Comment field to CreateSecretRequest for update operations - Replace requireRepoWrite helper with inline auth checks - Support userID=0 for token-based operations - Apply consistent auth pattern across all affected endpoints
This commit is contained in:
@@ -117,6 +117,7 @@ type CreateSecretRequest struct {
|
||||
Description string `json:"description"`
|
||||
Type string `json:"type"`
|
||||
Value string `json:"value" binding:"required"`
|
||||
Comment string `json:"comment"` // Used when updating existing secret
|
||||
}
|
||||
|
||||
// UpdateSecretRequest is the request body for updating a secret
|
||||
@@ -496,8 +497,29 @@ func apiPutSecret(lic *license.Manager) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !requireRepoWrite(ctx) {
|
||||
return
|
||||
// Try Gitea user auth first, then fall back to vault token auth
|
||||
var userID int64
|
||||
if ctx.Doer != nil {
|
||||
// Gitea user - check write permission
|
||||
if !ctx.Repo.CanWrite(unit.TypeCode) {
|
||||
ctx.JSON(http.StatusForbidden, map[string]any{
|
||||
"error": "forbidden",
|
||||
"message": "Repository write access required",
|
||||
})
|
||||
return
|
||||
}
|
||||
userID = ctx.Doer.ID
|
||||
} else {
|
||||
// Try vault token auth with write requirement
|
||||
authResult := authenticateVaultToken(ctx, r, true)
|
||||
if !authResult.Success {
|
||||
ctx.JSON(http.StatusUnauthorized, map[string]any{
|
||||
"error": "unauthorized",
|
||||
"message": authResult.Error,
|
||||
})
|
||||
return
|
||||
}
|
||||
userID = 0 // Token-based access
|
||||
}
|
||||
|
||||
name := chi.URLParam(r, "name")
|
||||
@@ -569,8 +591,8 @@ func apiPutSecret(lic *license.Manager) http.HandlerFunc {
|
||||
secret, err := services.UpdateSecret(ctx, ctx.Repo.Repository.ID, name, services.UpdateSecretOptions{
|
||||
Type: secretType,
|
||||
Value: req.Value,
|
||||
Comment: req.Description,
|
||||
UpdaterID: ctx.Doer.ID,
|
||||
Comment: req.Comment,
|
||||
UpdaterID: userID,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, map[string]any{
|
||||
@@ -651,8 +673,24 @@ func apiRestoreSecret(lic *license.Manager) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !requireRepoWrite(ctx) {
|
||||
return
|
||||
// Try Gitea user auth first, then fall back to vault token auth
|
||||
if ctx.Doer != nil {
|
||||
if !ctx.Repo.CanWrite(unit.TypeCode) {
|
||||
ctx.JSON(http.StatusForbidden, map[string]any{
|
||||
"error": "forbidden",
|
||||
"message": "Repository write access required",
|
||||
})
|
||||
return
|
||||
}
|
||||
} else {
|
||||
authResult := authenticateVaultToken(ctx, r, true)
|
||||
if !authResult.Success {
|
||||
ctx.JSON(http.StatusUnauthorized, map[string]any{
|
||||
"error": "unauthorized",
|
||||
"message": authResult.Error,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
name := chi.URLParam(r, "name")
|
||||
@@ -690,6 +728,18 @@ func apiListVersions(lic *license.Manager) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
// Try Gitea user auth first, then fall back to vault token auth
|
||||
if ctx.Doer == nil {
|
||||
authResult := authenticateVaultToken(ctx, r, false)
|
||||
if !authResult.Success {
|
||||
ctx.JSON(http.StatusUnauthorized, map[string]any{
|
||||
"error": "unauthorized",
|
||||
"message": authResult.Error,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
name := chi.URLParam(r, "name")
|
||||
|
||||
versions, err := services.ListVersions(ctx, ctx.Repo.Repository.ID, name)
|
||||
@@ -734,8 +784,27 @@ func apiRollbackSecret(lic *license.Manager) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if !requireRepoWrite(ctx) {
|
||||
return
|
||||
// Try Gitea user auth first, then fall back to vault token auth
|
||||
var userID int64
|
||||
if ctx.Doer != nil {
|
||||
if !ctx.Repo.CanWrite(unit.TypeCode) {
|
||||
ctx.JSON(http.StatusForbidden, map[string]any{
|
||||
"error": "forbidden",
|
||||
"message": "Repository write access required",
|
||||
})
|
||||
return
|
||||
}
|
||||
userID = ctx.Doer.ID
|
||||
} else {
|
||||
authResult := authenticateVaultToken(ctx, r, true)
|
||||
if !authResult.Success {
|
||||
ctx.JSON(http.StatusUnauthorized, map[string]any{
|
||||
"error": "unauthorized",
|
||||
"message": authResult.Error,
|
||||
})
|
||||
return
|
||||
}
|
||||
userID = 0
|
||||
}
|
||||
|
||||
name := chi.URLParam(r, "name")
|
||||
@@ -757,7 +826,7 @@ func apiRollbackSecret(lic *license.Manager) http.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
if err := services.RollbackSecret(ctx, ctx.Repo.Repository.ID, name, req.Version, ctx.Doer.ID); err != nil {
|
||||
if err := services.RollbackSecret(ctx, ctx.Repo.Repository.ID, name, req.Version, userID); err != nil {
|
||||
switch err {
|
||||
case services.ErrSecretNotFound:
|
||||
ctx.JSON(http.StatusNotFound, map[string]any{
|
||||
|
||||
Reference in New Issue
Block a user