Skip to content

Commit

Permalink
Merge remote-tracking branch 'giteaofficial/main'
Browse files Browse the repository at this point in the history
* giteaofficial/main:
  fix redis dep (go-gitea#31662)
  add skip secondary authorization option for public oauth2 clients (go-gitea#31454)
  Fix a branch divergence cache bug (go-gitea#31659)
  • Loading branch information
zjjhot committed Jul 20, 2024
2 parents 4cc97a7 + ba9589a commit 7bb635e
Show file tree
Hide file tree
Showing 19 changed files with 148 additions and 67 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ require (
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.19.1
github.com/quasoft/websspi v1.1.2
github.com/redis/go-redis/v9 v9.5.3
github.com/redis/go-redis/v9 v9.6.0
github.com/robfig/cron/v3 v3.0.1
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
github.com/sassoftware/go-rpmutils v0.4.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -668,8 +668,8 @@ github.com/prometheus/procfs v0.13.0/go.mod h1:cd4PFCR54QLnGKPaKGA6l+cfuNXtht43Z
github.com/quasoft/websspi v1.1.2 h1:/mA4w0LxWlE3novvsoEL6BBA1WnjJATbjkh1kFrTidw=
github.com/quasoft/websspi v1.1.2/go.mod h1:HmVdl939dQ0WIXZhyik+ARdI03M6bQzaSEKcgpFmewk=
github.com/rcrowley/go-metrics v0.0.0-20190826022208-cac0b30c2563/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/redis/go-redis/v9 v9.6.0 h1:NLck+Rab3AOTHw21CGRpvQpgTrAU4sgdCswqGtlhGRA=
github.com/redis/go-redis/v9 v9.6.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rhysd/actionlint v1.7.1 h1:WJaDzyT1StBWVKGSsZPYnbV0HF9Y9/vD6KFdZQL42qE=
Expand Down
43 changes: 24 additions & 19 deletions models/auth/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,11 @@ type OAuth2Application struct {
// https://datatracker.ietf.org/doc/html/rfc6749#section-2.1
// "Authorization servers MUST record the client type in the client registration details"
// https://datatracker.ietf.org/doc/html/rfc8252#section-8.4
ConfidentialClient bool `xorm:"NOT NULL DEFAULT TRUE"`
RedirectURIs []string `xorm:"redirect_uris JSON TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
ConfidentialClient bool `xorm:"NOT NULL DEFAULT TRUE"`
SkipSecondaryAuthorization bool `xorm:"NOT NULL DEFAULT FALSE"`
RedirectURIs []string `xorm:"redirect_uris JSON TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"INDEX created"`
UpdatedUnix timeutil.TimeStamp `xorm:"INDEX updated"`
}

func init() {
Expand Down Expand Up @@ -251,21 +252,23 @@ func GetOAuth2ApplicationByID(ctx context.Context, id int64) (app *OAuth2Applica

// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
type CreateOAuth2ApplicationOptions struct {
Name string
UserID int64
ConfidentialClient bool
RedirectURIs []string
Name string
UserID int64
ConfidentialClient bool
SkipSecondaryAuthorization bool
RedirectURIs []string
}

// CreateOAuth2Application inserts a new oauth2 application
func CreateOAuth2Application(ctx context.Context, opts CreateOAuth2ApplicationOptions) (*OAuth2Application, error) {
clientID := uuid.New().String()
app := &OAuth2Application{
UID: opts.UserID,
Name: opts.Name,
ClientID: clientID,
RedirectURIs: opts.RedirectURIs,
ConfidentialClient: opts.ConfidentialClient,
UID: opts.UserID,
Name: opts.Name,
ClientID: clientID,
RedirectURIs: opts.RedirectURIs,
ConfidentialClient: opts.ConfidentialClient,
SkipSecondaryAuthorization: opts.SkipSecondaryAuthorization,
}
if err := db.Insert(ctx, app); err != nil {
return nil, err
Expand All @@ -275,11 +278,12 @@ func CreateOAuth2Application(ctx context.Context, opts CreateOAuth2ApplicationOp

// UpdateOAuth2ApplicationOptions holds options to update an oauth2 application
type UpdateOAuth2ApplicationOptions struct {
ID int64
Name string
UserID int64
ConfidentialClient bool
RedirectURIs []string
ID int64
Name string
UserID int64
ConfidentialClient bool
SkipSecondaryAuthorization bool
RedirectURIs []string
}

// UpdateOAuth2Application updates an oauth2 application
Expand All @@ -305,6 +309,7 @@ func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOp
app.Name = opts.Name
app.RedirectURIs = opts.RedirectURIs
app.ConfidentialClient = opts.ConfidentialClient
app.SkipSecondaryAuthorization = opts.SkipSecondaryAuthorization

if err = updateOAuth2Application(ctx, app); err != nil {
return nil, err
Expand All @@ -315,7 +320,7 @@ func UpdateOAuth2Application(ctx context.Context, opts UpdateOAuth2ApplicationOp
}

func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error {
if _, err := db.GetEngine(ctx).ID(app.ID).UseBool("confidential_client").Update(app); err != nil {
if _, err := db.GetEngine(ctx).ID(app.ID).UseBool("confidential_client", "skip_secondary_authorization").Update(app); err != nil {
return err
}
return nil
Expand Down
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,8 @@ var migrations = []Migration{
NewMigration("Add content version to issue and comment table", v1_23.AddContentVersionToIssueAndComment),
// v300 -> v301
NewMigration("Add force-push branch protection support", v1_23.AddForcePushBranchProtection),
// v301 -> v302
NewMigration("Add skip_secondary_authorization option to oauth2 application table", v1_23.AddSkipSecondaryAuthColumnToOAuth2ApplicationTable),
}

// GetCurrentDBVersion returns the current db version
Expand Down
14 changes: 14 additions & 0 deletions models/migrations/v1_23/v301.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright 2024 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_23 //nolint

import "xorm.io/xorm"

// AddSkipSeconderyAuthToOAuth2ApplicationTable: add SkipSecondaryAuthorization column, setting existing rows to false
func AddSkipSecondaryAuthColumnToOAuth2ApplicationTable(x *xorm.Engine) error {
type oauth2Application struct {
SkipSecondaryAuthorization bool `xorm:"NOT NULL DEFAULT FALSE"`
}
return x.Sync(new(oauth2Application))
}
22 changes: 12 additions & 10 deletions modules/structs/user_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,23 @@ type CreateAccessTokenOption struct {

// CreateOAuth2ApplicationOptions holds options to create an oauth2 application
type CreateOAuth2ApplicationOptions struct {
Name string `json:"name" binding:"Required"`
ConfidentialClient bool `json:"confidential_client"`
RedirectURIs []string `json:"redirect_uris" binding:"Required"`
Name string `json:"name" binding:"Required"`
ConfidentialClient bool `json:"confidential_client"`
SkipSecondaryAuthorization bool `json:"skip_secondary_authorization"`
RedirectURIs []string `json:"redirect_uris" binding:"Required"`
}

// OAuth2Application represents an OAuth2 application.
// swagger:response OAuth2Application
type OAuth2Application struct {
ID int64 `json:"id"`
Name string `json:"name"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
ConfidentialClient bool `json:"confidential_client"`
RedirectURIs []string `json:"redirect_uris"`
Created time.Time `json:"created"`
ID int64 `json:"id"`
Name string `json:"name"`
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
ConfidentialClient bool `json:"confidential_client"`
SkipSecondaryAuthorization bool `json:"skip_secondary_authorization"`
RedirectURIs []string `json:"redirect_uris"`
Created time.Time `json:"created"`
}

// OAuth2ApplicationList represents a list of OAuth2 applications.
Expand Down
1 change: 1 addition & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ create_oauth2_application_success = You have successfully created a new OAuth2 a
update_oauth2_application_success = You have successfully updated the OAuth2 application.
oauth2_application_name = Application Name
oauth2_confidential_client = Confidential Client. Select for apps that keep the secret confidential, such as web apps. Do not select for native apps including desktop and mobile apps.
oauth2_skip_secondary_authorization = Skip authorization for public clients after granting access once. <strong>May pose a security risk.</strong>
oauth2_redirect_uris = Redirect URIs. Please use a new line for every URI.
save_application = Save
oauth2_client_id = Client ID
Expand Down
20 changes: 11 additions & 9 deletions routers/api/v1/user/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,10 +223,11 @@ func CreateOauth2Application(ctx *context.APIContext) {
data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions)

app, err := auth_model.CreateOAuth2Application(ctx, auth_model.CreateOAuth2ApplicationOptions{
Name: data.Name,
UserID: ctx.Doer.ID,
RedirectURIs: data.RedirectURIs,
ConfidentialClient: data.ConfidentialClient,
Name: data.Name,
UserID: ctx.Doer.ID,
RedirectURIs: data.RedirectURIs,
ConfidentialClient: data.ConfidentialClient,
SkipSecondaryAuthorization: data.SkipSecondaryAuthorization,
})
if err != nil {
ctx.Error(http.StatusBadRequest, "", "error creating oauth2 application")
Expand Down Expand Up @@ -381,11 +382,12 @@ func UpdateOauth2Application(ctx *context.APIContext) {
data := web.GetForm(ctx).(*api.CreateOAuth2ApplicationOptions)

app, err := auth_model.UpdateOAuth2Application(ctx, auth_model.UpdateOAuth2ApplicationOptions{
Name: data.Name,
UserID: ctx.Doer.ID,
ID: appID,
RedirectURIs: data.RedirectURIs,
ConfidentialClient: data.ConfidentialClient,
Name: data.Name,
UserID: ctx.Doer.ID,
ID: appID,
RedirectURIs: data.RedirectURIs,
ConfidentialClient: data.ConfidentialClient,
SkipSecondaryAuthorization: data.SkipSecondaryAuthorization,
})
if err != nil {
if auth_model.IsErrOauthClientIDInvalid(err) || auth_model.IsErrOAuthApplicationNotFound(err) {
Expand Down
6 changes: 3 additions & 3 deletions routers/web/auth/oauth.go
Original file line number Diff line number Diff line change
Expand Up @@ -469,9 +469,9 @@ func AuthorizeOAuth(ctx *context.Context) {
return
}

// Redirect if user already granted access and the application is confidential.
// I.e. always require authorization for public clients as recommended by RFC 6749 Section 10.2
if app.ConfidentialClient && grant != nil {
// Redirect if user already granted access and the application is confidential or trusted otherwise
// I.e. always require authorization for untrusted public clients as recommended by RFC 6749 Section 10.2
if (app.ConfidentialClient || app.SkipSecondaryAuthorization) && grant != nil {
code, err := grant.GenerateNewAuthorizationCode(ctx, form.RedirectURI, form.CodeChallenge, form.CodeChallengeMethod)
if err != nil {
handleServerError(ctx, form.State, form.RedirectURI)
Expand Down
20 changes: 11 additions & 9 deletions routers/web/user/setting/oauth2_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) {

// TODO validate redirect URI
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
Name: form.Name,
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
UserID: oa.OwnerID,
ConfidentialClient: form.ConfidentialClient,
Name: form.Name,
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
UserID: oa.OwnerID,
ConfidentialClient: form.ConfidentialClient,
SkipSecondaryAuthorization: form.SkipSecondaryAuthorization,
})
if err != nil {
ctx.ServerError("CreateOAuth2Application", err)
Expand Down Expand Up @@ -102,11 +103,12 @@ func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) {
// TODO validate redirect URI
var err error
if ctx.Data["App"], err = auth.UpdateOAuth2Application(ctx, auth.UpdateOAuth2ApplicationOptions{
ID: ctx.PathParamInt64("id"),
Name: form.Name,
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
UserID: oa.OwnerID,
ConfidentialClient: form.ConfidentialClient,
ID: ctx.PathParamInt64("id"),
Name: form.Name,
RedirectURIs: util.SplitTrimSpace(form.RedirectURIs, "\n"),
UserID: oa.OwnerID,
ConfidentialClient: form.ConfidentialClient,
SkipSecondaryAuthorization: form.SkipSecondaryAuthorization,
}); err != nil {
ctx.ServerError("UpdateOAuth2Application", err)
return
Expand Down
15 changes: 8 additions & 7 deletions services/convert/convert.go
Original file line number Diff line number Diff line change
Expand Up @@ -455,13 +455,14 @@ func ToTopicResponse(topic *repo_model.Topic) *api.TopicResponse {
// ToOAuth2Application convert from auth.OAuth2Application to api.OAuth2Application
func ToOAuth2Application(app *auth.OAuth2Application) *api.OAuth2Application {
return &api.OAuth2Application{
ID: app.ID,
Name: app.Name,
ClientID: app.ClientID,
ClientSecret: app.ClientSecret,
ConfidentialClient: app.ConfidentialClient,
RedirectURIs: app.RedirectURIs,
Created: app.CreatedUnix.AsTime(),
ID: app.ID,
Name: app.Name,
ClientID: app.ClientID,
ClientSecret: app.ClientSecret,
ConfidentialClient: app.ConfidentialClient,
SkipSecondaryAuthorization: app.SkipSecondaryAuthorization,
RedirectURIs: app.RedirectURIs,
Created: app.CreatedUnix.AsTime(),
}
}

Expand Down
7 changes: 4 additions & 3 deletions services/forms/user_form.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,9 +365,10 @@ func (f *NewAccessTokenForm) GetScope() (auth_model.AccessTokenScope, error) {

// EditOAuth2ApplicationForm form for editing oauth2 applications
type EditOAuth2ApplicationForm struct {
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
RedirectURIs string `binding:"Required" form:"redirect_uris"`
ConfidentialClient bool `form:"confidential_client"`
Name string `binding:"Required;MaxSize(255)" form:"application_name"`
RedirectURIs string `binding:"Required" form:"redirect_uris"`
ConfidentialClient bool `form:"confidential_client"`
SkipSecondaryAuthorization bool `form:"skip_secondary_authorization"`
}

// Validate validates the fields
Expand Down
17 changes: 17 additions & 0 deletions services/repository/branch.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,23 @@ func DelDivergenceFromCache(repoID int64, branchName string) error {
return cache.GetCache().Delete(getDivergenceCacheKey(repoID, branchName))
}

// DelRepoDivergenceFromCache deletes all divergence caches of a repository
func DelRepoDivergenceFromCache(ctx context.Context, repoID int64) error {
dbBranches, err := db.Find[git_model.Branch](ctx, git_model.FindBranchOptions{
RepoID: repoID,
ListOptions: db.ListOptionsAll,
})
if err != nil {
return err
}
for i := range dbBranches {
if err := DelDivergenceFromCache(repoID, dbBranches[i].Name); err != nil {
log.Error("DelDivergenceFromCache: %v", err)
}
}
return nil
}

func loadOneBranch(ctx context.Context, repo *repo_model.Repository, dbBranch *git_model.Branch, protectedBranches *git_model.ProtectedBranchRules,
repoIDToRepo map[int64]*repo_model.Repository,
repoIDToGitRepo map[int64]*git.Repository,
Expand Down
10 changes: 8 additions & 2 deletions services/repository/push.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,8 +221,14 @@ func pushUpdates(optsList []*repo_module.PushUpdateOptions) error {
}

// delete cache for divergence
if err := DelDivergenceFromCache(repo.ID, branch); err != nil {
log.Error("DelDivergenceFromCache: %v", err)
if branch == repo.DefaultBranch {
if err := DelRepoDivergenceFromCache(ctx, repo.ID); err != nil {
log.Error("DelRepoDivergenceFromCache: %v", err)
}
} else {
if err := DelDivergenceFromCache(repo.ID, branch); err != nil {
log.Error("DelDivergenceFromCache: %v", err)
}
}

commits := repo_module.GitToPushCommits(l)
Expand Down
8 changes: 8 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.

8 changes: 7 additions & 1 deletion templates/user/settings/applications_oauth2_edit_form.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,13 @@
<div class="field {{if .Err_ConfidentialClient}}error{{end}}">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label>
<input type="checkbox" name="confidential_client" {{if .App.ConfidentialClient}}checked{{end}}>
<input class="disable-setting" type="checkbox" name="confidential_client" data-target="#skip-secondary-authorization" {{if .App.ConfidentialClient}}checked{{end}}>
</div>
</div>
<div class="field {{if .Err_SkipSecondaryAuthorization}}error{{end}} {{if .App.ConfidentialClient}}disabled{{end}}" id="skip-secondary-authorization">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "settings.oauth2_skip_secondary_authorization"}}</label>
<input type="checkbox" name="skip_secondary_authorization" {{if .App.SkipSecondaryAuthorization}}checked{{end}}>
</div>
</div>
<button class="ui primary button">
Expand Down
8 changes: 7 additions & 1 deletion templates/user/settings/applications_oauth2_list.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,13 @@
<div class="field {{if .Err_ConfidentialClient}}error{{end}}">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "settings.oauth2_confidential_client"}}</label>
<input type="checkbox" name="confidential_client" checked>
<input class="disable-setting" type="checkbox" name="confidential_client" data-target="#skip-secondary-authorization" checked>
</div>
</div>
<div class="field {{if .Err_SkipSecondaryAuthorization}}error{{end}} disabled" id="skip-secondary-authorization">
<div class="ui checkbox">
<label>{{ctx.Locale.Tr "settings.oauth2_skip_secondary_authorization"}}</label>
<input type="checkbox" name="skip_secondary_authorization">
</div>
</div>
<button class="ui primary button">
Expand Down
5 changes: 5 additions & 0 deletions web_src/js/features/oauth2-settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function initOAuth2SettingsDisableCheckbox() {
for (const e of document.querySelectorAll('.disable-setting')) e.addEventListener('change', ({target}) => {
document.querySelector(e.getAttribute('data-target')).classList.toggle('disabled', target.checked);
});
}
Loading

0 comments on commit 7bb635e

Please sign in to comment.