Skip to content

Commit 91b01ea

Browse files
committed
allow the actions user to login via the jwt token
The format of the env var `ACTIONS_RUNTIME_TOKEN` in actions jobs changed with /pull/28885 to be a JWT. Since it was a JWT, the OAuth parsing logic attempted to parse it as an OAuth token, and would return user not found, instead of falling back to look up the running task and assigning it to the actions user. This restores that functionality by parsing Actions JWTs first, and then attempting to parse OAUTH JWTs. The code to parse potential old `ACTION_RUNTIME_TOKEN` was kept in case someone is running an older version of act_runner that doesn't support the Actions JWT.
1 parent e546480 commit 91b01ea

File tree

1 file changed

+47
-1
lines changed

1 file changed

+47
-1
lines changed

services/auth/oauth2.go

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package auth
66

77
import (
88
"context"
9+
"errors"
910
"net/http"
1011
"strings"
1112
"time"
@@ -16,7 +17,9 @@ import (
1617
"code.gitea.io/gitea/modules/log"
1718
"code.gitea.io/gitea/modules/setting"
1819
"code.gitea.io/gitea/modules/timeutil"
20+
"code.gitea.io/gitea/modules/util"
1921
"code.gitea.io/gitea/modules/web/middleware"
22+
"code.gitea.io/gitea/services/actions"
2023
"code.gitea.io/gitea/services/oauth2_provider"
2124
)
2225

@@ -131,6 +134,40 @@ func (o *OAuth2) userIDFromToken(ctx context.Context, tokenSHA string, store Dat
131134
return t.UID
132135
}
133136

137+
// parseActionJWT identifies actions runner JWTs that look like an
138+
// OAuth token, but needs to be parsed by its code
139+
func parseActionsJWT(req *http.Request, store DataStore) (*user_model.User, error) {
140+
taskID, err := actions.ParseAuthorizationToken(req)
141+
if err != nil || taskID == 0 {
142+
return nil, nil
143+
}
144+
145+
// Verify the task exists
146+
task, err := actions_model.GetTaskByID(req.Context(), taskID)
147+
if err != nil {
148+
if errors.Is(err, util.ErrNotExist) {
149+
return nil, nil
150+
}
151+
152+
return nil, err
153+
}
154+
155+
// Verify that it's running
156+
if task.Status != actions_model.StatusRunning {
157+
return nil, nil
158+
}
159+
160+
store.GetData()["IsActionsToken"] = true
161+
store.GetData()["ActionsTaskID"] = taskID
162+
163+
user, err := user_model.GetPossibleUserByID(req.Context(), user_model.ActionsUserID)
164+
if err != nil {
165+
return nil, err
166+
}
167+
168+
return user, nil
169+
}
170+
134171
// Verify extracts the user ID from the OAuth token in the query parameters
135172
// or the "Authorization" header and returns the corresponding user object for that ID.
136173
// If verification is successful returns an existing user object.
@@ -142,6 +179,15 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
142179
return nil, nil
143180
}
144181

182+
user, err := parseActionsJWT(req, store)
183+
if err != nil {
184+
return nil, err
185+
}
186+
187+
if user != nil {
188+
return user, nil
189+
}
190+
145191
token, ok := parseToken(req)
146192
if !ok {
147193
return nil, nil
@@ -154,7 +200,7 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
154200
}
155201
log.Trace("OAuth2 Authorization: Found token for user[%d]", id)
156202

157-
user, err := user_model.GetPossibleUserByID(req.Context(), id)
203+
user, err = user_model.GetPossibleUserByID(req.Context(), id)
158204
if err != nil {
159205
if !user_model.IsErrUserNotExist(err) {
160206
log.Error("GetUserByName: %v", err)

0 commit comments

Comments
 (0)