Skip to content

Commit f588ae4

Browse files
authored
Delete user rbac attachments on deletion of users (#271)
* Delete user rbac attachments on deletion of users * Add a DeleteUser method so we can delete rbac attachments for a user. * Make noop.go fully no-op (makes sure that a call to DeleteUser) even with RBAC off is OK. All other endpoints now fully no-op for consistency. * Introduce a UserHandler to contain dependencies for the user handlers * Fix tests post merge * Move handler deps to providers * Created a RBAC Provider * Created a User Provider * Fix linting issues
1 parent c108600 commit f588ae4

File tree

13 files changed

+273
-192
lines changed

13 files changed

+273
-192
lines changed

gaia.go

+11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"os"
55
"time"
66

7+
"github.com/dgrijalva/jwt-go"
78
hclog "github.com/hashicorp/go-hclog"
89
"github.com/robfig/cron"
910
)
@@ -156,6 +157,16 @@ const (
156157
StartReasonScheduled = "scheduled"
157158
)
158159

160+
// JwtExpiry is the default JWT expiry.
161+
const JwtExpiry = 12 * 60 * 60
162+
163+
// JwtCustomClaims is the custom JWT claims for a Gaia session.
164+
type JwtCustomClaims struct {
165+
Username string `json:"username"`
166+
Roles []string `json:"roles"`
167+
jwt.StandardClaims
168+
}
169+
159170
// User is the user object
160171
type User struct {
161172
Username string `json:"username,omitempty"`

handlers/auth_test.go

+16-16
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ func TestAuthBarrierHMACTokenWithHMACKey(t *testing.T) {
128128
JWTKey: []byte("hmac-jwt-key"),
129129
}
130130

131-
claims := jwtCustomClaims{
131+
claims := gaia.JwtCustomClaims{
132132
Username: "test-user",
133133
Roles: []string{},
134134
StandardClaims: jwt.StandardClaims{
135-
ExpiresAt: time.Now().Unix() + jwtExpiry,
135+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
136136
IssuedAt: time.Now().Unix(),
137137
Subject: "Gaia Session Token",
138138
},
@@ -164,11 +164,11 @@ func TestAuthBarrierRSATokenWithRSAKey(t *testing.T) {
164164
JWTKey: key,
165165
}
166166

167-
claims := jwtCustomClaims{
167+
claims := gaia.JwtCustomClaims{
168168
Username: "test-user",
169169
Roles: []string{},
170170
StandardClaims: jwt.StandardClaims{
171-
ExpiresAt: time.Now().Unix() + jwtExpiry,
171+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
172172
IssuedAt: time.Now().Unix(),
173173
Subject: "Gaia Session Token",
174174
},
@@ -199,11 +199,11 @@ func TestAuthBarrierHMACTokenWithRSAKey(t *testing.T) {
199199
JWTKey: &rsa.PrivateKey{},
200200
}
201201

202-
claims := jwtCustomClaims{
202+
claims := gaia.JwtCustomClaims{
203203
Username: "test-user",
204204
Roles: []string{},
205205
StandardClaims: jwt.StandardClaims{
206-
ExpiresAt: time.Now().Unix() + jwtExpiry,
206+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
207207
IssuedAt: time.Now().Unix(),
208208
Subject: "Gaia Session Token",
209209
},
@@ -242,11 +242,11 @@ func TestAuthBarrierRSATokenWithHMACKey(t *testing.T) {
242242
JWTKey: []byte("hmac-jwt-key"),
243243
}
244244

245-
claims := jwtCustomClaims{
245+
claims := gaia.JwtCustomClaims{
246246
Username: "test-user",
247247
Roles: []string{},
248248
StandardClaims: jwt.StandardClaims{
249-
ExpiresAt: time.Now().Unix() + jwtExpiry,
249+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
250250
IssuedAt: time.Now().Unix(),
251251
Subject: "Gaia Session Token",
252252
},
@@ -298,11 +298,11 @@ func TestAuthBarrierNoPerms(t *testing.T) {
298298
JWTKey: []byte("hmac-jwt-key"),
299299
}
300300

301-
claims := jwtCustomClaims{
301+
claims := gaia.JwtCustomClaims{
302302
Username: "test-user",
303303
Roles: []string{},
304304
StandardClaims: jwt.StandardClaims{
305-
ExpiresAt: time.Now().Unix() + jwtExpiry,
305+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
306306
IssuedAt: time.Now().Unix(),
307307
Subject: "Gaia Session Token",
308308
},
@@ -333,11 +333,11 @@ func TestAuthBarrierAllPerms(t *testing.T) {
333333
JWTKey: []byte("hmac-jwt-key"),
334334
}
335335

336-
claims := jwtCustomClaims{
336+
claims := gaia.JwtCustomClaims{
337337
Username: "test-user",
338338
Roles: []string{"CatOneGetSingle", "CatOnePostSingle", "CatTwoGetSingle", "CatTwoPostSingle"},
339339
StandardClaims: jwt.StandardClaims{
340-
ExpiresAt: time.Now().Unix() + jwtExpiry,
340+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
341341
IssuedAt: time.Now().Unix(),
342342
Subject: "Gaia Session Token",
343343
},
@@ -386,11 +386,11 @@ func Test_AuthMiddleware_Enforcer_PermissionDenied(t *testing.T) {
386386
JWTKey: []byte("hmac-jwt-key"),
387387
}
388388

389-
claims := jwtCustomClaims{
389+
claims := gaia.JwtCustomClaims{
390390
Username: "enforcer-perms-err",
391391
Roles: []string{},
392392
StandardClaims: jwt.StandardClaims{
393-
ExpiresAt: time.Now().Unix() + jwtExpiry,
393+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
394394
IssuedAt: time.Now().Unix(),
395395
Subject: "Gaia Session Token",
396396
},
@@ -420,11 +420,11 @@ func Test_AuthMiddleware_Enforcer_UnknownError(t *testing.T) {
420420
}
421421
gaia.Cfg.Logger = hclog.NewNullLogger()
422422

423-
claims := jwtCustomClaims{
423+
claims := gaia.JwtCustomClaims{
424424
Username: "enforcer-err",
425425
Roles: []string{},
426426
StandardClaims: jwt.StandardClaims{
427-
ExpiresAt: time.Now().Unix() + jwtExpiry,
427+
ExpiresAt: time.Now().Unix() + gaia.JwtExpiry,
428428
IssuedAt: time.Now().Unix(),
429429
Subject: "Gaia Session Token",
430430
},

handlers/handler.go

+15-22
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,14 @@ func (s *GaiaHandler) InitHandlers(e *echo.Echo) error {
3434

3535
// Endpoints for Gaia primary instance
3636
if gaia.Cfg.Mode == gaia.ModeServer {
37-
// Users
38-
apiGrp.POST("login", UserLogin)
39-
40-
apiAuthGrp.GET("users", UserGetAll)
41-
apiAuthGrp.POST("user/password", UserChangePassword)
42-
apiAuthGrp.DELETE("user/:username", UserDelete)
43-
apiAuthGrp.GET("user/:username/permissions", UserGetPermissions)
44-
apiAuthGrp.PUT("user/:username/permissions", UserPutPermissions)
45-
apiAuthGrp.POST("user", UserAdd)
46-
apiAuthGrp.PUT("user/:username/reset-trigger-token", UserResetTriggerToken)
47-
37+
apiGrp.POST("login", s.deps.UserProvider.UserLogin)
38+
apiAuthGrp.GET("users", s.deps.UserProvider.UserGetAll)
39+
apiAuthGrp.POST("user/password", s.deps.UserProvider.UserChangePassword)
40+
apiAuthGrp.DELETE("user/:username", s.deps.UserProvider.UserDelete)
41+
apiAuthGrp.GET("user/:username/permissions", s.deps.UserProvider.UserGetPermissions)
42+
apiAuthGrp.PUT("user/:username/permissions", s.deps.UserProvider.UserPutPermissions)
43+
apiAuthGrp.POST("user", s.deps.UserProvider.UserAdd)
44+
apiAuthGrp.PUT("user/:username/reset-trigger-token", s.deps.UserProvider.UserResetTriggerToken)
4845
apiAuthGrp.GET("permission", PermissionGetAll)
4946

5047
// Pipelines
@@ -86,19 +83,15 @@ func (s *GaiaHandler) InitHandlers(e *echo.Echo) error {
8683
apiAuthGrp.POST("secret", SetSecret)
8784
apiAuthGrp.PUT("secret/update", SetSecret)
8885

89-
// RBAC
90-
rbacHandler := rbacHandler{
91-
svc: s.deps.RBACService,
92-
}
9386
// RBAC - Management
94-
apiAuthGrp.GET("rbac/roles", rbacHandler.getAllRoles)
95-
apiAuthGrp.PUT("rbac/roles/:role", rbacHandler.addRole)
96-
apiAuthGrp.DELETE("rbac/roles/:role", rbacHandler.deleteRole)
97-
apiAuthGrp.PUT("rbac/roles/:role/attach/:username", rbacHandler.attachRole)
98-
apiAuthGrp.DELETE("rbac/roles/:role/attach/:username", rbacHandler.detachRole)
99-
apiAuthGrp.GET("rbac/roles/:role/attached", rbacHandler.getRolesAttachedUsers)
87+
apiAuthGrp.GET("rbac/roles", s.deps.RBACProvider.GetAllRoles)
88+
apiAuthGrp.PUT("rbac/roles/:role", s.deps.RBACProvider.AddRole)
89+
apiAuthGrp.DELETE("rbac/roles/:role", s.deps.RBACProvider.DeleteRole)
90+
apiAuthGrp.PUT("rbac/roles/:role/attach/:username", s.deps.RBACProvider.DetachRole)
91+
apiAuthGrp.DELETE("rbac/roles/:role/attach/:username", s.deps.RBACProvider.DetachRole)
92+
apiAuthGrp.GET("rbac/roles/:role/attached", s.deps.RBACProvider.GetRolesAttachedUsers)
10093
// RBAC - Users
101-
apiAuthGrp.GET("users/:username/rbac/roles", rbacHandler.getUserAttachedRoles)
94+
apiAuthGrp.GET("users/:username/rbac/roles", s.deps.RBACProvider.GetUserAttachedRoles)
10295
}
10396

10497
// Worker

handlers/service.go

+3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package handlers
22

33
import (
4+
"github.com/gaia-pipeline/gaia/providers"
45
"github.com/gaia-pipeline/gaia/providers/pipelines"
56
"github.com/gaia-pipeline/gaia/providers/workers"
67
"github.com/gaia-pipeline/gaia/security"
@@ -15,6 +16,8 @@ type Dependencies struct {
1516
Scheduler service.GaiaScheduler
1617
PipelineService pipeline.Servicer
1718
PipelineProvider pipelines.PipelineProviderer
19+
UserProvider providers.UserProvider
20+
RBACProvider providers.RBACProvider
1821
WorkerProvider workers.WorkerProviderer
1922
Certificate security.CAAPI
2023
RBACService rbac.Service

providers/provider.go

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package providers
2+
3+
import (
4+
"github.com/labstack/echo"
5+
)
6+
7+
// RBACProvider provides all the handler endpoints for RBAC actions.
8+
type RBACProvider interface {
9+
AddRole(c echo.Context) error
10+
DeleteRole(c echo.Context) error
11+
GetAllRoles(c echo.Context) error
12+
GetUserAttachedRoles(c echo.Context) error
13+
GetRolesAttachedUsers(c echo.Context) error
14+
AttachRole(c echo.Context) error
15+
DetachRole(c echo.Context) error
16+
}
17+
18+
// UserProvider provides all the handler endpoints for User actions.
19+
type UserProvider interface {
20+
UserLogin(c echo.Context) error
21+
UserGetAll(c echo.Context) error
22+
UserChangePassword(c echo.Context) error
23+
UserResetTriggerToken(c echo.Context) error
24+
UserDelete(c echo.Context) error
25+
UserAdd(c echo.Context) error
26+
UserGetPermissions(c echo.Context) error
27+
UserPutPermissions(c echo.Context) error
28+
}

handlers/rbac.go providers/rbac/provider.go

+22-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package handlers
1+
package rbac
22

33
import (
44
"net/http"
@@ -9,11 +9,18 @@ import (
99
"github.com/gaia-pipeline/gaia/security/rbac"
1010
)
1111

12-
type rbacHandler struct {
12+
// Provider represents the RBAC provider.
13+
type Provider struct {
1314
svc rbac.Service
1415
}
1516

16-
func (h *rbacHandler) addRole(c echo.Context) error {
17+
// NewProvider creates a new Provider.
18+
func NewProvider(svc rbac.Service) *Provider {
19+
return &Provider{svc: svc}
20+
}
21+
22+
// AddRole adds an RBAC role using the RBAC service.
23+
func (h *Provider) AddRole(c echo.Context) error {
1724
role := c.Param("role")
1825
if role == "" {
1926
return c.String(http.StatusBadRequest, "Must provide role.")
@@ -33,7 +40,8 @@ func (h *rbacHandler) addRole(c echo.Context) error {
3340
return c.String(http.StatusOK, "Role created successfully.")
3441
}
3542

36-
func (h *rbacHandler) deleteRole(c echo.Context) error {
43+
// DeleteRole deletes an RBAC role using the RBAC service.
44+
func (h *Provider) DeleteRole(c echo.Context) error {
3745
role := c.Param("role")
3846
if role == "" {
3947
return c.String(http.StatusBadRequest, "Must provide role.")
@@ -47,11 +55,13 @@ func (h *rbacHandler) deleteRole(c echo.Context) error {
4755
return c.String(http.StatusOK, "Role deleted successfully.")
4856
}
4957

50-
func (h *rbacHandler) getAllRoles(c echo.Context) error {
58+
// GetAllRoles gets all RBAC roles.
59+
func (h *Provider) GetAllRoles(c echo.Context) error {
5160
return c.JSON(http.StatusOK, h.svc.GetAllRoles())
5261
}
5362

54-
func (h *rbacHandler) getUserAttachedRoles(c echo.Context) error {
63+
// GetUserAttachedRoles gets all roles attached to a specific user.
64+
func (h *Provider) GetUserAttachedRoles(c echo.Context) error {
5565
username := c.Param("username")
5666
if username == "" {
5767
return c.String(http.StatusBadRequest, "Must provide username.")
@@ -66,7 +76,8 @@ func (h *rbacHandler) getUserAttachedRoles(c echo.Context) error {
6676
return c.JSON(http.StatusOK, roles)
6777
}
6878

69-
func (h *rbacHandler) getRolesAttachedUsers(c echo.Context) error {
79+
// GetRolesAttachedUsers gets all users attached to a role.
80+
func (h *Provider) GetRolesAttachedUsers(c echo.Context) error {
7081
role := c.Param("role")
7182
if role == "" {
7283
return c.String(http.StatusBadRequest, "Must provide role.")
@@ -81,7 +92,8 @@ func (h *rbacHandler) getRolesAttachedUsers(c echo.Context) error {
8192
return c.JSON(http.StatusOK, roles)
8293
}
8394

84-
func (h *rbacHandler) attachRole(c echo.Context) error {
95+
// AttachRole attches a role to a user.
96+
func (h *Provider) AttachRole(c echo.Context) error {
8597
role := c.Param("role")
8698
if role == "" {
8799
return c.String(http.StatusBadRequest, "Must provide role.")
@@ -100,7 +112,8 @@ func (h *rbacHandler) attachRole(c echo.Context) error {
100112
return c.String(http.StatusOK, "Role attached successfully.")
101113
}
102114

103-
func (h *rbacHandler) detachRole(c echo.Context) error {
115+
// DetachRole deteches a role from a user.
116+
func (h *Provider) DetachRole(c echo.Context) error {
104117
role := c.Param("role")
105118
if role == "" {
106119
return c.String(http.StatusBadRequest, "Must provide role.")

0 commit comments

Comments
 (0)