Skip to content

Commit

Permalink
incorporate logic into userIDFromToken instead of a standalone function
Browse files Browse the repository at this point in the history
  • Loading branch information
bohde committed Nov 19, 2024
1 parent 91b01ea commit 6e876cc
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 49 deletions.
11 changes: 8 additions & 3 deletions services/actions/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,12 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
return 0, fmt.Errorf("split token failed")
}

token, err := jwt.ParseWithClaims(parts[1], &actionsClaims{}, func(t *jwt.Token) (any, error) {
return TokenToTaskID(parts[1])
}

// TokenToTaskID returns the TaskID associated with the provided JWT token
func TokenToTaskID(token string) (int64, error) {
parsedToken, err := jwt.ParseWithClaims(token, &actionsClaims{}, func(t *jwt.Token) (any, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
}
Expand All @@ -93,8 +98,8 @@ func ParseAuthorizationToken(req *http.Request) (int64, error) {
return 0, err
}

c, ok := token.Claims.(*actionsClaims)
if !token.Valid || !ok {
c, ok := parsedToken.Claims.(*actionsClaims)
if !parsedToken.Valid || !ok {
return 0, fmt.Errorf("invalid token claim")
}

Expand Down
69 changes: 23 additions & 46 deletions services/auth/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package auth

import (
"context"
"errors"
"net/http"
"strings"
"time"
Expand All @@ -17,7 +16,6 @@ import (
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/modules/web/middleware"
"code.gitea.io/gitea/services/actions"
"code.gitea.io/gitea/services/oauth2_provider"
Expand Down Expand Up @@ -57,6 +55,18 @@ func CheckOAuthAccessToken(ctx context.Context, accessToken string) int64 {
return grant.UserID
}

// CheckTaskID verifies that the TaskID corresponds to a running task
func CheckTaskID(ctx context.Context, taskID int64) bool {
// Verify the task exists
task, err := actions_model.GetTaskByID(ctx, taskID)
if err != nil {
return false
}

// Verify that it's running
return task.Status == actions_model.StatusRunning
}

// OAuth2 implements the Auth interface and authenticates requests
// (API requests only) by looking for an OAuth token in query parameters or the
// "Authorization" header.
Expand Down Expand Up @@ -100,6 +110,16 @@ func parseToken(req *http.Request) (string, bool) {
func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store DataStore) int64 {
// Let's see if token is valid.
if strings.Contains(tokenSHA, ".") {
// First attempt to decode an actions JWT, returning the actions user
if taskID, err := actions.TokenToTaskID(tokenSHA); err == nil {
if CheckTaskID(ctx, taskID) {
store.GetData()["IsActionsToken"] = true
store.GetData()["ActionsTaskID"] = taskID
return user_model.ActionsUserID
}
}

// Otherwise, check if this is an OAuth access token
uid := CheckOAuthAccessToken(ctx, tokenSHA)
if uid != 0 {
store.GetData()["IsApiToken"] = true
Expand Down Expand Up @@ -134,40 +154,6 @@ func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store Dat
return t.UID
}

// parseActionJWT identifies actions runner JWTs that look like an
// OAuth token, but needs to be parsed by its code
func parseActionsJWT(req *http.Request, store DataStore) (*user_model.User, error) {
taskID, err := actions.ParseAuthorizationToken(req)
if err != nil || taskID == 0 {
return nil, nil
}

// Verify the task exists
task, err := actions_model.GetTaskByID(req.Context(), taskID)
if err != nil {
if errors.Is(err, util.ErrNotExist) {
return nil, nil
}

return nil, err
}

// Verify that it's running
if task.Status != actions_model.StatusRunning {
return nil, nil
}

store.GetData()["IsActionsToken"] = true
store.GetData()["ActionsTaskID"] = taskID

user, err := user_model.GetPossibleUserByID(req.Context(), user_model.ActionsUserID)
if err != nil {
return nil, err
}

return user, nil
}

// Verify extracts the user ID from the OAuth token in the query parameters
// or the "Authorization" header and returns the corresponding user object for that ID.
// If verification is successful returns an existing user object.
Expand All @@ -179,15 +165,6 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
return nil, nil
}

user, err := parseActionsJWT(req, store)
if err != nil {
return nil, err
}

if user != nil {
return user, nil
}

token, ok := parseToken(req)
if !ok {
return nil, nil
Expand All @@ -200,7 +177,7 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
}
log.Trace("OAuth2 Authorization: Found token for user[%d]", id)

user, err = user_model.GetPossibleUserByID(req.Context(), id)
user, err := user_model.GetPossibleUserByID(req.Context(), id)
if err != nil {
if !user_model.IsErrUserNotExist(err) {
log.Error("GetUserByName: %v", err)
Expand Down

0 comments on commit 6e876cc

Please sign in to comment.