Skip to content

Commit a813c9d

Browse files
Allow creation of OAuth2 applications for orgs (#18084)
Adds the settings pages to create OAuth2 apps also to the org settings and allows to create apps for orgs. Refactoring: the oauth2 related templates are shared for instance-wide/org/user, and the backend code uses `OAuth2CommonHandlers` to share code for instance-wide/org/user. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
1 parent 97f3f19 commit a813c9d

15 files changed

+439
-235
lines changed

assets/go-licenses.json

Lines changed: 10 additions & 0 deletions
Large diffs are not rendered by default.

models/auth/oauth2.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,8 @@ func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error
225225

226226
func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
227227
sess := db.GetEngine(ctx)
228-
if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil {
228+
// the userid could be 0 if the app is instance-wide
229+
if deleted, err := sess.Where(builder.Eq{"id": id, "uid": userid}).Delete(&OAuth2Application{}); err != nil {
229230
return err
230231
} else if deleted == 0 {
231232
return ErrOAuthApplicationNotFound{ID: id}
@@ -476,7 +477,7 @@ func GetOAuth2GrantsByUserID(ctx context.Context, uid int64) ([]*OAuth2Grant, er
476477

477478
// RevokeOAuth2Grant deletes the grant with grantID and userID
478479
func RevokeOAuth2Grant(ctx context.Context, grantID, userID int64) error {
479-
_, err := db.DeleteByBean(ctx, &OAuth2Grant{ID: grantID, UserID: userID})
480+
_, err := db.GetEngine(ctx).Where(builder.Eq{"id": grantID, "user_id": userID}).Delete(&OAuth2Grant{})
480481
return err
481482
}
482483

routers/web/org/setting_oauth2.go

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// Copyright 2022 The Gitea Authors. All rights reserved.
2+
// Use of this source code is governed by a MIT-style
3+
// license that can be found in the LICENSE file.
4+
5+
package org
6+
7+
import (
8+
"fmt"
9+
"net/http"
10+
11+
"code.gitea.io/gitea/models/auth"
12+
"code.gitea.io/gitea/modules/base"
13+
"code.gitea.io/gitea/modules/context"
14+
"code.gitea.io/gitea/modules/setting"
15+
user_setting "code.gitea.io/gitea/routers/web/user/setting"
16+
)
17+
18+
const (
19+
tplSettingsApplications base.TplName = "org/settings/applications"
20+
tplSettingsOAuthApplicationEdit base.TplName = "org/settings/applications_oauth2_edit"
21+
)
22+
23+
func newOAuth2CommonHandlers(org *context.Organization) *user_setting.OAuth2CommonHandlers {
24+
return &user_setting.OAuth2CommonHandlers{
25+
OwnerID: org.Organization.ID,
26+
BasePathList: fmt.Sprintf("%s/org/%s/settings/applications", setting.AppSubURL, org.Organization.Name),
27+
BasePathEditPrefix: fmt.Sprintf("%s/org/%s/settings/applications/oauth2", setting.AppSubURL, org.Organization.Name),
28+
TplAppEdit: tplSettingsOAuthApplicationEdit,
29+
}
30+
}
31+
32+
// Applications render org applications page (for org, at the moment, there are only OAuth2 applications)
33+
func Applications(ctx *context.Context) {
34+
ctx.Data["Title"] = ctx.Tr("settings.applications")
35+
ctx.Data["PageIsOrgSettings"] = true
36+
ctx.Data["PageIsSettingsApplications"] = true
37+
38+
apps, err := auth.GetOAuth2ApplicationsByUserID(ctx, ctx.Org.Organization.ID)
39+
if err != nil {
40+
ctx.ServerError("GetOAuth2ApplicationsByUserID", err)
41+
return
42+
}
43+
ctx.Data["Applications"] = apps
44+
45+
ctx.HTML(http.StatusOK, tplSettingsApplications)
46+
}
47+
48+
// OAuthApplicationsPost response for adding an oauth2 application
49+
func OAuthApplicationsPost(ctx *context.Context) {
50+
ctx.Data["Title"] = ctx.Tr("settings.applications")
51+
ctx.Data["PageIsOrgSettings"] = true
52+
ctx.Data["PageIsSettingsApplications"] = true
53+
54+
oa := newOAuth2CommonHandlers(ctx.Org)
55+
oa.AddApp(ctx)
56+
}
57+
58+
// OAuth2ApplicationShow displays the given application
59+
func OAuth2ApplicationShow(ctx *context.Context) {
60+
ctx.Data["PageIsOrgSettings"] = true
61+
ctx.Data["PageIsSettingsApplications"] = true
62+
63+
oa := newOAuth2CommonHandlers(ctx.Org)
64+
oa.EditShow(ctx)
65+
}
66+
67+
// OAuth2ApplicationEdit response for editing oauth2 application
68+
func OAuth2ApplicationEdit(ctx *context.Context) {
69+
ctx.Data["Title"] = ctx.Tr("settings.applications")
70+
ctx.Data["PageIsOrgSettings"] = true
71+
ctx.Data["PageIsSettingsApplications"] = true
72+
73+
oa := newOAuth2CommonHandlers(ctx.Org)
74+
oa.EditSave(ctx)
75+
}
76+
77+
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
78+
func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
79+
ctx.Data["Title"] = ctx.Tr("settings")
80+
ctx.Data["PageIsOrgSettings"] = true
81+
ctx.Data["PageIsSettingsApplications"] = true
82+
83+
oa := newOAuth2CommonHandlers(ctx.Org)
84+
oa.RegenerateSecret(ctx)
85+
}
86+
87+
// DeleteOAuth2Application deletes the given oauth2 application
88+
func DeleteOAuth2Application(ctx *context.Context) {
89+
oa := newOAuth2CommonHandlers(ctx.Org)
90+
oa.DeleteApp(ctx)
91+
}
92+
93+
// TODO: revokes the grant with the given id

routers/web/user/setting/oauth2.go

Lines changed: 22 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -5,155 +5,65 @@
55
package setting
66

77
import (
8-
"fmt"
9-
"net/http"
10-
11-
"code.gitea.io/gitea/models/auth"
128
"code.gitea.io/gitea/modules/base"
139
"code.gitea.io/gitea/modules/context"
14-
"code.gitea.io/gitea/modules/log"
1510
"code.gitea.io/gitea/modules/setting"
16-
"code.gitea.io/gitea/modules/web"
17-
"code.gitea.io/gitea/services/forms"
1811
)
1912

2013
const (
21-
tplSettingsOAuthApplications base.TplName = "user/settings/applications_oauth2_edit"
14+
tplSettingsOAuthApplicationEdit base.TplName = "user/settings/applications_oauth2_edit"
2215
)
2316

17+
func newOAuth2CommonHandlers(userID int64) *OAuth2CommonHandlers {
18+
return &OAuth2CommonHandlers{
19+
OwnerID: userID,
20+
BasePathList: setting.AppSubURL + "/user/settings/applications",
21+
BasePathEditPrefix: setting.AppSubURL + "/user/settings/applications/oauth2",
22+
TplAppEdit: tplSettingsOAuthApplicationEdit,
23+
}
24+
}
25+
2426
// OAuthApplicationsPost response for adding a oauth2 application
2527
func OAuthApplicationsPost(ctx *context.Context) {
26-
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
2728
ctx.Data["Title"] = ctx.Tr("settings")
2829
ctx.Data["PageIsSettingsApplications"] = true
2930

30-
if ctx.HasError() {
31-
loadApplicationsData(ctx)
32-
33-
ctx.HTML(http.StatusOK, tplSettingsApplications)
34-
return
35-
}
36-
// TODO validate redirect URI
37-
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
38-
Name: form.Name,
39-
RedirectURIs: []string{form.RedirectURI},
40-
UserID: ctx.Doer.ID,
41-
})
42-
if err != nil {
43-
ctx.ServerError("CreateOAuth2Application", err)
44-
return
45-
}
46-
ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"))
47-
ctx.Data["App"] = app
48-
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
49-
if err != nil {
50-
ctx.ServerError("GenerateClientSecret", err)
51-
return
52-
}
53-
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
31+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
32+
oa.AddApp(ctx)
5433
}
5534

5635
// OAuthApplicationsEdit response for editing oauth2 application
5736
func OAuthApplicationsEdit(ctx *context.Context) {
58-
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
5937
ctx.Data["Title"] = ctx.Tr("settings")
6038
ctx.Data["PageIsSettingsApplications"] = true
6139

62-
if ctx.HasError() {
63-
loadApplicationsData(ctx)
64-
65-
ctx.HTML(http.StatusOK, tplSettingsApplications)
66-
return
67-
}
68-
// TODO validate redirect URI
69-
var err error
70-
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{
71-
ID: ctx.ParamsInt64("id"),
72-
Name: form.Name,
73-
RedirectURIs: []string{form.RedirectURI},
74-
UserID: ctx.Doer.ID,
75-
}); err != nil {
76-
ctx.ServerError("UpdateOAuth2Application", err)
77-
return
78-
}
79-
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
80-
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
40+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
41+
oa.EditSave(ctx)
8142
}
8243

8344
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
8445
func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
8546
ctx.Data["Title"] = ctx.Tr("settings")
8647
ctx.Data["PageIsSettingsApplications"] = true
8748

88-
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
89-
if err != nil {
90-
if auth.IsErrOAuthApplicationNotFound(err) {
91-
ctx.NotFound("Application not found", err)
92-
return
93-
}
94-
ctx.ServerError("GetOAuth2ApplicationByID", err)
95-
return
96-
}
97-
if app.UID != ctx.Doer.ID {
98-
ctx.NotFound("Application not found", nil)
99-
return
100-
}
101-
ctx.Data["App"] = app
102-
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
103-
if err != nil {
104-
ctx.ServerError("GenerateClientSecret", err)
105-
return
106-
}
107-
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
108-
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
49+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
50+
oa.RegenerateSecret(ctx)
10951
}
11052

11153
// OAuth2ApplicationShow displays the given application
11254
func OAuth2ApplicationShow(ctx *context.Context) {
113-
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
114-
if err != nil {
115-
if auth.IsErrOAuthApplicationNotFound(err) {
116-
ctx.NotFound("Application not found", err)
117-
return
118-
}
119-
ctx.ServerError("GetOAuth2ApplicationByID", err)
120-
return
121-
}
122-
if app.UID != ctx.Doer.ID {
123-
ctx.NotFound("Application not found", nil)
124-
return
125-
}
126-
ctx.Data["App"] = app
127-
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
55+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
56+
oa.EditShow(ctx)
12857
}
12958

13059
// DeleteOAuth2Application deletes the given oauth2 application
13160
func DeleteOAuth2Application(ctx *context.Context) {
132-
if err := auth.DeleteOAuth2Application(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
133-
ctx.ServerError("DeleteOAuth2Application", err)
134-
return
135-
}
136-
log.Trace("OAuth2 Application deleted: %s", ctx.Doer.Name)
137-
138-
ctx.Flash.Success(ctx.Tr("settings.remove_oauth2_application_success"))
139-
ctx.JSON(http.StatusOK, map[string]interface{}{
140-
"redirect": setting.AppSubURL + "/user/settings/applications",
141-
})
61+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
62+
oa.DeleteApp(ctx)
14263
}
14364

14465
// RevokeOAuth2Grant revokes the grant with the given id
14566
func RevokeOAuth2Grant(ctx *context.Context) {
146-
if ctx.Doer.ID == 0 || ctx.FormInt64("id") == 0 {
147-
ctx.ServerError("RevokeOAuth2Grant", fmt.Errorf("user id or grant id is zero"))
148-
return
149-
}
150-
if err := auth.RevokeOAuth2Grant(ctx, ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
151-
ctx.ServerError("RevokeOAuth2Grant", err)
152-
return
153-
}
154-
155-
ctx.Flash.Success(ctx.Tr("settings.revoke_oauth2_grant_success"))
156-
ctx.JSON(http.StatusOK, map[string]interface{}{
157-
"redirect": setting.AppSubURL + "/user/settings/applications",
158-
})
67+
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
68+
oa.RevokeGrant(ctx)
15969
}

0 commit comments

Comments
 (0)