Skip to content

Commit

Permalink
Deprecate query string auth tokens (go-gitea#28390)
Browse files Browse the repository at this point in the history
## Changes
- Add deprecation warning to `Token` and `AccessToken` authentication
methods in swagger.
- Add deprecation warning header to API response. Example: 
  ```
  HTTP/1.1 200 OK
  ...
  Warning: token and access_token API authentication is deprecated
  ...
  ```
- Add setting `DISABLE_QUERY_AUTH_TOKEN` to reject query string auth
tokens entirely. Default is `false`

## Next steps
- `DISABLE_QUERY_AUTH_TOKEN` should be true in a subsequent release and
the methods should be removed in swagger
- `DISABLE_QUERY_AUTH_TOKEN` should be removed and the implementation of
the auth methods in question should be removed

## Open questions
- Should there be further changes to the swagger documentation?
Deprecation is not yet supported for security definitions (coming in
[OpenAPI Spec version
3.2.0](OAI/OpenAPI-Specification#2506))
- Should the API router logger sanitize urls that use `token` or
`access_token`? (This is obviously an insufficient solution on its own)

---------

Co-authored-by: delvh <[email protected]>
  • Loading branch information
2 people authored and silverwind committed Feb 20, 2024
1 parent 8d04f18 commit b0fe88a
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 7 deletions.
5 changes: 5 additions & 0 deletions custom/conf/app.example.ini
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,11 @@ INTERNAL_TOKEN=
;; Cache successful token hashes. API tokens are stored in the DB as pbkdf2 hashes however, this means that there is a potentially significant hashing load when there are multiple API operations.
;; This cache will store the successfully hashed tokens in a LRU cache as a balance between performance and security.
;SUCCESSFUL_TOKENS_CACHE_SIZE = 20
;;
;; Reject API tokens sent in URL query string (Accept Header-based API tokens only). This avoids security vulnerabilities
;; stemming from cached/logged plain-text API tokens.
;; In future releases, this will become the default behavior
;DISABLE_QUERY_AUTH_TOKEN = false

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Expand Down
8 changes: 8 additions & 0 deletions modules/setting/security.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ var (
PasswordHashAlgo string
PasswordCheckPwn bool
SuccessfulTokensCacheSize int
DisableQueryAuthToken bool
CSRFCookieName = "_csrf"
CSRFCookieHTTPOnly = true
)
Expand Down Expand Up @@ -157,4 +158,11 @@ func loadSecurityFrom(rootCfg ConfigProvider) {
PasswordComplexity = append(PasswordComplexity, name)
}
}

// TODO: default value should be true in future releases
DisableQueryAuthToken = sec.Key("DISABLE_QUERY_AUTH_TOKEN").MustBool(false)

if !DisableQueryAuthToken {
log.Warn("Enabling Query API Auth tokens is not recommended. DISABLE_QUERY_AUTH_TOKEN will default to true in gitea 1.23 and will be removed in gitea 1.24.")
}
}
11 changes: 11 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@
// type: apiKey
// name: token
// in: query
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
// AccessToken:
// type: apiKey
// name: access_token
// in: query
// description: This authentication option is deprecated for removal in Gitea 1.23. Please use AuthorizationHeaderToken instead.
// AuthorizationHeaderToken:
// type: apiKey
// name: Authorization
Expand Down Expand Up @@ -788,6 +790,13 @@ func verifyAuthWithOptions(options *common.VerifyOptions) func(ctx *context.APIC
}
}

// check for and warn against deprecated authentication options
func checkDeprecatedAuthMethods(ctx *context.APIContext) {
if ctx.FormString("token") != "" || ctx.FormString("access_token") != "" {
ctx.Resp.Header().Set("Warning", "token and access_token API authentication is deprecated and will be removed in gitea 1.23. Please use AuthorizationHeaderToken instead. Existing queries will continue to work but without authorization.")
}
}

// Routes registers all v1 APIs routes to web application.
func Routes() *web.Route {
m := web.NewRoute()
Expand All @@ -806,6 +815,8 @@ func Routes() *web.Route {
}
m.Use(context.APIContexter())

m.Use(checkDeprecatedAuthMethods)

// Get user from session if logged in.
m.Use(apiAuth(buildAuthGroup()))

Expand Down
20 changes: 13 additions & 7 deletions services/auth/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
auth_model "code.gitea.io/gitea/models/auth"
user_model "code.gitea.io/gitea/models/user"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/auth/source/oauth2"
Expand Down Expand Up @@ -62,14 +63,19 @@ func (o *OAuth2) Name() string {
// representing whether the token exists or not
func parseToken(req *http.Request) (string, bool) {
_ = req.ParseForm()
// Check token.
if token := req.Form.Get("token"); token != "" {
return token, true
}
// Check access token.
if token := req.Form.Get("access_token"); token != "" {
return token, true
if !setting.DisableQueryAuthToken {
// Check token.
if token := req.Form.Get("token"); token != "" {
return token, true
}
// Check access token.
if token := req.Form.Get("access_token"); token != "" {
return token, true
}
} else if req.Form.Get("token") != "" || req.Form.Get("access_token") != "" {
log.Warn("API token sent in query string but DISABLE_QUERY_AUTH_TOKEN=true")
}

// check header token
if auHead := req.Header.Get("Authorization"); auHead != "" {
auths := strings.Fields(auHead)
Expand Down
2 changes: 2 additions & 0 deletions templates/swagger/v1_json.tmpl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit b0fe88a

Please sign in to comment.