Skip to content

Commit 9205c59

Browse files
authored
Merge branch 'main' into fix-regression-in-16544-openidconnect
2 parents cc2b851 + 06f8264 commit 9205c59

File tree

7 files changed

+80
-67
lines changed

7 files changed

+80
-67
lines changed

routers/web/repo/issue.go

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,9 +1727,12 @@ func UpdateIssueContent(ctx *context.Context) {
17271727
return
17281728
}
17291729

1730-
if err := updateAttachments(issue, ctx.FormStrings("files[]")); err != nil {
1731-
ctx.ServerError("UpdateAttachments", err)
1732-
return
1730+
// when update the request doesn't intend to update attachments (eg: change checkbox state), ignore attachment updates
1731+
if !ctx.FormBool("ignore_attachments") {
1732+
if err := updateAttachments(issue, ctx.FormStrings("files[]")); err != nil {
1733+
ctx.ServerError("UpdateAttachments", err)
1734+
return
1735+
}
17331736
}
17341737

17351738
content, err := markdown.RenderString(&markup.RenderContext{
@@ -2148,20 +2151,19 @@ func UpdateCommentContent(ctx *context.Context) {
21482151
return
21492152
}
21502153

2151-
if ctx.FormBool("ignore_attachments") {
2152-
return
2153-
}
2154-
21552154
if comment.Type == models.CommentTypeComment {
21562155
if err := comment.LoadAttachments(); err != nil {
21572156
ctx.ServerError("LoadAttachments", err)
21582157
return
21592158
}
21602159
}
21612160

2162-
if err := updateAttachments(comment, ctx.FormStrings("files[]")); err != nil {
2163-
ctx.ServerError("UpdateAttachments", err)
2164-
return
2161+
// when the update request doesn't intend to update attachments (eg: change checkbox state), ignore attachment updates
2162+
if !ctx.FormBool("ignore_attachments") {
2163+
if err := updateAttachments(comment, ctx.FormStrings("files[]")); err != nil {
2164+
ctx.ServerError("UpdateAttachments", err)
2165+
return
2166+
}
21652167
}
21662168

21672169
content, err := markdown.RenderString(&markup.RenderContext{

routers/web/user/oauth.go

Lines changed: 43 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -96,24 +96,6 @@ func (err AccessTokenError) Error() string {
9696
return fmt.Sprintf("%s: %s", err.ErrorCode, err.ErrorDescription)
9797
}
9898

99-
// BearerTokenErrorCode represents an error code specified in RFC 6750
100-
type BearerTokenErrorCode string
101-
102-
const (
103-
// BearerTokenErrorCodeInvalidRequest represents an error code specified in RFC 6750
104-
BearerTokenErrorCodeInvalidRequest BearerTokenErrorCode = "invalid_request"
105-
// BearerTokenErrorCodeInvalidToken represents an error code specified in RFC 6750
106-
BearerTokenErrorCodeInvalidToken BearerTokenErrorCode = "invalid_token"
107-
// BearerTokenErrorCodeInsufficientScope represents an error code specified in RFC 6750
108-
BearerTokenErrorCodeInsufficientScope BearerTokenErrorCode = "insufficient_scope"
109-
)
110-
111-
// BearerTokenError represents an error response specified in RFC 6750
112-
type BearerTokenError struct {
113-
ErrorCode BearerTokenErrorCode `json:"error" form:"error"`
114-
ErrorDescription string `json:"error_description"`
115-
}
116-
11799
// TokenType specifies the kind of token
118100
type TokenType string
119101

@@ -253,35 +235,56 @@ type userInfoResponse struct {
253235

254236
// InfoOAuth manages request for userinfo endpoint
255237
func InfoOAuth(ctx *context.Context) {
256-
header := ctx.Req.Header.Get("Authorization")
257-
auths := strings.Fields(header)
258-
if len(auths) != 2 || auths[0] != "Bearer" {
259-
ctx.HandleText(http.StatusUnauthorized, "no valid auth token authorization")
260-
return
261-
}
262-
uid := auth.CheckOAuthAccessToken(auths[1])
263-
if uid == 0 {
264-
handleBearerTokenError(ctx, BearerTokenError{
265-
ErrorCode: BearerTokenErrorCodeInvalidToken,
266-
ErrorDescription: "Access token not assigned to any user",
267-
})
268-
return
269-
}
270-
authUser, err := models.GetUserByID(uid)
271-
if err != nil {
272-
ctx.ServerError("GetUserByID", err)
238+
if ctx.User == nil || ctx.Data["AuthedMethod"] != (&auth.OAuth2{}).Name() {
239+
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
240+
ctx.HandleText(http.StatusUnauthorized, "no valid authorization")
273241
return
274242
}
275243
response := &userInfoResponse{
276-
Sub: fmt.Sprint(authUser.ID),
277-
Name: authUser.FullName,
278-
Username: authUser.Name,
279-
Email: authUser.Email,
280-
Picture: authUser.AvatarLink(),
244+
Sub: fmt.Sprint(ctx.User.ID),
245+
Name: ctx.User.FullName,
246+
Username: ctx.User.Name,
247+
Email: ctx.User.Email,
248+
Picture: ctx.User.AvatarLink(),
281249
}
282250
ctx.JSON(http.StatusOK, response)
283251
}
284252

253+
// IntrospectOAuth introspects an oauth token
254+
func IntrospectOAuth(ctx *context.Context) {
255+
if ctx.User == nil {
256+
ctx.Resp.Header().Set("WWW-Authenticate", `Bearer realm=""`)
257+
ctx.HandleText(http.StatusUnauthorized, "no valid authorization")
258+
return
259+
}
260+
261+
var response struct {
262+
Active bool `json:"active"`
263+
Scope string `json:"scope,omitempty"`
264+
jwt.StandardClaims
265+
}
266+
267+
form := web.GetForm(ctx).(*forms.IntrospectTokenForm)
268+
token, err := oauth2.ParseToken(form.Token)
269+
if err == nil {
270+
if token.Valid() == nil {
271+
grant, err := models.GetOAuth2GrantByID(token.GrantID)
272+
if err == nil && grant != nil {
273+
app, err := models.GetOAuth2ApplicationByID(grant.ApplicationID)
274+
if err == nil && app != nil {
275+
response.Active = true
276+
response.Scope = grant.Scope
277+
response.Issuer = setting.AppURL
278+
response.Audience = app.ClientID
279+
response.Subject = fmt.Sprint(grant.UserID)
280+
}
281+
}
282+
}
283+
}
284+
285+
ctx.JSON(http.StatusOK, response)
286+
}
287+
285288
// AuthorizeOAuth manages authorize requests
286289
func AuthorizeOAuth(ctx *context.Context) {
287290
form := web.GetForm(ctx).(*forms.AuthorizationForm)
@@ -697,18 +700,3 @@ func handleAuthorizeError(ctx *context.Context, authErr AuthorizeError, redirect
697700
redirect.RawQuery = q.Encode()
698701
ctx.Redirect(redirect.String(), 302)
699702
}
700-
701-
func handleBearerTokenError(ctx *context.Context, beErr BearerTokenError) {
702-
ctx.Resp.Header().Set("WWW-Authenticate", fmt.Sprintf("Bearer realm=\"\", error=\"%s\", error_description=\"%s\"", beErr.ErrorCode, beErr.ErrorDescription))
703-
switch beErr.ErrorCode {
704-
case BearerTokenErrorCodeInvalidRequest:
705-
ctx.JSON(http.StatusBadRequest, beErr)
706-
case BearerTokenErrorCodeInvalidToken:
707-
ctx.JSON(http.StatusUnauthorized, beErr)
708-
case BearerTokenErrorCodeInsufficientScope:
709-
ctx.JSON(http.StatusForbidden, beErr)
710-
default:
711-
log.Error("Invalid BearerTokenErrorCode: %v", beErr.ErrorCode)
712-
ctx.ServerError("Unhandled BearerTokenError", fmt.Errorf("BearerTokenError: error=\"%v\", error_description=\"%v\"", beErr.ErrorCode, beErr.ErrorDescription))
713-
}
714-
}

routers/web/web.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,7 @@ func RegisterRoutes(m *web.Route) {
311311
m.Get("/login/oauth/userinfo", ignSignInAndCsrf, user.InfoOAuth)
312312
m.Post("/login/oauth/access_token", CorsHandler(), bindIgnErr(forms.AccessTokenForm{}), ignSignInAndCsrf, user.AccessTokenOAuth)
313313
m.Get("/login/oauth/keys", ignSignInAndCsrf, user.OIDCKeys)
314+
m.Post("/login/oauth/introspect", CorsHandler(), bindIgnErr(forms.IntrospectTokenForm{}), ignSignInAndCsrf, user.IntrospectOAuth)
314315

315316
m.Group("/user/settings", func() {
316317
m.Get("", userSetting.Profile)

services/auth/oauth2.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
113113
return nil
114114
}
115115

116-
if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) {
116+
if !middleware.IsAPIPath(req) && !isAttachmentDownload(req) && !isAuthenticatedTokenRequest(req) {
117117
return nil
118118
}
119119

@@ -134,3 +134,13 @@ func (o *OAuth2) Verify(req *http.Request, w http.ResponseWriter, store DataStor
134134
log.Trace("OAuth2 Authorization: Logged in user %-v", user)
135135
return user
136136
}
137+
138+
func isAuthenticatedTokenRequest(req *http.Request) bool {
139+
switch req.URL.Path {
140+
case "/login/oauth/userinfo":
141+
fallthrough
142+
case "/login/oauth/introspect":
143+
return true
144+
}
145+
return false
146+
}

services/forms/user_form.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,17 @@ func (f *AccessTokenForm) Validate(req *http.Request, errs binding.Errors) bindi
215215
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
216216
}
217217

218+
// IntrospectTokenForm for introspecting tokens
219+
type IntrospectTokenForm struct {
220+
Token string `json:"token"`
221+
}
222+
223+
// Validate validates the fields
224+
func (f *IntrospectTokenForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
225+
ctx := context.GetContext(req)
226+
return middleware.Validate(errs, ctx.Data, f, ctx.Locale)
227+
}
228+
218229
// __________________________________________.___ _______ ________ _________
219230
// / _____/\_ _____/\__ ___/\__ ___/| |\ \ / _____/ / _____/
220231
// \_____ \ | __)_ | | | | | |/ | \/ \ ___ \_____ \

templates/repo/issue/view_content/sidebar.tmpl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@
490490
{{range .BlockedByDependencies}}
491491
<div class="item dependency{{if .Issue.IsClosed}} is-closed{{end}} df ac sb">
492492
<div class="item-left df jc fc f1">
493-
<a class="title" href="{{.Repository.Link}}/issues/{{.Issue.Index}}">
493+
<a class="title" href="{{.Repository.Link}}/{{if .Issue.IsPull}}pulls{{else}}issues{{end}}/{{.Issue.Index}}">
494494
#{{.Issue.Index}} {{.Issue.Title | RenderEmoji}}
495495
</a>
496496
<div class="text small">

templates/user/auth/oidc_wellknown.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"token_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/access_token",
55
"jwks_uri": "{{AppUrl | JSEscape | Safe}}login/oauth/keys",
66
"userinfo_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/userinfo",
7+
"introspection_endpoint": "{{AppUrl | JSEscape | Safe}}login/oauth/introspect",
78
"response_types_supported": [
89
"code",
910
"id_token"

0 commit comments

Comments
 (0)