Skip to content

OAuth2 Grant UI #6625

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 15 commits into from
Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 49 additions & 6 deletions models/oauth2_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,12 +340,13 @@ func getOAuth2AuthorizationByCode(e Engine, code string) (auth *OAuth2Authorizat

// OAuth2Grant represents the permission of an user for a specifc application to access resources
type OAuth2Grant struct {
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX unique(user_application)"`
ApplicationID int64 `xorm:"INDEX unique(user_application)"`
Counter int64 `xorm:"NOT NULL DEFAULT 1"`
CreatedUnix util.TimeStamp `xorm:"created"`
UpdatedUnix util.TimeStamp `xorm:"updated"`
ID int64 `xorm:"pk autoincr"`
UserID int64 `xorm:"INDEX unique(user_application)"`
Application *OAuth2Application `xorm:"-"`
ApplicationID int64 `xorm:"INDEX unique(user_application)"`
Counter int64 `xorm:"NOT NULL DEFAULT 1"`
CreatedUnix util.TimeStamp `xorm:"created"`
UpdatedUnix util.TimeStamp `xorm:"updated"`
}

// TableName sets the table name to `oauth2_grant`
Expand Down Expand Up @@ -410,6 +411,48 @@ func getOAuth2GrantByID(e Engine, id int64) (grant *OAuth2Grant, err error) {
return
}

// GetOAuth2GrantsByUserID lists all grants of a certain user
func GetOAuth2GrantsByUserID(uid int64) ([]*OAuth2Grant, error) {
return getOAuth2GrantsByUserID(x, uid)
}

func getOAuth2GrantsByUserID(e Engine, uid int64) ([]*OAuth2Grant, error) {
type joinedOAuth2Grant struct {
Grant *OAuth2Grant `xorm:"extends"`
Application *OAuth2Application `xorm:"extends"`
}
var results *xorm.Rows
var err error
if results, err = e.
Table("oauth2_grant").
Where("user_id = ?", uid).
Join("INNER", "oauth2_application", "application_id = oauth2_application.id").
Rows(new(joinedOAuth2Grant)); err != nil {
return nil, err
}
defer results.Close()
grants := make([]*OAuth2Grant, 0)
for results.Next() {
joinedGrant := new(joinedOAuth2Grant)
if err := results.Scan(joinedGrant); err != nil {
return nil, err
}
joinedGrant.Grant.Application = joinedGrant.Application
grants = append(grants, joinedGrant.Grant)
}
return grants, nil
}

// RevokeOAuth2Grant deletes the grant with grantID and userID
func RevokeOAuth2Grant(grantID, userID int64) error {
return revokeOAuth2Grant(x, grantID, userID)
}

func revokeOAuth2Grant(e Engine, grantID, userID int64) error {
_, err := e.Delete(&OAuth2Grant{ID: grantID, UserID: userID})
return err
}

//////////////////////////////////////////////////////////////

// OAuth2TokenType represents the type of token for an oauth application
Expand Down
19 changes: 19 additions & 0 deletions models/oauth2_application_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,25 @@ func TestOAuth2Grant_TableName(t *testing.T) {
assert.Equal(t, "oauth2_grant", new(OAuth2Grant).TableName())
}

func TestGetOAuth2GrantsByUserID(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
result, err := GetOAuth2GrantsByUserID(1)
assert.NoError(t, err)
assert.Len(t, result, 1)
assert.Equal(t, int64(1), result[0].ID)
assert.Equal(t, result[0].ApplicationID, result[0].Application.ID)

result, err = GetOAuth2GrantsByUserID(34134)
assert.NoError(t, err)
assert.Empty(t, result)
}

func TestRevokeOAuth2Grant(t *testing.T) {
assert.NoError(t, PrepareTestDatabase())
assert.NoError(t, RevokeOAuth2Grant(1, 1))
AssertNotExistsBean(t, &OAuth2Grant{ID: 1, UserID: 1})
}

//////////////////// Authorization Code

func TestGetOAuth2AuthorizationByCode(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,13 @@ oauth2_application_edit = Edit
oauth2_application_create_description = OAuth2 applications gives your third-party application access to user accounts on this instance.
oauth2_application_remove_description = Removing an OAuth2 application will prevent it to access authorized user accounts on this instance. Continue?

authorized_oauth2_applications = Authorized OAuth2 Applications
authorized_oauth2_applications_description = You've granted access to your personal Gitea account to these third party applications. Please revoke access for applications no longer needed.
revoke_key = Revoke
revoke_oauth2_grant = Revoke Access
revoke_oauth2_grant_description = Revoking access for this third party application will prevent this application from accessing your data. Are you sure?
revoke_oauth2_grant_success = You've revoked access successfully.

twofa_desc = Two-factor authentication enhances the security of your account.
twofa_is_enrolled = Your account is currently <strong>enrolled</strong> in two-factor authentication.
twofa_not_enrolled = Your account is not currently enrolled in two-factor authentication.
Expand Down
1 change: 1 addition & 0 deletions routers/routes/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Post("/:id/regenerate_secret", userSetting.OAuthApplicationsRegenerateSecret)
m.Post("", bindIgnErr(auth.EditOAuth2ApplicationForm{}), userSetting.OAuthApplicationsPost)
m.Post("/delete", userSetting.DeleteOAuth2Application)
m.Post("/revoke", userSetting.RevokeOAuth2Grant)
})
m.Combo("/applications").Get(userSetting.Applications).
Post(bindIgnErr(auth.NewAccessTokenForm{}), userSetting.ApplicationsPost)
Expand Down
5 changes: 5 additions & 0 deletions routers/user/setting/applications.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,10 @@ func loadApplicationsData(ctx *context.Context) {
ctx.ServerError("GetOAuth2ApplicationsByUserID", err)
return
}
ctx.Data["Grants"], err = models.GetOAuth2GrantsByUserID(ctx.User.ID)
if err != nil {
ctx.ServerError("GetOAuth2GrantsByUserID", err)
return
}
}
}
13 changes: 13 additions & 0 deletions routers/user/setting/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,16 @@ func DeleteOAuth2Application(ctx *context.Context) {
"redirect": setting.AppSubURL + "/user/settings/applications",
})
}

// RevokeOAuth2Grant revokes the grant with the given id
func RevokeOAuth2Grant(ctx *context.Context) {
if err := models.RevokeOAuth2Grant(ctx.QueryInt64("id"), ctx.User.ID); err != nil {
ctx.ServerError("RevokeOAuth2Grant", err)
return
}

ctx.Flash.Success(ctx.Tr("settings.revoke_oauth2_grant_success"))
ctx.JSON(200, map[string]interface{}{
"redirect": setting.AppSubURL + "/user/settings/applications",
})
}
1 change: 1 addition & 0 deletions templates/user/settings/applications.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
</div>

{{if .EnableOAuth2}}
{{template "user/settings/grants_oauth2" .}}
{{template "user/settings/applications_oauth2" .}}
{{end}}
</div>
Expand Down
39 changes: 39 additions & 0 deletions templates/user/settings/grants_oauth2.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<h4 class="ui top attached header">
{{.i18n.Tr "settings.authorized_oauth2_applications"}}
</h4>
<div class="ui attached segment">
<div class="ui key list">
<div class="item">
{{.i18n.Tr "settings.authorized_oauth2_applications_description"}}
</div>
{{range $grant := .Grants}}
<div class="item">
<div class="right floated content">
<button class="ui red tiny button delete-button" id="revoke-gitea-oauth2-grant"
data-url="{{AppSubUrl}}/user/settings/applications/oauth2/revoke"
data-id="{{$grant.ID}}">
{{$.i18n.Tr "settings.revoke_key"}}
</button>
</div>
<i class="big key icon"></i>
<div class="content">
<strong>{{$grant.Application.Name}}</strong>
<div class="activity meta">
<i>{{$.i18n.Tr "settings.add_on"}} <span>{{$grant.CreatedUnix.FormatShort}}</span></i>
</div>
</div>
</div>
{{end}}
</div>
</div>

<div class="ui small basic delete modal" id="revoke-gitea-oauth2-grant">
<div class="ui icon header">
<i class="shield alternate icon"></i>
{{.i18n.Tr "settings.revoke_oauth2_grant"}}
</div>
<div class="content">
<p>{{.i18n.Tr "settings.revoke_oauth2_grant_description"}}</p>
</div>
{{template "base/delete_modal_actions" .}}
</div>