diff --git a/migration/current.go b/migration/current.go index 0967937c0..20f99661e 100644 --- a/migration/current.go +++ b/migration/current.go @@ -46,6 +46,7 @@ func Migrations() []*gormigrate.Migration { v33(), // 未読テーブルにチャンネルIDカラムを追加 / インデックス類の更新 / 不要なレコードの削除 v34(), // 未読テーブルのcreated_atカラムをメッセージテーブルを元に更新 / カラム名を変更 v35(), // OIDC実装のため、openid, profileロール、get_oidc_userinfo権限を追加 + v36(), // OAuth Client Credentials Grantの対応のため、clientロールを追加 } } diff --git a/migration/v36.go b/migration/v36.go new file mode 100644 index 000000000..008934bb0 --- /dev/null +++ b/migration/v36.go @@ -0,0 +1,68 @@ +package migration + +import ( + "github.com/go-gormigrate/gormigrate/v2" + "gorm.io/gorm" +) + +// v36 OAuth Client Credentials Grantの対応のため、clientロールを追加 +func v36() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "36", + Migrate: func(db *gorm.DB) error { + roles := []v36UserRole{ + { + Name: "client", + Oauth2Scope: false, + System: true, + Permissions: []v36RolePermission{ + { + Role: "client", + Permission: "get_user", + }, + { + Role: "client", + Permission: "get_user_tag", + }, + { + Role: "client", + Permission: "get_user_group", + }, + { + Role: "client", + Permission: "get_stamp", + }, + }, + }, + } + for _, role := range roles { + err := db.Create(&role).Error + if err != nil { + return err + } + } + return nil + }, + } +} + +type v36UserRole struct { + Name string `gorm:"type:varchar(30);not null;primaryKey"` + Oauth2Scope bool `gorm:"type:boolean;not null;default:false"` + System bool `gorm:"type:boolean;not null;default:false"` + + Permissions []v36RolePermission `gorm:"constraint:user_role_permissions_role_user_roles_name_foreign,OnUpdate:CASCADE,OnDelete:CASCADE;foreignKey:Role;references:Name"` +} + +func (*v36UserRole) TableName() string { + return "user_roles" +} + +type v36RolePermission struct { + Role string `gorm:"type:varchar(30);not null;primaryKey"` + Permission string `gorm:"type:varchar(30);not null;primaryKey"` +} + +func (*v36RolePermission) TableName() string { + return "user_role_permissions" +} diff --git a/router/middlewares/access_control.go b/router/middlewares/access_control.go index a8607f7e8..eebbd714f 100644 --- a/router/middlewares/access_control.go +++ b/router/middlewares/access_control.go @@ -14,6 +14,7 @@ import ( "github.com/traPtitech/traQ/service/message" "github.com/traPtitech/traQ/service/rbac" "github.com/traPtitech/traQ/service/rbac/permission" + "github.com/traPtitech/traQ/service/rbac/role" ) // AccessControlMiddlewareGenerator アクセスコントロールミドルウェアのジェネレーターを返します @@ -33,6 +34,16 @@ func AccessControlMiddlewareGenerator(r rbac.RBAC) func(p ...permission.Permissi // ユーザー権限検証 user := c.Get(consts.KeyUser).(model.UserInfo) + if user == nil { + for _, v := range p { + if !r.IsGranted(role.Client, v) { + // NG + return echo.NewHTTPError(http.StatusForbidden, fmt.Sprintf("you are not permitted to request to '%s'", c.Request().URL.Path)) + } + } + + return next(c) // OK + } for _, v := range p { if !r.IsGranted(user.GetRole(), v) { // NG diff --git a/router/middlewares/user_authenticate.go b/router/middlewares/user_authenticate.go index e615370e4..0dfd8f271 100644 --- a/router/middlewares/user_authenticate.go +++ b/router/middlewares/user_authenticate.go @@ -47,6 +47,12 @@ func UserAuthenticate(repo repository.Repository, sessStore session.Store) echo. } c.Set(consts.KeyOAuth2AccessScopes, token.Scopes) + if token.UserID == uuid.Nil { + // client credentials grant の場合ユーザーが存在しない + c.Set(consts.KeyUser, nil) + c.Set(consts.KeyUserID, uuid.Nil) + return next(c) + } uid = token.UserID } else { // Authorizationヘッダーがないためセッションを確認する diff --git a/service/rbac/role/client.go b/service/rbac/role/client.go new file mode 100644 index 000000000..d8768a90c --- /dev/null +++ b/service/rbac/role/client.go @@ -0,0 +1,18 @@ +package role + +import ( + "github.com/traPtitech/traQ/service/rbac/permission" +) + +// Client Clientロール (for OAuth2 client credentials grant) +const Client = "client" + +// 自分自身以外の参照系は許可するようにしたいが、https://github.com/traPtitech/traQ/pull/2433#discussion_r1649383346 +// の事情から許可できる権限が限られる +// https://github.com/traPtitech/traQ/issues/2463 で権限を増やせるよう対応予定 +var clientPerms = []permission.Permission{ + permission.GetUser, + permission.GetUserTag, + permission.GetUserGroup, + permission.GetStamp, +} diff --git a/service/rbac/role/role.go b/service/rbac/role/role.go index 77794c9dd..375c2ef56 100644 --- a/service/rbac/role/role.go +++ b/service/rbac/role/role.go @@ -48,6 +48,11 @@ func GetSystemRoles() Roles { oauth2Scope: true, permissions: permission.PermissionsFromArray(profilePerms), }, + Client: &systemRole{ + name: Client, + oauth2Scope: false, + permissions: permission.PermissionsFromArray(clientPerms), + }, } }