[SEC] Ensure propagation of API scopes for Conan and Container authentication
- The Conan and Container packages use a different type of authentication. It first authenticates via the regular way (api tokens or user:password, handled via `auth.Basic`) and then generates a JWT token that is used by the package software (such as Docker) to do the action they wanted to do. This JWT token didn't properly propagate the API scopes that the token was generated for, and thus could lead to a 'scope escalation' within the Conan and Container packages, read access to write access. - Store the API scope in the JWT token, so it can be propagated on subsequent calls that uses that JWT token. - Integration test added. - Resolves #5128
This commit is contained in:
parent
8d0530650e
commit
5a871f6095
8 changed files with 151 additions and 12 deletions
|
@ -22,7 +22,7 @@ func (a *Auth) Name() string {
|
|||
|
||||
// Verify extracts the user from the Bearer token
|
||||
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
|
||||
uid, err := packages.ParseAuthorizationToken(req)
|
||||
uid, scope, err := packages.ParseAuthorizationToken(req)
|
||||
if err != nil {
|
||||
log.Trace("ParseAuthorizationToken: %v", err)
|
||||
return nil, err
|
||||
|
@ -32,6 +32,12 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Propagate scope of the authorization token.
|
||||
if scope != "" {
|
||||
store.GetData()["IsApiToken"] = true
|
||||
store.GetData()["ApiTokenScope"] = scope
|
||||
}
|
||||
|
||||
u, err := user_model.GetUserByID(req.Context(), uid)
|
||||
if err != nil {
|
||||
log.Error("GetUserByID: %v", err)
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/models/db"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
conan_model "code.gitea.io/gitea/models/packages/conan"
|
||||
|
@ -117,7 +118,10 @@ func Authenticate(ctx *context.Context) {
|
|||
return
|
||||
}
|
||||
|
||||
token, err := packages_service.CreateAuthorizationToken(ctx.Doer)
|
||||
// If there's an API scope, ensure it propagates.
|
||||
scope, _ := ctx.Data.GetData()["ApiTokenScope"].(auth_model.AccessTokenScope)
|
||||
|
||||
token, err := packages_service.CreateAuthorizationToken(ctx.Doer, scope)
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
|
@ -23,7 +23,7 @@ func (a *Auth) Name() string {
|
|||
// Verify extracts the user from the Bearer token
|
||||
// If it's an anonymous session a ghost user is returned
|
||||
func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataStore, sess auth.SessionStore) (*user_model.User, error) {
|
||||
uid, err := packages.ParseAuthorizationToken(req)
|
||||
uid, scope, err := packages.ParseAuthorizationToken(req)
|
||||
if err != nil {
|
||||
log.Trace("ParseAuthorizationToken: %v", err)
|
||||
return nil, err
|
||||
|
@ -33,6 +33,12 @@ func (a *Auth) Verify(req *http.Request, w http.ResponseWriter, store auth.DataS
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// Propagate scope of the authorization token.
|
||||
if scope != "" {
|
||||
store.GetData()["IsApiToken"] = true
|
||||
store.GetData()["ApiTokenScope"] = scope
|
||||
}
|
||||
|
||||
u, err := user_model.GetPossibleUserByID(req.Context(), uid)
|
||||
if err != nil {
|
||||
log.Error("GetPossibleUserByID: %v", err)
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"strconv"
|
||||
"strings"
|
||||
|
||||
auth_model "code.gitea.io/gitea/models/auth"
|
||||
packages_model "code.gitea.io/gitea/models/packages"
|
||||
container_model "code.gitea.io/gitea/models/packages/container"
|
||||
user_model "code.gitea.io/gitea/models/user"
|
||||
|
@ -154,7 +155,10 @@ func Authenticate(ctx *context.Context) {
|
|||
u = user_model.NewGhostUser()
|
||||
}
|
||||
|
||||
token, err := packages_service.CreateAuthorizationToken(u)
|
||||
// If there's an API scope, ensure it propagates.
|
||||
scope, _ := ctx.Data["ApiTokenScope"].(auth_model.AccessTokenScope)
|
||||
|
||||
token, err := packages_service.CreateAuthorizationToken(u, scope)
|
||||
if err != nil {
|
||||
apiError(ctx, http.StatusInternalServerError, err)
|
||||
return
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue