diff --git a/plugins/access-control/handlers/permission_handlers_test.go b/plugins/access-control/handlers/permission_handlers_test.go index d5048a4d..d0246c44 100644 --- a/plugins/access-control/handlers/permission_handlers_test.go +++ b/plugins/access-control/handlers/permission_handlers_test.go @@ -474,7 +474,7 @@ func TestDeletePermissionHandler(t *testing.T) { } func newPermissionsUseCase(permissionsRepo *accesscontroltests.MockPermissionsRepository, rolePermissionsRepo *accesscontroltests.MockRolePermissionsRepository) *usecases.PermissionsUseCase { - return usecases.NewPermissionsUseCase(services.NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{})) + return usecases.NewPermissionsUseCase(services.NewPermissionsService(permissionsRepo, rolePermissionsRepo), &internaltests.NoopAuthorizer{}) } func assertPermissionsEqual(t *testing.T, got []types.Permission, want []types.Permission) { diff --git a/plugins/access-control/handlers/role_handlers_test.go b/plugins/access-control/handlers/role_handlers_test.go index 46e00150..80f0e5e6 100644 --- a/plugins/access-control/handlers/role_handlers_test.go +++ b/plugins/access-control/handlers/role_handlers_test.go @@ -627,7 +627,7 @@ func TestDeleteRoleHandler(t *testing.T) { } func newRolesUseCase(rolesRepo *accesscontroltests.MockRolesRepository, rolePermissionsRepo *accesscontroltests.MockRolePermissionsRepository, userRolesRepo *accesscontroltests.MockUserRolesRepository) *usecases.RolesUseCase { - return usecases.NewRolesUseCase(services.NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, &internaltests.NoopAuthorizer{})) + return usecases.NewRolesUseCase(services.NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo), &internaltests.NoopAuthorizer{}) } func assertRolesEqual(t *testing.T, got []types.Role, want []types.Role) { diff --git a/plugins/access-control/handlers/role_permission_handlers_test.go b/plugins/access-control/handlers/role_permission_handlers_test.go index 41878024..1dcef694 100644 --- a/plugins/access-control/handlers/role_permission_handlers_test.go +++ b/plugins/access-control/handlers/role_permission_handlers_test.go @@ -394,7 +394,7 @@ func TestRemoveRolePermissionHandler(t *testing.T) { } func newRolePermissionsUseCase(rolesRepo *accesscontroltests.MockRolesRepository, permissionsRepo *accesscontroltests.MockPermissionsRepository, rolePermissionsRepo *accesscontroltests.MockRolePermissionsRepository) *usecases.RolePermissionsUseCase { - return usecases.NewRolePermissionsUseCase(services.NewRolePermissionsService(rolesRepo, permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{})) + return usecases.NewRolePermissionsUseCase(services.NewRolePermissionsService(rolesRepo, permissionsRepo, rolePermissionsRepo), &internaltests.NoopAuthorizer{}) } func assertUserPermissionInfosEqual(t *testing.T, got []types.UserPermissionInfo, want []types.UserPermissionInfo) { diff --git a/plugins/access-control/handlers/user_permissions_handlers_test.go b/plugins/access-control/handlers/user_permissions_handlers_test.go index ce571604..f623f66a 100644 --- a/plugins/access-control/handlers/user_permissions_handlers_test.go +++ b/plugins/access-control/handlers/user_permissions_handlers_test.go @@ -157,5 +157,5 @@ func TestCheckUserPermissionsHandler(t *testing.T) { } func newUserPermissionsUseCase(repo *accesscontroltests.MockUserPermissionsRepository) *usecases.UserPermissionsUseCase { - return usecases.NewUserPermissionsUseCase(services.NewUserPermissionsService(repo, &internaltests.NoopAuthorizer{})) + return usecases.NewUserPermissionsUseCase(services.NewUserPermissionsService(repo), &internaltests.NoopAuthorizer{}) } diff --git a/plugins/access-control/handlers/user_roles_handlers_test.go b/plugins/access-control/handlers/user_roles_handlers_test.go index ccc637c6..5b2c1096 100644 --- a/plugins/access-control/handlers/user_roles_handlers_test.go +++ b/plugins/access-control/handlers/user_roles_handlers_test.go @@ -387,7 +387,7 @@ func TestRemoveUserRoleHandler(t *testing.T) { } func newUserRolesUseCase(rolesRepo *accesscontroltests.MockRolesRepository, userRolesRepo *accesscontroltests.MockUserRolesRepository) *usecases.UserRolesUseCase { - return usecases.NewUserRolesUseCase(services.NewUserRolesService(userRolesRepo, rolesRepo, &internaltests.NoopAuthorizer{})) + return usecases.NewUserRolesUseCase(services.NewUserRolesService(userRolesRepo, rolesRepo), &internaltests.NoopAuthorizer{}) } func assertUserRoleInfosEqual(t *testing.T, got []types.UserRoleInfo, want []types.UserRoleInfo) { diff --git a/plugins/access-control/hooks_test.go b/plugins/access-control/hooks_test.go index 8ae5d056..dc20d2bb 100644 --- a/plugins/access-control/hooks_test.go +++ b/plugins/access-control/hooks_test.go @@ -30,16 +30,16 @@ func (a *noopAuthorizer) AuthorizeOrganizationAccess(_ context.Context, _ *authm func newAccessControlHookTestPlugin(logger authmodels.Logger, rolesRepo *accesscontroltests.MockRolesRepository, userRolesRepo *accesscontroltests.MockUserRolesRepository) *AccessControlPlugin { authorizer := &noopAuthorizer{} - rolesService := services.NewRolesService(rolesRepo, nil, userRolesRepo, authorizer) - userRolesService := services.NewUserRolesService(userRolesRepo, rolesRepo, authorizer) + rolesService := services.NewRolesService(rolesRepo, nil, userRolesRepo) + userRolesService := services.NewUserRolesService(userRolesRepo, rolesRepo) accessControlService := services.NewAccessControlService(rolesService, userRolesService, nil) - rolePermissionsService := services.NewRolePermissionsService(nil, nil, nil, authorizer) + rolePermissionsService := services.NewRolePermissionsService(nil, nil, nil) useCases := usecases.NewAccessControlUseCases( - usecases.NewRolesUseCase(rolesService), - usecases.NewPermissionsUseCase(nil), - usecases.NewRolePermissionsUseCase(rolePermissionsService), - usecases.NewUserRolesUseCase(userRolesService), - usecases.NewUserPermissionsUseCase(nil), + usecases.NewRolesUseCase(rolesService, authorizer), + usecases.NewPermissionsUseCase(nil, authorizer), + usecases.NewRolePermissionsUseCase(rolePermissionsService, authorizer), + usecases.NewUserRolesUseCase(userRolesService, authorizer), + usecases.NewUserPermissionsUseCase(nil, authorizer), ) return &AccessControlPlugin{ @@ -154,6 +154,8 @@ func TestAccessControlPluginAssignRoleFromContextHook(t *testing.T) { setup: func(rolesRepo *accesscontroltests.MockRolesRepository, userRolesRepo *accesscontroltests.MockUserRolesRepository) { rolesRepo.On("GetRoleByName", mock.Anything, "Editor").Return(&types.Role{ID: "role-1", Name: "Editor", Weight: 10}, nil).Once() userRolesRepo.On("GetUserRoles", mock.Anything, "user-1").Return([]types.UserRoleInfo{}, nil).Once() + rolesRepo.On("GetRoleByID", mock.Anything, "role-1").Return(&types.Role{ID: "role-1", Name: "Editor", Weight: 10}, nil).Once() + userRolesRepo.On("GetUserRoles", mock.Anything, "assigner-1").Return([]types.UserRoleInfo{{RoleID: "role-admin", RoleName: "admin", RoleWeight: 50}}, nil).Once() userRolesRepo.On("AssignUserRole", mock.Anything, "user-1", "role-1", mock.MatchedBy(func(userID *string) bool { return userID != nil && *userID == "assigner-1" }), (*time.Time)(nil)).Return(nil).Once() @@ -172,6 +174,7 @@ func TestAccessControlPluginAssignRoleFromContextHook(t *testing.T) { setup: func(rolesRepo *accesscontroltests.MockRolesRepository, userRolesRepo *accesscontroltests.MockUserRolesRepository) { rolesRepo.On("GetRoleByName", mock.Anything, "Editor").Return(&types.Role{ID: "role-1", Name: "Editor", Weight: 10}, nil).Once() userRolesRepo.On("GetUserRoles", mock.Anything, "user-1").Return([]types.UserRoleInfo{}, nil).Once() + rolesRepo.On("GetRoleByID", mock.Anything, "role-1").Return(&types.Role{ID: "role-1", Name: "Editor", Weight: 10}, nil).Once() userRolesRepo.On("AssignUserRole", mock.Anything, "user-1", "role-1", (*string)(nil), (*time.Time)(nil)).Return(errors.New("assign failed")).Once() }, }, diff --git a/plugins/access-control/plugin.go b/plugins/access-control/plugin.go index 1902ab16..9948de16 100644 --- a/plugins/access-control/plugin.go +++ b/plugins/access-control/plugin.go @@ -54,13 +54,11 @@ func (p *AccessControlPlugin) Init(ctx *models.PluginContext) error { userRolesRepo := repositories.NewBunUserRolesRepository(ctx.DB) userPermissionsRepo := repositories.NewBunUserPermissionsRepository(ctx.DB) - authorizer := rootservices.NewDefaultAuthorizer() - - rolesService := services.NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, authorizer) - permissionsService := services.NewPermissionsService(permissionsRepo, rolePermissionsRepo, authorizer) - rolePermissionsService := services.NewRolePermissionsService(rolesRepo, permissionsRepo, rolePermissionsRepo, authorizer) - userRolesService := services.NewUserRolesService(userRolesRepo, rolesRepo, authorizer) - userPermissionsService := services.NewUserPermissionsService(userPermissionsRepo, authorizer) + rolesService := services.NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo) + permissionsService := services.NewPermissionsService(permissionsRepo, rolePermissionsRepo) + rolePermissionsService := services.NewRolePermissionsService(rolesRepo, permissionsRepo, rolePermissionsRepo) + userRolesService := services.NewUserRolesService(userRolesRepo, rolesRepo) + userPermissionsService := services.NewUserPermissionsService(userPermissionsRepo) accessControlService := services.NewAccessControlService(rolesService, userRolesService, permissionsRepo) p.accessControlService = accessControlService @@ -68,12 +66,14 @@ func (p *AccessControlPlugin) Init(ctx *models.PluginContext) error { return err } + authorizer := rootservices.NewDefaultAuthorizer() + useCases := usecases.NewAccessControlUseCases( - usecases.NewRolesUseCase(rolesService), - usecases.NewPermissionsUseCase(permissionsService), - usecases.NewRolePermissionsUseCase(rolePermissionsService), - usecases.NewUserRolesUseCase(userRolesService), - usecases.NewUserPermissionsUseCase(userPermissionsService), + usecases.NewRolesUseCase(rolesService, authorizer), + usecases.NewPermissionsUseCase(permissionsService, authorizer), + usecases.NewRolePermissionsUseCase(rolePermissionsService, authorizer), + usecases.NewUserRolesUseCase(userRolesService, authorizer), + usecases.NewUserPermissionsUseCase(userPermissionsService, authorizer), ) p.Api = NewAPI(useCases) diff --git a/plugins/access-control/services/access_control_service.go b/plugins/access-control/services/access_control_service.go index 4ab3ee36..14f619fe 100644 --- a/plugins/access-control/services/access_control_service.go +++ b/plugins/access-control/services/access_control_service.go @@ -22,7 +22,7 @@ func NewAccessControlService(rolesService *RolesService, userRolesService *UserR } func (s *AccessControlService) RoleExists(ctx context.Context, roleName string) (bool, error) { - role, err := s.rolesService.getRoleByNameInternal(ctx, roleName) + role, err := s.rolesService.GetRoleByName(ctx, nil, roleName) if err != nil { return false, err } @@ -31,7 +31,7 @@ func (s *AccessControlService) RoleExists(ctx context.Context, roleName string) } func (s *AccessControlService) ValidateRoleAssignment(ctx context.Context, roleName string, assignerUserID *string) (bool, error) { - role, err := s.rolesService.getRoleByNameInternal(ctx, roleName) + role, err := s.rolesService.GetRoleByName(ctx, nil, roleName) if err != nil { return false, err } @@ -43,7 +43,7 @@ func (s *AccessControlService) ValidateRoleAssignment(ctx context.Context, roleN return false, nil } - assignerRoles, err := s.userRolesService.getUserRolesInternal(ctx, *assignerUserID) + assignerRoles, err := s.userRolesService.GetUserRoles(ctx, nil, *assignerUserID) if err != nil { return false, err } @@ -74,12 +74,12 @@ func (s *AccessControlService) ValidatePermissionKeys(ctx context.Context, permi } func (s *AccessControlService) AssignRoleToUserIfMissing(ctx context.Context, userID string, roleName string, assignedByUserID *string) error { - role, err := s.rolesService.getRoleByNameInternal(ctx, roleName) + role, err := s.rolesService.GetRoleByName(ctx, nil, roleName) if err != nil { return err } - userRoles, err := s.userRolesService.getUserRolesInternal(ctx, userID) + userRoles, err := s.userRolesService.GetUserRoles(ctx, nil, userID) if err != nil { return err } @@ -90,7 +90,7 @@ func (s *AccessControlService) AssignRoleToUserIfMissing(ctx context.Context, us } } - return s.userRolesService.assignRoleToUserInternal(ctx, userID, role.ID, assignedByUserID) + return s.userRolesService.AssignRoleToUser(ctx, nil, userID, types.AssignUserRoleRequest{RoleID: role.ID}, assignedByUserID) } func (s *AccessControlService) EnsurePermissions(ctx context.Context, permissions []rootservices.PermissionDefinition) error { diff --git a/plugins/access-control/services/access_control_service_test.go b/plugins/access-control/services/access_control_service_test.go index 34ae5a14..df195088 100644 --- a/plugins/access-control/services/access_control_service_test.go +++ b/plugins/access-control/services/access_control_service_test.go @@ -8,7 +8,6 @@ import ( "github.com/stretchr/testify/mock" internalerrors "github.com/Authula/authula/internal/errors" - internaltests "github.com/Authula/authula/internal/tests" accesscontroltests "github.com/Authula/authula/plugins/access-control/tests" "github.com/Authula/authula/plugins/access-control/types" ) @@ -59,7 +58,7 @@ func TestAccessControlServiceRoleExists(t *testing.T) { tc.setup(rolesRepo) } - service := NewAccessControlService(NewRolesService(rolesRepo, nil, nil, &internaltests.NoopAuthorizer{}), NewUserRolesService(nil, nil, &internaltests.NoopAuthorizer{}), nil) + service := NewAccessControlService(NewRolesService(rolesRepo, nil, nil), NewUserRolesService(nil, nil), nil) ok, err := service.RoleExists(context.Background(), tc.roleName) if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) @@ -129,8 +128,8 @@ func TestAccessControlServiceValidatePermissionKeys(t *testing.T) { } service := NewAccessControlService( - NewRolesService(nil, nil, nil, &internaltests.NoopAuthorizer{}), - NewUserRolesService(nil, nil, &internaltests.NoopAuthorizer{}), + NewRolesService(nil, nil, nil), + NewUserRolesService(nil, nil), permissionsRepo, ) err := service.ValidatePermissionKeys(context.Background(), tc.permissionKeys) @@ -218,7 +217,7 @@ func TestAccessControlServiceValidateRoleAssignment(t *testing.T) { tc.setup(rolesRepo, userRolesRepo) } - service := NewAccessControlService(NewRolesService(rolesRepo, nil, userRolesRepo, &internaltests.NoopAuthorizer{}), NewUserRolesService(userRolesRepo, rolesRepo, &internaltests.NoopAuthorizer{}), nil) + service := NewAccessControlService(NewRolesService(rolesRepo, nil, userRolesRepo), NewUserRolesService(userRolesRepo, rolesRepo), nil) ok, err := service.ValidateRoleAssignment(context.Background(), tc.roleName, tc.assigner) if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) diff --git a/plugins/access-control/services/permissions_service.go b/plugins/access-control/services/permissions_service.go index e8353c33..4294c87b 100644 --- a/plugins/access-control/services/permissions_service.go +++ b/plugins/access-control/services/permissions_service.go @@ -6,27 +6,20 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/repositories" "github.com/Authula/authula/plugins/access-control/types" - rootservices "github.com/Authula/authula/services" ) type PermissionsService struct { permissionsRepo repositories.PermissionsRepository rolePermissionsRepo repositories.RolePermissionsRepository - authorizer rootservices.Authorizer } -func NewPermissionsService(permissionsRepo repositories.PermissionsRepository, rolePermissionsRepo repositories.RolePermissionsRepository, authorizer rootservices.Authorizer) *PermissionsService { - return &PermissionsService{permissionsRepo: permissionsRepo, rolePermissionsRepo: rolePermissionsRepo, authorizer: authorizer} +func NewPermissionsService(permissionsRepo repositories.PermissionsRepository, rolePermissionsRepo repositories.RolePermissionsRepository) *PermissionsService { + return &PermissionsService{permissionsRepo: permissionsRepo, rolePermissionsRepo: rolePermissionsRepo} } func (s *PermissionsService) CreatePermission(ctx context.Context, actor *models.Actor, req types.CreatePermissionRequest) (*types.Permission, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsCreatePermission); err != nil { - return nil, err - } - if req.Key == "" { return nil, internalerrors.ErrBadRequest } @@ -51,18 +44,10 @@ func (s *PermissionsService) CreatePermission(ctx context.Context, actor *models } func (s *PermissionsService) GetAllPermissions(ctx context.Context, actor *models.Actor) ([]types.Permission, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsListPermission); err != nil { - return nil, err - } - return s.permissionsRepo.GetAllPermissions(ctx) } func (s *PermissionsService) GetPermissionByID(ctx context.Context, actor *models.Actor, permissionID string) (*types.Permission, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsReadPermission); err != nil { - return nil, err - } - if permissionID == "" { return nil, internalerrors.ErrBadRequest } @@ -79,10 +64,6 @@ func (s *PermissionsService) GetPermissionByID(ctx context.Context, actor *model } func (s *PermissionsService) GetPermissionByKey(ctx context.Context, actor *models.Actor, permissionKey string) (*types.Permission, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsReadPermission); err != nil { - return nil, err - } - if permissionKey == "" { return nil, internalerrors.ErrBadRequest } @@ -99,10 +80,6 @@ func (s *PermissionsService) GetPermissionByKey(ctx context.Context, actor *mode } func (s *PermissionsService) UpdatePermission(ctx context.Context, actor *models.Actor, permissionID string, req types.UpdatePermissionRequest) (*types.Permission, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsUpdatePermission); err != nil { - return nil, err - } - if permissionID == "" { return nil, internalerrors.ErrUnprocessableEntity } @@ -146,10 +123,6 @@ func (s *PermissionsService) UpdatePermission(ctx context.Context, actor *models } func (s *PermissionsService) DeletePermission(ctx context.Context, actor *models.Actor, permissionID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsDeletePermission); err != nil { - return err - } - if permissionID == "" { return internalerrors.ErrBadRequest } diff --git a/plugins/access-control/services/permissions_service_test.go b/plugins/access-control/services/permissions_service_test.go index 03f125ef..ae89de71 100644 --- a/plugins/access-control/services/permissions_service_test.go +++ b/plugins/access-control/services/permissions_service_test.go @@ -82,7 +82,7 @@ func TestPermissionsServiceCreatePermission(t *testing.T) { tc.setup(permissionsRepo) } - service := NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{}) + service := NewPermissionsService(permissionsRepo, rolePermissionsRepo) permission, err := service.CreatePermission(context.Background(), internaltests.TestActor(), tc.req) if tc.wantErr == nil { if err != nil { @@ -137,7 +137,7 @@ func TestPermissionsServiceGetAllPermissions(t *testing.T) { tc.setup(permissionsRepo) } - service := NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{}) + service := NewPermissionsService(permissionsRepo, rolePermissionsRepo) permissions, err := service.GetAllPermissions(context.Background(), internaltests.TestActor()) if tc.wantErr == nil { if err != nil { @@ -199,7 +199,7 @@ func TestPermissionsServiceGetPermissionByID(t *testing.T) { tc.setup(permissionsRepo) } - service := NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{}) + service := NewPermissionsService(permissionsRepo, rolePermissionsRepo) permission, err := service.GetPermissionByID(context.Background(), internaltests.TestActor(), tc.id) if tc.wantErr == nil { if err != nil { @@ -299,7 +299,7 @@ func TestPermissionsServiceUpdatePermission(t *testing.T) { tc.setup(permissionsRepo) } - service := NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{}) + service := NewPermissionsService(permissionsRepo, rolePermissionsRepo) permission, err := service.UpdatePermission(context.Background(), internaltests.TestActor(), tc.id, tc.req) if tc.wantErr == nil { if err != nil { @@ -387,7 +387,7 @@ func TestPermissionsServiceDeletePermission(t *testing.T) { tc.setup(permissionsRepo, rolePermissionsRepo) } - service := NewPermissionsService(permissionsRepo, rolePermissionsRepo, &internaltests.NoopAuthorizer{}) + service := NewPermissionsService(permissionsRepo, rolePermissionsRepo) err := service.DeletePermission(context.Background(), internaltests.TestActor(), tc.id) if tc.wantErr == nil { if err != nil { diff --git a/plugins/access-control/services/role_permission_service.go b/plugins/access-control/services/role_permission_service.go index c565b1f3..7c4d535c 100644 --- a/plugins/access-control/services/role_permission_service.go +++ b/plugins/access-control/services/role_permission_service.go @@ -5,28 +5,21 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/repositories" "github.com/Authula/authula/plugins/access-control/types" - rootservices "github.com/Authula/authula/services" ) type RolePermissionsService struct { rolesRepo repositories.RolesRepository permissionsRepo repositories.PermissionsRepository rolePermissionsRepo repositories.RolePermissionsRepository - authorizer rootservices.Authorizer } -func NewRolePermissionsService(rolesRepo repositories.RolesRepository, permissionsRepo repositories.PermissionsRepository, rolePermissionsRepo repositories.RolePermissionsRepository, authorizer rootservices.Authorizer) *RolePermissionsService { - return &RolePermissionsService{rolesRepo: rolesRepo, permissionsRepo: permissionsRepo, rolePermissionsRepo: rolePermissionsRepo, authorizer: authorizer} +func NewRolePermissionsService(rolesRepo repositories.RolesRepository, permissionsRepo repositories.PermissionsRepository, rolePermissionsRepo repositories.RolePermissionsRepository) *RolePermissionsService { + return &RolePermissionsService{rolesRepo: rolesRepo, permissionsRepo: permissionsRepo, rolePermissionsRepo: rolePermissionsRepo} } func (s *RolePermissionsService) GetRolePermissions(ctx context.Context, actor *models.Actor, roleID string) ([]types.UserPermissionInfo, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsReadPermission); err != nil { - return nil, err - } - if roleID == "" { return nil, internalerrors.ErrUnprocessableEntity } @@ -43,10 +36,6 @@ func (s *RolePermissionsService) GetRolePermissions(ctx context.Context, actor * } func (s *RolePermissionsService) AddPermissionToRole(ctx context.Context, actor *models.Actor, roleID string, permissionID string, grantedByUserID *string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsAssignPermission); err != nil { - return err - } - if roleID == "" { return internalerrors.ErrBadRequest } @@ -80,10 +69,6 @@ func (s *RolePermissionsService) AddPermissionToRole(ctx context.Context, actor } func (s *RolePermissionsService) RemovePermissionFromRole(ctx context.Context, actor *models.Actor, roleID string, permissionID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsRemovePermission); err != nil { - return err - } - if roleID == "" { return internalerrors.ErrUnprocessableEntity } @@ -117,10 +102,6 @@ func (s *RolePermissionsService) RemovePermissionFromRole(ctx context.Context, a } func (s *RolePermissionsService) ReplaceRolePermissions(ctx context.Context, actor *models.Actor, roleID string, permissionIDs []string, grantedByUserID *string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsAssignPermission); err != nil { - return err - } - if roleID == "" { return internalerrors.ErrBadRequest } diff --git a/plugins/access-control/services/roles_service.go b/plugins/access-control/services/roles_service.go index 9d937994..3fcf0421 100644 --- a/plugins/access-control/services/roles_service.go +++ b/plugins/access-control/services/roles_service.go @@ -9,25 +9,19 @@ import ( accesscontrolconstants "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/repositories" "github.com/Authula/authula/plugins/access-control/types" - rootservices "github.com/Authula/authula/services" ) type RolesService struct { rolesRepo repositories.RolesRepository rolePermissionsRepo repositories.RolePermissionsRepository userRolesRepo repositories.UserRolesRepository - authorizer rootservices.Authorizer } -func NewRolesService(rolesRepo repositories.RolesRepository, rolePermissionsRepo repositories.RolePermissionsRepository, userRolesRepo repositories.UserRolesRepository, authorizer rootservices.Authorizer) *RolesService { - return &RolesService{rolesRepo: rolesRepo, rolePermissionsRepo: rolePermissionsRepo, userRolesRepo: userRolesRepo, authorizer: authorizer} +func NewRolesService(rolesRepo repositories.RolesRepository, rolePermissionsRepo repositories.RolePermissionsRepository, userRolesRepo repositories.UserRolesRepository) *RolesService { + return &RolesService{rolesRepo: rolesRepo, rolePermissionsRepo: rolePermissionsRepo, userRolesRepo: userRolesRepo} } func (s *RolesService) CreateRole(ctx context.Context, actor *models.Actor, req types.CreateRoleRequest) (*types.Role, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesCreatePermission); err != nil { - return nil, err - } - if req.Name == "" { return nil, internalerrors.ErrBadRequest } @@ -57,14 +51,10 @@ func (s *RolesService) CreateRole(ctx context.Context, actor *models.Actor, req } func (s *RolesService) GetAllRoles(ctx context.Context, actor *models.Actor) ([]types.Role, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesListPermission); err != nil { - return nil, err - } - return s.rolesRepo.GetAllRoles(ctx) } -func (s *RolesService) getRoleByNameInternal(ctx context.Context, roleName string) (*types.Role, error) { +func (s *RolesService) GetRoleByName(ctx context.Context, actor *models.Actor, roleName string) (*types.Role, error) { if roleName == "" { return nil, internalerrors.ErrBadRequest } @@ -80,19 +70,7 @@ func (s *RolesService) getRoleByNameInternal(ctx context.Context, roleName strin return role, nil } -func (s *RolesService) GetRoleByName(ctx context.Context, actor *models.Actor, roleName string) (*types.Role, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesReadPermission); err != nil { - return nil, err - } - - return s.getRoleByNameInternal(ctx, roleName) -} - func (s *RolesService) GetRoleByID(ctx context.Context, actor *models.Actor, roleID string) (*types.RoleDetails, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesReadPermission); err != nil { - return nil, err - } - if roleID == "" { return nil, internalerrors.ErrBadRequest } @@ -114,10 +92,6 @@ func (s *RolesService) GetRoleByID(ctx context.Context, actor *models.Actor, rol } func (s *RolesService) UpdateRole(ctx context.Context, actor *models.Actor, roleID string, req types.UpdateRoleRequest) (*types.Role, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesUpdatePermission); err != nil { - return nil, err - } - if roleID == "" { return nil, internalerrors.ErrBadRequest } @@ -175,10 +149,6 @@ func (s *RolesService) UpdateRole(ctx context.Context, actor *models.Actor, role } func (s *RolesService) DeleteRole(ctx context.Context, actor *models.Actor, roleID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesDeletePermission); err != nil { - return err - } - if roleID == "" { return internalerrors.ErrBadRequest } diff --git a/plugins/access-control/services/roles_service_test.go b/plugins/access-control/services/roles_service_test.go index 1434c291..8848c7c0 100644 --- a/plugins/access-control/services/roles_service_test.go +++ b/plugins/access-control/services/roles_service_test.go @@ -23,7 +23,7 @@ func TestRolesServiceGetRoleByID(t *testing.T) { rolesRepo.On("GetRoleByID", mock.Anything, "role-1").Return(&types.Role{ID: "role-1", Name: "admin"}, nil).Once() rolePermissionsRepo.On("GetRolePermissions", mock.Anything, "role-1").Return([]types.UserPermissionInfo{{PermissionID: "perm-1", PermissionKey: "users.read"}}, nil).Once() - service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, &internaltests.NoopAuthorizer{}) + service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo) details, err := service.GetRoleByID(context.Background(), internaltests.TestActor(), "role-1") if err != nil { t.Fatalf("expected nil err, got %v", err) @@ -79,7 +79,7 @@ func TestRolesServiceGetRoleByName(t *testing.T) { tc.setup(rolesRepo, userRolesRepo) } - service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, &internaltests.NoopAuthorizer{}) + service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo) role, err := service.GetRoleByName(context.Background(), internaltests.TestActor(), tc.roleName) if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) @@ -162,7 +162,7 @@ func TestRolesServiceRoleWeightOperations(t *testing.T) { tc.setup(rolesRepo, rolePermissionsRepo, userRolesRepo) } - service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, &internaltests.NoopAuthorizer{}) + service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo) role, err := tc.run(context.Background(), service) if err != nil { t.Fatalf("expected nil err, got %v", err) @@ -215,7 +215,7 @@ func TestRolesServiceDeleteRole(t *testing.T) { tc.setup(rolesRepo, userRolesRepo) } - service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo, &internaltests.NoopAuthorizer{}) + service := NewRolesService(rolesRepo, rolePermissionsRepo, userRolesRepo) err := service.DeleteRole(context.Background(), internaltests.TestActor(), "role-1") if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) diff --git a/plugins/access-control/services/user_permissions_service.go b/plugins/access-control/services/user_permissions_service.go index 120235af..d31e46a8 100644 --- a/plugins/access-control/services/user_permissions_service.go +++ b/plugins/access-control/services/user_permissions_service.go @@ -5,38 +5,19 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/repositories" "github.com/Authula/authula/plugins/access-control/types" - rootservices "github.com/Authula/authula/services" ) type UserPermissionsService struct { - repo repositories.UserPermissionsRepository - authorizer rootservices.Authorizer + repo repositories.UserPermissionsRepository } -func NewUserPermissionsService(repo repositories.UserPermissionsRepository, authorizer rootservices.Authorizer) *UserPermissionsService { - return &UserPermissionsService{repo: repo, authorizer: authorizer} -} - -func (s *UserPermissionsService) GetSelfUserPermissions(ctx context.Context, actor *models.Actor, userID string) ([]types.UserPermissionInfo, error) { - if actor.ID != userID { - return nil, internalerrors.ErrForbidden - } - - if userID == "" { - return nil, internalerrors.ErrUnprocessableEntity - } - - return s.repo.GetUserPermissions(ctx, userID) +func NewUserPermissionsService(repo repositories.UserPermissionsRepository) *UserPermissionsService { + return &UserPermissionsService{repo: repo} } func (s *UserPermissionsService) GetUserPermissions(ctx context.Context, actor *models.Actor, userID string) ([]types.UserPermissionInfo, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserPermissionsReadPermission); err != nil { - return nil, err - } - if userID == "" { return nil, internalerrors.ErrUnprocessableEntity } @@ -45,10 +26,6 @@ func (s *UserPermissionsService) GetUserPermissions(ctx context.Context, actor * } func (s *UserPermissionsService) HasPermissions(ctx context.Context, actor *models.Actor, userID string, permissionKeys []string) (bool, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserPermissionsCheckPermission); err != nil { - return false, err - } - if userID == "" { return false, internalerrors.ErrUnprocessableEntity } diff --git a/plugins/access-control/services/user_permissions_service_test.go b/plugins/access-control/services/user_permissions_service_test.go index 4c3545a2..93397ce0 100644 --- a/plugins/access-control/services/user_permissions_service_test.go +++ b/plugins/access-control/services/user_permissions_service_test.go @@ -54,7 +54,7 @@ func TestUserPermissionsServiceGetUserPermissions(t *testing.T) { tc.setupMock(repo) } - service := NewUserPermissionsService(repo, &internaltests.NoopAuthorizer{}) + service := NewUserPermissionsService(repo) permissions, err := service.GetUserPermissions(context.Background(), internaltests.TestActor(), tc.userID) if tc.expectedErr != nil { if err != tc.expectedErr { @@ -119,7 +119,7 @@ func TestUserPermissionsServiceHasPermissions(t *testing.T) { tc.setupMock(repo) } - service := NewUserPermissionsService(repo, &internaltests.NoopAuthorizer{}) + service := NewUserPermissionsService(repo) hasPermissions, err := service.HasPermissions(context.Background(), internaltests.TestActor(), tc.userID, tc.permissionKeys) if tc.expectedErr != nil { if err != tc.expectedErr { diff --git a/plugins/access-control/services/user_roles_service.go b/plugins/access-control/services/user_roles_service.go index 3fa580ff..3af32964 100644 --- a/plugins/access-control/services/user_roles_service.go +++ b/plugins/access-control/services/user_roles_service.go @@ -6,23 +6,20 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/repositories" "github.com/Authula/authula/plugins/access-control/types" - rootservices "github.com/Authula/authula/services" ) type UserRolesService struct { userRolesRepo repositories.UserRolesRepository rolesRepo repositories.RolesRepository - authorizer rootservices.Authorizer } -func NewUserRolesService(userRolesRepo repositories.UserRolesRepository, rolesRepo repositories.RolesRepository, authorizer rootservices.Authorizer) *UserRolesService { - return &UserRolesService{userRolesRepo: userRolesRepo, rolesRepo: rolesRepo, authorizer: authorizer} +func NewUserRolesService(userRolesRepo repositories.UserRolesRepository, rolesRepo repositories.RolesRepository) *UserRolesService { + return &UserRolesService{userRolesRepo: userRolesRepo, rolesRepo: rolesRepo} } -func (s *UserRolesService) getUserRolesInternal(ctx context.Context, userID string) ([]types.UserRoleInfo, error) { +func (s *UserRolesService) GetUserRoles(ctx context.Context, actor *models.Actor, userID string) ([]types.UserRoleInfo, error) { if userID == "" { return nil, internalerrors.ErrUnprocessableEntity } @@ -30,19 +27,7 @@ func (s *UserRolesService) getUserRolesInternal(ctx context.Context, userID stri return s.userRolesRepo.GetUserRoles(ctx, userID) } -func (s *UserRolesService) GetUserRoles(ctx context.Context, actor *models.Actor, userID string) ([]types.UserRoleInfo, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesReadPermission); err != nil { - return nil, err - } - - return s.getUserRolesInternal(ctx, userID) -} - func (s *UserRolesService) ReplaceUserRoles(ctx context.Context, actor *models.Actor, userID string, roleIDs []string, assignedByUserID *string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesAssignPermission); err != nil { - return err - } - if userID == "" { return internalerrors.ErrBadRequest } @@ -88,10 +73,6 @@ func (s *UserRolesService) ReplaceUserRoles(ctx context.Context, actor *models.A } func (s *UserRolesService) AssignRoleToUser(ctx context.Context, actor *models.Actor, userID string, req types.AssignUserRoleRequest, assignedByUserID *string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesAssignPermission); err != nil { - return err - } - if userID == "" { return internalerrors.ErrBadRequest } @@ -120,18 +101,7 @@ func (s *UserRolesService) AssignRoleToUser(ctx context.Context, actor *models.A return s.userRolesRepo.AssignUserRole(ctx, userID, roleID, assignedByUserID, req.ExpiresAt) } -func (s *UserRolesService) assignRoleToUserInternal(ctx context.Context, userID string, roleID string, assignedByUserID *string) error { - if userID == "" || roleID == "" { - return internalerrors.ErrBadRequest - } - return s.userRolesRepo.AssignUserRole(ctx, userID, roleID, assignedByUserID, nil) -} - func (s *UserRolesService) RemoveRoleFromUser(ctx context.Context, actor *models.Actor, userID string, roleID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesRemovePermission); err != nil { - return err - } - if userID == "" || roleID == "" { return internalerrors.ErrBadRequest } diff --git a/plugins/access-control/services/user_roles_service_test.go b/plugins/access-control/services/user_roles_service_test.go index f8a5ee77..774dc59e 100644 --- a/plugins/access-control/services/user_roles_service_test.go +++ b/plugins/access-control/services/user_roles_service_test.go @@ -70,7 +70,7 @@ func TestUserRolesServiceAssignRoleToUser(t *testing.T) { tc.setup(userRolesRepo, rolesRepo) } - service := NewUserRolesService(userRolesRepo, rolesRepo, &internaltests.NoopAuthorizer{}) + service := NewUserRolesService(userRolesRepo, rolesRepo) err := service.AssignRoleToUser(context.Background(), internaltests.TestActor(), "user-1", tc.req, tc.assignedByUserID) if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) @@ -124,7 +124,7 @@ func TestUserRolesServiceReplaceUserRoles(t *testing.T) { tc.setup(userRolesRepo, rolesRepo) } - service := NewUserRolesService(userRolesRepo, rolesRepo, &internaltests.NoopAuthorizer{}) + service := NewUserRolesService(userRolesRepo, rolesRepo) err := service.ReplaceUserRoles(context.Background(), internaltests.TestActor(), "user-1", tc.roleIDs, tc.assignedByUserID) if err != tc.wantErr { t.Fatalf("expected err %v, got %v", tc.wantErr, err) diff --git a/plugins/access-control/usecases/permissions_usecase.go b/plugins/access-control/usecases/permissions_usecase.go index d20608ad..d4d575ae 100644 --- a/plugins/access-control/usecases/permissions_usecase.go +++ b/plugins/access-control/usecases/permissions_usecase.go @@ -4,38 +4,59 @@ import ( "context" "github.com/Authula/authula/models" + "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/services" "github.com/Authula/authula/plugins/access-control/types" + rootservices "github.com/Authula/authula/services" ) type PermissionsUseCase struct { - service *services.PermissionsService + service *services.PermissionsService + authorizer rootservices.Authorizer } -func NewPermissionsUseCase(service *services.PermissionsService) *PermissionsUseCase { - return &PermissionsUseCase{service: service} +func NewPermissionsUseCase(service *services.PermissionsService, authorizer rootservices.Authorizer) *PermissionsUseCase { + return &PermissionsUseCase{service: service, authorizer: authorizer} } func (u *PermissionsUseCase) CreatePermission(ctx context.Context, actor *models.Actor, req types.CreatePermissionRequest) (*types.Permission, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsCreatePermission); err != nil { + return nil, err + } return u.service.CreatePermission(ctx, actor, req) } func (u *PermissionsUseCase) GetAllPermissions(ctx context.Context, actor *models.Actor) ([]types.Permission, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsListPermission); err != nil { + return nil, err + } return u.service.GetAllPermissions(ctx, actor) } func (u *PermissionsUseCase) GetPermissionByID(ctx context.Context, actor *models.Actor, permissionID string) (*types.Permission, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsReadPermission); err != nil { + return nil, err + } return u.service.GetPermissionByID(ctx, actor, permissionID) } func (u *PermissionsUseCase) GetPermissionByKey(ctx context.Context, actor *models.Actor, permissionKey string) (*types.Permission, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsReadPermission); err != nil { + return nil, err + } return u.service.GetPermissionByKey(ctx, actor, permissionKey) } func (u *PermissionsUseCase) UpdatePermission(ctx context.Context, actor *models.Actor, permissionID string, req types.UpdatePermissionRequest) (*types.Permission, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsUpdatePermission); err != nil { + return nil, err + } return u.service.UpdatePermission(ctx, actor, permissionID, req) } func (u *PermissionsUseCase) DeletePermission(ctx context.Context, actor *models.Actor, permissionID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.PermissionsDeletePermission); err != nil { + return err + } return u.service.DeletePermission(ctx, actor, permissionID) } diff --git a/plugins/access-control/usecases/role_permission_usecase.go b/plugins/access-control/usecases/role_permission_usecase.go index 65147c8b..f7858d50 100644 --- a/plugins/access-control/usecases/role_permission_usecase.go +++ b/plugins/access-control/usecases/role_permission_usecase.go @@ -4,30 +4,45 @@ import ( "context" "github.com/Authula/authula/models" + "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/services" "github.com/Authula/authula/plugins/access-control/types" + rootservices "github.com/Authula/authula/services" ) type RolePermissionsUseCase struct { - service *services.RolePermissionsService + service *services.RolePermissionsService + authorizer rootservices.Authorizer } -func NewRolePermissionsUseCase(service *services.RolePermissionsService) *RolePermissionsUseCase { - return &RolePermissionsUseCase{service: service} +func NewRolePermissionsUseCase(service *services.RolePermissionsService, authorizer rootservices.Authorizer) *RolePermissionsUseCase { + return &RolePermissionsUseCase{service: service, authorizer: authorizer} } func (u *RolePermissionsUseCase) GetRolePermissions(ctx context.Context, actor *models.Actor, roleID string) ([]types.UserPermissionInfo, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsReadPermission); err != nil { + return nil, err + } return u.service.GetRolePermissions(ctx, actor, roleID) } func (u *RolePermissionsUseCase) AddPermissionToRole(ctx context.Context, actor *models.Actor, roleID string, permissionID string, grantedByUserID *string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsAssignPermission); err != nil { + return err + } return u.service.AddPermissionToRole(ctx, actor, roleID, permissionID, grantedByUserID) } func (u *RolePermissionsUseCase) RemovePermissionFromRole(ctx context.Context, actor *models.Actor, roleID string, permissionID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsRemovePermission); err != nil { + return err + } return u.service.RemovePermissionFromRole(ctx, actor, roleID, permissionID) } func (u *RolePermissionsUseCase) ReplaceRolePermissions(ctx context.Context, actor *models.Actor, roleID string, permissionIDs []string, grantedByUserID *string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.RolePermissionsAssignPermission); err != nil { + return err + } return u.service.ReplaceRolePermissions(ctx, actor, roleID, permissionIDs, grantedByUserID) } diff --git a/plugins/access-control/usecases/roles_usecase.go b/plugins/access-control/usecases/roles_usecase.go index 6042022e..23a76015 100644 --- a/plugins/access-control/usecases/roles_usecase.go +++ b/plugins/access-control/usecases/roles_usecase.go @@ -4,38 +4,59 @@ import ( "context" "github.com/Authula/authula/models" + accesscontrolconstants "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/services" "github.com/Authula/authula/plugins/access-control/types" + rootservices "github.com/Authula/authula/services" ) type RolesUseCase struct { - service *services.RolesService + service *services.RolesService + authorizer rootservices.Authorizer } -func NewRolesUseCase(service *services.RolesService) *RolesUseCase { - return &RolesUseCase{service: service} +func NewRolesUseCase(service *services.RolesService, authorizer rootservices.Authorizer) *RolesUseCase { + return &RolesUseCase{service: service, authorizer: authorizer} } func (u *RolesUseCase) CreateRole(ctx context.Context, actor *models.Actor, req types.CreateRoleRequest) (*types.Role, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesCreatePermission); err != nil { + return nil, err + } return u.service.CreateRole(ctx, actor, req) } func (u *RolesUseCase) GetAllRoles(ctx context.Context, actor *models.Actor) ([]types.Role, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesListPermission); err != nil { + return nil, err + } return u.service.GetAllRoles(ctx, actor) } func (u *RolesUseCase) GetRoleByName(ctx context.Context, actor *models.Actor, roleName string) (*types.Role, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesReadPermission); err != nil { + return nil, err + } return u.service.GetRoleByName(ctx, actor, roleName) } func (u *RolesUseCase) GetRoleByID(ctx context.Context, actor *models.Actor, roleID string) (*types.RoleDetails, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesReadPermission); err != nil { + return nil, err + } return u.service.GetRoleByID(ctx, actor, roleID) } func (u *RolesUseCase) UpdateRole(ctx context.Context, actor *models.Actor, roleID string, req types.UpdateRoleRequest) (*types.Role, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesUpdatePermission); err != nil { + return nil, err + } return u.service.UpdateRole(ctx, actor, roleID, req) } func (u *RolesUseCase) DeleteRole(ctx context.Context, actor *models.Actor, roleID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, accesscontrolconstants.RolesDeletePermission); err != nil { + return err + } return u.service.DeleteRole(ctx, actor, roleID) } diff --git a/plugins/access-control/usecases/user_permissions_usecase.go b/plugins/access-control/usecases/user_permissions_usecase.go index 4d228b96..8ea36967 100644 --- a/plugins/access-control/usecases/user_permissions_usecase.go +++ b/plugins/access-control/usecases/user_permissions_usecase.go @@ -3,27 +3,40 @@ package usecases import ( "context" + internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" + "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/services" "github.com/Authula/authula/plugins/access-control/types" + rootservices "github.com/Authula/authula/services" ) type UserPermissionsUseCase struct { - service *services.UserPermissionsService + service *services.UserPermissionsService + authorizer rootservices.Authorizer } -func NewUserPermissionsUseCase(service *services.UserPermissionsService) *UserPermissionsUseCase { - return &UserPermissionsUseCase{service: service} +func NewUserPermissionsUseCase(service *services.UserPermissionsService, authorizer rootservices.Authorizer) *UserPermissionsUseCase { + return &UserPermissionsUseCase{service: service, authorizer: authorizer} } func (u *UserPermissionsUseCase) GetSelfUserPermissions(ctx context.Context, actor *models.Actor, userID string) ([]types.UserPermissionInfo, error) { - return u.service.GetSelfUserPermissions(ctx, actor, userID) + if actor.ID != userID { + return nil, internalerrors.ErrForbidden + } + return u.service.GetUserPermissions(ctx, actor, userID) } func (u *UserPermissionsUseCase) GetUserPermissions(ctx context.Context, actor *models.Actor, userID string) ([]types.UserPermissionInfo, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserPermissionsReadPermission); err != nil { + return nil, err + } return u.service.GetUserPermissions(ctx, actor, userID) } func (u *UserPermissionsUseCase) HasPermissions(ctx context.Context, actor *models.Actor, userID string, permissionKeys []string) (bool, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserPermissionsCheckPermission); err != nil { + return false, err + } return u.service.HasPermissions(ctx, actor, userID, permissionKeys) } diff --git a/plugins/access-control/usecases/user_roles_usecase.go b/plugins/access-control/usecases/user_roles_usecase.go index 131bbcb6..09bfd541 100644 --- a/plugins/access-control/usecases/user_roles_usecase.go +++ b/plugins/access-control/usecases/user_roles_usecase.go @@ -4,30 +4,45 @@ import ( "context" "github.com/Authula/authula/models" + "github.com/Authula/authula/plugins/access-control/constants" "github.com/Authula/authula/plugins/access-control/services" "github.com/Authula/authula/plugins/access-control/types" + rootservices "github.com/Authula/authula/services" ) type UserRolesUseCase struct { - service *services.UserRolesService + service *services.UserRolesService + authorizer rootservices.Authorizer } -func NewUserRolesUseCase(service *services.UserRolesService) *UserRolesUseCase { - return &UserRolesUseCase{service: service} +func NewUserRolesUseCase(service *services.UserRolesService, authorizer rootservices.Authorizer) *UserRolesUseCase { + return &UserRolesUseCase{service: service, authorizer: authorizer} } func (u *UserRolesUseCase) GetUserRoles(ctx context.Context, actor *models.Actor, userID string) ([]types.UserRoleInfo, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesReadPermission); err != nil { + return nil, err + } return u.service.GetUserRoles(ctx, actor, userID) } func (u *UserRolesUseCase) ReplaceUserRoles(ctx context.Context, actor *models.Actor, userID string, roleIDs []string, assignedByUserID *string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesAssignPermission); err != nil { + return err + } return u.service.ReplaceUserRoles(ctx, actor, userID, roleIDs, assignedByUserID) } func (u *UserRolesUseCase) AssignRoleToUser(ctx context.Context, actor *models.Actor, userID string, req types.AssignUserRoleRequest, assignedByUserID *string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesAssignPermission); err != nil { + return err + } return u.service.AssignRoleToUser(ctx, actor, userID, req, assignedByUserID) } func (u *UserRolesUseCase) RemoveRoleFromUser(ctx context.Context, actor *models.Actor, userID string, roleID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, constants.UserRolesRemovePermission); err != nil { + return err + } return u.service.RemoveRoleFromUser(ctx, actor, userID, roleID) } diff --git a/plugins/admin/services/accounts_service.go b/plugins/admin/services/accounts_service.go index d31be1ef..f95f1c8a 100644 --- a/plugins/admin/services/accounts_service.go +++ b/plugins/admin/services/accounts_service.go @@ -8,7 +8,6 @@ import ( corerepositories "github.com/Authula/authula/internal/repositories" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/types" rootservices "github.com/Authula/authula/services" ) @@ -17,29 +16,21 @@ type AccountsService struct { accountRepo corerepositories.AccountRepository userRepo corerepositories.UserRepository passwordService rootservices.PasswordService - authorizer rootservices.Authorizer } func NewAccountsService( accountRepo corerepositories.AccountRepository, userRepo corerepositories.UserRepository, passwordService rootservices.PasswordService, - authorizer rootservices.Authorizer, ) *AccountsService { - return &AccountsService{accountRepo: accountRepo, userRepo: userRepo, passwordService: passwordService, authorizer: authorizer} + return &AccountsService{accountRepo: accountRepo, userRepo: userRepo, passwordService: passwordService} } func (s *AccountsService) GetByID(ctx context.Context, actor *models.Actor, accountID string) (*models.Account, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsReadPermission); err != nil { - return nil, err - } return s.accountRepo.GetByID(ctx, accountID) } func (s *AccountsService) GetByUserID(ctx context.Context, actor *models.Actor, userID string) ([]models.Account, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsListPermission); err != nil { - return nil, err - } user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return nil, err @@ -52,9 +43,6 @@ func (s *AccountsService) GetByUserID(ctx context.Context, actor *models.Actor, } func (s *AccountsService) Create(ctx context.Context, actor *models.Actor, userID string, request types.CreateAccountRequest) (*models.Account, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsCreatePermission); err != nil { - return nil, err - } user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return nil, err @@ -101,9 +89,6 @@ func (s *AccountsService) Create(ctx context.Context, actor *models.Actor, userI } func (s *AccountsService) Update(ctx context.Context, actor *models.Actor, accountID string, request types.UpdateAccountRequest) (*models.Account, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsUpdatePermission); err != nil { - return nil, err - } account, err := s.accountRepo.GetByID(ctx, accountID) if err != nil { return nil, err @@ -151,9 +136,6 @@ func (s *AccountsService) Update(ctx context.Context, actor *models.Actor, accou } func (s *AccountsService) Delete(ctx context.Context, actor *models.Actor, accountID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsDeletePermission); err != nil { - return err - } account, err := s.accountRepo.GetByID(ctx, accountID) if err != nil { return err diff --git a/plugins/admin/services/impersonation_service.go b/plugins/admin/services/impersonation_service.go index 5f0af363..08e3003a 100644 --- a/plugins/admin/services/impersonation_service.go +++ b/plugins/admin/services/impersonation_service.go @@ -8,7 +8,6 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/repositories" "github.com/Authula/authula/plugins/admin/types" rootservices "github.com/Authula/authula/services" @@ -21,7 +20,6 @@ type ImpersonationService struct { tokenService rootservices.TokenService sessionExpiresIn time.Duration maxExpiresIn time.Duration - authorizer rootservices.Authorizer } func NewImpersonationService( @@ -31,7 +29,6 @@ func NewImpersonationService( tokenService rootservices.TokenService, sessionExpiresIn time.Duration, maxExpiresIn time.Duration, - authorizer rootservices.Authorizer, ) *ImpersonationService { if maxExpiresIn <= 0 { maxExpiresIn = 15 * time.Minute @@ -47,21 +44,14 @@ func NewImpersonationService( tokenService: tokenService, sessionExpiresIn: sessionExpiresIn, maxExpiresIn: maxExpiresIn, - authorizer: authorizer, } } func (s *ImpersonationService) GetAllImpersonations(ctx context.Context, actor *models.Actor) ([]types.Impersonation, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsListPermission); err != nil { - return nil, err - } return s.impersonationRepo.GetAllImpersonations(ctx) } func (s *ImpersonationService) GetImpersonationByID(ctx context.Context, actor *models.Actor, impersonationID string) (*types.Impersonation, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsReadPermission); err != nil { - return nil, err - } impersonationID = strings.TrimSpace(impersonationID) if impersonationID == "" { return nil, internalerrors.ErrBadRequest @@ -90,9 +80,6 @@ func (s *ImpersonationService) StartImpersonation( originalCookieValue string, originalCookieMaxAge int, ) (*types.StartImpersonationResult, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsStartPermission); err != nil { - return nil, err - } actorUserID = strings.TrimSpace(actorUserID) targetUserID := strings.TrimSpace(req.TargetUserID) reason := strings.TrimSpace(req.Reason) @@ -231,9 +218,6 @@ func (s *ImpersonationService) ValidateImpersonationCookie(ctx context.Context, } func (s *ImpersonationService) StopImpersonation(ctx context.Context, actor *models.Actor, actorUserID string, request types.StopImpersonationRequest) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsStopPermission); err != nil { - return err - } actorUserID = strings.TrimSpace(actorUserID) if actorUserID == "" { return internalerrors.ErrBadRequest diff --git a/plugins/admin/services/impersonation_service_test.go b/plugins/admin/services/impersonation_service_test.go index b5df4d8e..5bb5cfc2 100644 --- a/plugins/admin/services/impersonation_service_test.go +++ b/plugins/admin/services/impersonation_service_test.go @@ -123,7 +123,7 @@ func TestImpersonationService_StartImpersonation_noSessionServices(t *testing.T) impRepo := &admintests.MockImpersonationRepository{} sessRepo := &admintests.MockSessionStateRepository{} // Use constructor to create service with nil session/token services - svc := adminservices.NewImpersonationService(impRepo, sessRepo, nil, nil, time.Minute, time.Minute, &internaltests.NoopAuthorizer{}) + svc := adminservices.NewImpersonationService(impRepo, sessRepo, nil, nil, time.Minute, time.Minute) ctx := context.Background() impRepo.On("UserExists", mock.Anything, "actor").Return(true, nil).Once() diff --git a/plugins/admin/services/state_service.go b/plugins/admin/services/state_service.go index 652fb19f..23bef810 100644 --- a/plugins/admin/services/state_service.go +++ b/plugins/admin/services/state_service.go @@ -6,34 +6,25 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/repositories" "github.com/Authula/authula/plugins/admin/types" - rootservices "github.com/Authula/authula/services" ) type StateService struct { userStateRepo repositories.UserStateRepository sessionStateRepo repositories.SessionStateRepository impersonationRepo repositories.ImpersonationRepository - authorizer rootservices.Authorizer } -func NewStateService(userStateRepo repositories.UserStateRepository, sessionStateRepo repositories.SessionStateRepository, impersonationRepo repositories.ImpersonationRepository, authorizer rootservices.Authorizer) *StateService { - return &StateService{userStateRepo: userStateRepo, sessionStateRepo: sessionStateRepo, impersonationRepo: impersonationRepo, authorizer: authorizer} +func NewStateService(userStateRepo repositories.UserStateRepository, sessionStateRepo repositories.SessionStateRepository, impersonationRepo repositories.ImpersonationRepository) *StateService { + return &StateService{userStateRepo: userStateRepo, sessionStateRepo: sessionStateRepo, impersonationRepo: impersonationRepo} } func (s *StateService) GetUserState(ctx context.Context, actor *models.Actor, userID string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateReadPermission); err != nil { - return nil, err - } return s.userStateRepo.GetByUserID(ctx, userID) } func (s *StateService) CreateUserState(ctx context.Context, actor *models.Actor, userID string, request types.CreateUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateCreatePermission); err != nil { - return nil, err - } exists, err := s.impersonationRepo.UserExists(ctx, userID) if err != nil { return nil, err @@ -59,9 +50,6 @@ func (s *StateService) CreateUserState(ctx context.Context, actor *models.Actor, } func (s *StateService) UpdateUserState(ctx context.Context, actor *models.Actor, userID string, request types.UpsertUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUpdatePermission); err != nil { - return nil, err - } exists, err := s.impersonationRepo.UserExists(ctx, userID) if err != nil { return nil, err @@ -87,9 +75,6 @@ func (s *StateService) UpdateUserState(ctx context.Context, actor *models.Actor, } func (s *StateService) UpsertUserState(ctx context.Context, actor *models.Actor, userID string, request types.UpsertUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUpdatePermission); err != nil { - return nil, err - } exists, err := s.impersonationRepo.UserExists(ctx, userID) if err != nil { return nil, err @@ -108,16 +93,10 @@ func (s *StateService) UpsertUserState(ctx context.Context, actor *models.Actor, } func (s *StateService) DeleteUserState(ctx context.Context, actor *models.Actor, userID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateDeletePermission); err != nil { - return err - } return s.userStateRepo.Delete(ctx, userID) } func (s *StateService) GetBannedUserStates(ctx context.Context, actor *models.Actor) ([]types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateListBannedPermission); err != nil { - return nil, err - } return s.userStateRepo.GetBanned(ctx) } @@ -133,16 +112,10 @@ func (s *StateService) GetSelfSessionState(ctx context.Context, sessionID string } func (s *StateService) GetSessionState(ctx context.Context, actor *models.Actor, sessionID string) (*types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateReadPermission); err != nil { - return nil, err - } return s.sessionStateRepo.GetBySessionID(ctx, sessionID) } func (s *StateService) CreateSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.CreateSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateCreatePermission); err != nil { - return nil, err - } exists, err := s.sessionStateRepo.SessionExists(ctx, sessionID) if err != nil { return nil, err @@ -168,9 +141,6 @@ func (s *StateService) CreateSessionState(ctx context.Context, actor *models.Act } func (s *StateService) UpdateSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.UpsertSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateUpdatePermission); err != nil { - return nil, err - } exists, err := s.sessionStateRepo.SessionExists(ctx, sessionID) if err != nil { return nil, err @@ -196,9 +166,6 @@ func (s *StateService) UpdateSessionState(ctx context.Context, actor *models.Act } func (s *StateService) UpsertSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.UpsertSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateUpdatePermission); err != nil { - return nil, err - } exists, err := s.sessionStateRepo.SessionExists(ctx, sessionID) if err != nil { return nil, err @@ -217,16 +184,10 @@ func (s *StateService) UpsertSessionState(ctx context.Context, actor *models.Act } func (s *StateService) DeleteSessionState(ctx context.Context, actor *models.Actor, sessionID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateDeletePermission); err != nil { - return err - } return s.sessionStateRepo.Delete(ctx, sessionID) } func (s *StateService) GetUserAdminSessions(ctx context.Context, actor *models.Actor, userID string) ([]types.AdminUserSession, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateListSessionsPermission); err != nil { - return nil, err - } exists, err := s.impersonationRepo.UserExists(ctx, userID) if err != nil { return nil, err @@ -239,9 +200,6 @@ func (s *StateService) GetUserAdminSessions(ctx context.Context, actor *models.A } func (s *StateService) RevokeSession(ctx context.Context, actor *models.Actor, sessionID string, reason *string, actorUserID *string) (*types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateRevokePermission); err != nil { - return nil, err - } return s.UpsertSessionState(ctx, actor, sessionID, types.UpsertSessionStateRequest{ Revoke: true, RevokedReason: reason, @@ -249,16 +207,10 @@ func (s *StateService) RevokeSession(ctx context.Context, actor *models.Actor, s } func (s *StateService) GetRevokedSessionStates(ctx context.Context, actor *models.Actor) ([]types.AdminSessionState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateListRevokedPermission); err != nil { - return nil, err - } return s.sessionStateRepo.GetRevoked(ctx) } func (s *StateService) BanUser(ctx context.Context, actor *models.Actor, userID string, request types.BanUserRequest, actorUserID *string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateBanPermission); err != nil { - return nil, err - } return s.UpsertUserState(ctx, actor, userID, types.UpsertUserStateRequest{ Banned: true, BannedUntil: request.BannedUntil, @@ -267,9 +219,6 @@ func (s *StateService) BanUser(ctx context.Context, actor *models.Actor, userID } func (s *StateService) UnbanUser(ctx context.Context, actor *models.Actor, userID string) (*types.AdminUserState, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUnbanPermission); err != nil { - return nil, err - } return s.UpsertUserState(ctx, actor, userID, types.UpsertUserStateRequest{Banned: false}, nil) } diff --git a/plugins/admin/services/users_service.go b/plugins/admin/services/users_service.go index 15093dc5..b070b99d 100644 --- a/plugins/admin/services/users_service.go +++ b/plugins/admin/services/users_service.go @@ -7,24 +7,18 @@ import ( repositories "github.com/Authula/authula/internal/repositories" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/types" - rootservices "github.com/Authula/authula/services" ) type UsersService struct { - userRepo repositories.UserRepository - authorizer rootservices.Authorizer + userRepo repositories.UserRepository } -func NewUsersService(userRepo repositories.UserRepository, authorizer rootservices.Authorizer) *UsersService { - return &UsersService{userRepo: userRepo, authorizer: authorizer} +func NewUsersService(userRepo repositories.UserRepository) *UsersService { + return &UsersService{userRepo: userRepo} } func (s *UsersService) Create(ctx context.Context, actor *models.Actor, request types.CreateUserRequest) (*models.User, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersCreatePermission); err != nil { - return nil, err - } existing, err := s.userRepo.GetByEmail(ctx, request.Email) if err != nil { return nil, err @@ -50,9 +44,6 @@ func (s *UsersService) Create(ctx context.Context, actor *models.Actor, request } func (s *UsersService) GetAll(ctx context.Context, actor *models.Actor, cursor *string, limit int) (*types.UsersPage, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersListPermission); err != nil { - return nil, err - } users, nextCursor, err := s.userRepo.GetAll(ctx, cursor, limit) if err != nil { return nil, err @@ -62,16 +53,10 @@ func (s *UsersService) GetAll(ctx context.Context, actor *models.Actor, cursor * } func (s *UsersService) GetByID(ctx context.Context, actor *models.Actor, userID string) (*models.User, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersReadPermission); err != nil { - return nil, err - } return s.userRepo.GetByID(ctx, userID) } func (s *UsersService) Update(ctx context.Context, actor *models.Actor, userID string, request types.UpdateUserRequest) (*models.User, error) { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersUpdatePermission); err != nil { - return nil, err - } user, err := s.userRepo.GetByID(ctx, userID) if err != nil { return nil, err @@ -105,9 +90,6 @@ func (s *UsersService) Update(ctx context.Context, actor *models.Actor, userID s } func (s *UsersService) Delete(ctx context.Context, actor *models.Actor, userID string) error { - if err := s.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersDeletePermission); err != nil { - return err - } existing, err := s.userRepo.GetByID(ctx, userID) if err != nil { return err diff --git a/plugins/admin/services/users_service_test.go b/plugins/admin/services/users_service_test.go index 6f8ba5a4..6d79eaf8 100644 --- a/plugins/admin/services/users_service_test.go +++ b/plugins/admin/services/users_service_test.go @@ -17,7 +17,7 @@ import ( func newUsersServiceFixture() (*adminservices.UsersService, *internaltests.MockUserRepository) { repo := &internaltests.MockUserRepository{} - return adminservices.NewUsersService(repo, &internaltests.NoopAuthorizer{}), repo + return adminservices.NewUsersService(repo), repo } func TestUsersService_Create(t *testing.T) { diff --git a/plugins/admin/tests/test_helpers.go b/plugins/admin/tests/test_helpers.go index b5310b28..47ff2954 100644 --- a/plugins/admin/tests/test_helpers.go +++ b/plugins/admin/tests/test_helpers.go @@ -27,8 +27,8 @@ func PtrTime(t *testing.T, offset int) *time.Time { func NewUsersUseCaseFixture() (usecases.UsersUseCase, *internaltests.MockUserRepository) { mockUserRepo := &internaltests.MockUserRepository{} - service := adminservices.NewUsersService(mockUserRepo, &internaltests.NoopAuthorizer{}) - return usecases.NewUsersUseCase(service), mockUserRepo + service := adminservices.NewUsersService(mockUserRepo) + return usecases.NewUsersUseCase(service, &internaltests.NoopAuthorizer{}), mockUserRepo } type MockPasswordService struct { @@ -49,15 +49,15 @@ func NewAccountsUseCaseFixture() (usecases.AccountsUseCase, *adminservices.Accou accountRepo := &internaltests.MockAccountRepository{} userRepo := &internaltests.MockUserRepository{} passwordSvc := &MockPasswordService{} - service := adminservices.NewAccountsService(accountRepo, userRepo, passwordSvc, &internaltests.NoopAuthorizer{}) - return usecases.NewAccountsUseCase(service), service, accountRepo, userRepo, passwordSvc + service := adminservices.NewAccountsService(accountRepo, userRepo, passwordSvc) + return usecases.NewAccountsUseCase(service, &internaltests.NoopAuthorizer{}), service, accountRepo, userRepo, passwordSvc } func NewAccountsServiceFixture() (*adminservices.AccountsService, *internaltests.MockAccountRepository, *internaltests.MockUserRepository, *MockPasswordService) { accountRepo := &internaltests.MockAccountRepository{} userRepo := &internaltests.MockUserRepository{} passwordSvc := &MockPasswordService{} - return adminservices.NewAccountsService(accountRepo, userRepo, passwordSvc, &internaltests.NoopAuthorizer{}), accountRepo, userRepo, passwordSvc + return adminservices.NewAccountsService(accountRepo, userRepo, passwordSvc), accountRepo, userRepo, passwordSvc } type MockUserStateRepository struct { @@ -210,17 +210,17 @@ func NewImpersonationUseCaseFixture(t *testing.T) (usecases.ImpersonationUseCase sessionStateRepo := &MockSessionStateRepository{} sessionSvc := &internaltests.MockSessionService{} tokenSvc := &internaltests.MockTokenService{} - stateService := adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo, &internaltests.NoopAuthorizer{}) - service := adminservices.NewImpersonationService(impRepo, sessionStateRepo, sessionSvc, tokenSvc, 15*time.Minute, 15*time.Minute, &internaltests.NoopAuthorizer{}) - return usecases.NewImpersonationUseCase(stateService, service), impRepo, sessionStateRepo, sessionSvc, tokenSvc + stateService := adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo) + service := adminservices.NewImpersonationService(impRepo, sessionStateRepo, sessionSvc, tokenSvc, 15*time.Minute, 15*time.Minute) + return usecases.NewImpersonationUseCase(stateService, service, &internaltests.NoopAuthorizer{}), impRepo, sessionStateRepo, sessionSvc, tokenSvc } func NewStateUseCaseFixture() (usecases.StateUseCase, *MockUserStateRepository, *MockSessionStateRepository, *MockImpersonationRepository) { userStateRepo := &MockUserStateRepository{} sessionStateRepo := &MockSessionStateRepository{} impRepo := &MockImpersonationRepository{} - service := adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo, &internaltests.NoopAuthorizer{}) - return usecases.NewStateUseCase(service), userStateRepo, sessionStateRepo, impRepo + service := adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo) + return usecases.NewStateUseCase(service, &internaltests.NoopAuthorizer{}), userStateRepo, sessionStateRepo, impRepo } func BuildAccountModel(id, userID, providerID, accountID string) *models.Account { @@ -232,7 +232,7 @@ func NewStateServiceFixture() (*adminservices.StateService, *MockUserStateReposi userStateRepo := &MockUserStateRepository{} sessionStateRepo := &MockSessionStateRepository{} impRepo := &MockImpersonationRepository{} - return adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo, &internaltests.NoopAuthorizer{}), userStateRepo, sessionStateRepo, impRepo + return adminservices.NewStateService(userStateRepo, sessionStateRepo, impRepo), userStateRepo, sessionStateRepo, impRepo } // impersonation service fixture returns service and all repos + helpers @@ -241,6 +241,6 @@ func NewImpersonationServiceFixture() (*adminservices.ImpersonationService, *Moc sessionStateRepo := &MockSessionStateRepository{} sessSvc := &internaltests.MockSessionService{} tokenSvc := &internaltests.MockTokenService{} - service := adminservices.NewImpersonationService(impRepo, sessionStateRepo, sessSvc, tokenSvc, 15*time.Minute, 15*time.Minute, &internaltests.NoopAuthorizer{}) + service := adminservices.NewImpersonationService(impRepo, sessionStateRepo, sessSvc, tokenSvc, 15*time.Minute, 15*time.Minute) return service, impRepo, sessionStateRepo, sessSvc, tokenSvc } diff --git a/plugins/admin/usecases/accounts_usecase.go b/plugins/admin/usecases/accounts_usecase.go index 0ba634ee..932dd136 100644 --- a/plugins/admin/usecases/accounts_usecase.go +++ b/plugins/admin/usecases/accounts_usecase.go @@ -9,17 +9,22 @@ import ( adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/services" "github.com/Authula/authula/plugins/admin/types" + rootservices "github.com/Authula/authula/services" ) type AccountsUseCase struct { - service *services.AccountsService + service *services.AccountsService + authorizer rootservices.Authorizer } -func NewAccountsUseCase(service *services.AccountsService) AccountsUseCase { - return AccountsUseCase{service: service} +func NewAccountsUseCase(service *services.AccountsService, authorizer rootservices.Authorizer) AccountsUseCase { + return AccountsUseCase{service: service, authorizer: authorizer} } func (u AccountsUseCase) GetByID(ctx context.Context, actor *models.Actor, accountID string) (*models.Account, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsReadPermission); err != nil { + return nil, err + } accountID = strings.TrimSpace(accountID) if accountID == "" { return nil, internalerrors.ErrBadRequest @@ -28,6 +33,9 @@ func (u AccountsUseCase) GetByID(ctx context.Context, actor *models.Actor, accou } func (u AccountsUseCase) GetByUserID(ctx context.Context, actor *models.Actor, userID string) ([]models.Account, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsListPermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, adminconstants.ErrUserIDRequired @@ -36,6 +44,9 @@ func (u AccountsUseCase) GetByUserID(ctx context.Context, actor *models.Actor, u } func (u AccountsUseCase) Create(ctx context.Context, actor *models.Actor, userID string, request types.CreateAccountRequest) (*models.Account, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsCreatePermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) request.ProviderID = strings.TrimSpace(strings.ToLower(request.ProviderID)) request.AccountID = strings.TrimSpace(request.AccountID) @@ -55,6 +66,9 @@ func (u AccountsUseCase) Create(ctx context.Context, actor *models.Actor, userID } func (u AccountsUseCase) Update(ctx context.Context, actor *models.Actor, accountID string, request types.UpdateAccountRequest) (*models.Account, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsUpdatePermission); err != nil { + return nil, err + } accountID = strings.TrimSpace(accountID) if accountID == "" { return nil, internalerrors.ErrBadRequest @@ -89,6 +103,9 @@ func (u AccountsUseCase) Update(ctx context.Context, actor *models.Actor, accoun } func (u AccountsUseCase) Delete(ctx context.Context, actor *models.Actor, accountID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.AccountsDeletePermission); err != nil { + return err + } accountID = strings.TrimSpace(accountID) if accountID == "" { return internalerrors.ErrBadRequest diff --git a/plugins/admin/usecases/admin_usecases.go b/plugins/admin/usecases/admin_usecases.go index e0a7897d..c7cc914d 100644 --- a/plugins/admin/usecases/admin_usecases.go +++ b/plugins/admin/usecases/admin_usecases.go @@ -32,8 +32,8 @@ func NewAdminUseCases( sessionExpiresIn time.Duration, authorizer rootservices.Authorizer, ) *AdminUseCases { - usersService := services.NewUsersService(userRepo, authorizer) - accountsService := services.NewAccountsService(accountRepo, userRepo, passwordService, authorizer) + usersService := services.NewUsersService(userRepo) + accountsService := services.NewAccountsService(accountRepo, userRepo, passwordService) impersonationService := services.NewImpersonationService( impersonationRepo, sessionStateRepo, @@ -41,15 +41,14 @@ func NewAdminUseCases( tokenService, sessionExpiresIn, config.ImpersonationMaxExpiresIn, - authorizer, ) - stateService := services.NewStateService(userStateRepo, sessionStateRepo, impersonationRepo, authorizer) + stateService := services.NewStateService(userStateRepo, sessionStateRepo, impersonationRepo) return &AdminUseCases{ - users: NewUsersUseCase(usersService), - accounts: NewAccountsUseCase(accountsService), - state: NewStateUseCase(stateService), - impersonation: NewImpersonationUseCase(stateService, impersonationService), + users: NewUsersUseCase(usersService, authorizer), + accounts: NewAccountsUseCase(accountsService, authorizer), + state: NewStateUseCase(stateService, authorizer), + impersonation: NewImpersonationUseCase(stateService, impersonationService, authorizer), } } diff --git a/plugins/admin/usecases/impersonation_usecase.go b/plugins/admin/usecases/impersonation_usecase.go index e39c2454..45deba06 100644 --- a/plugins/admin/usecases/impersonation_usecase.go +++ b/plugins/admin/usecases/impersonation_usecase.go @@ -8,36 +8,52 @@ import ( adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/services" "github.com/Authula/authula/plugins/admin/types" + rootservices "github.com/Authula/authula/services" ) type ImpersonationUseCase struct { stateService *services.StateService impersonationService *services.ImpersonationService + authorizer rootservices.Authorizer } func NewImpersonationUseCase( stateService *services.StateService, impersonationService *services.ImpersonationService, + authorizer rootservices.Authorizer, ) ImpersonationUseCase { return ImpersonationUseCase{ stateService: stateService, impersonationService: impersonationService, + authorizer: authorizer, } } func (u ImpersonationUseCase) GetAllImpersonations(ctx context.Context, actor *models.Actor) ([]types.Impersonation, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsListPermission); err != nil { + return nil, err + } return u.impersonationService.GetAllImpersonations(ctx, actor) } func (u ImpersonationUseCase) GetImpersonationByID(ctx context.Context, actor *models.Actor, impersonationID string) (*types.Impersonation, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsReadPermission); err != nil { + return nil, err + } return u.impersonationService.GetImpersonationByID(ctx, actor, impersonationID) } func (u ImpersonationUseCase) StartImpersonation(ctx context.Context, actor *models.Actor, actorUserID string, actorSessionID *string, ipAddress *string, userAgent *string, req types.StartImpersonationRequest, impersonatorScopes []string, originalCookieValue string, originalCookieMaxAge int) (*types.StartImpersonationResult, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsStartPermission); err != nil { + return nil, err + } return u.impersonationService.StartImpersonation(ctx, actor, actorUserID, actorSessionID, ipAddress, userAgent, req, impersonatorScopes, originalCookieValue, originalCookieMaxAge) } func (u ImpersonationUseCase) StopImpersonation(ctx context.Context, actor *models.Actor, impersonatedUserID string, impersonatedSessionID string, originalCookieValue string, request types.StopImpersonationRequest) (*types.StopImpersonationResult, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.ImpersonationsStopPermission); err != nil { + return nil, err + } sessionState, err := u.stateService.GetSessionState(ctx, actor, impersonatedSessionID) if err != nil { return nil, err diff --git a/plugins/admin/usecases/state_usecase.go b/plugins/admin/usecases/state_usecase.go index f6f1c777..54488e8f 100644 --- a/plugins/admin/usecases/state_usecase.go +++ b/plugins/admin/usecases/state_usecase.go @@ -6,19 +6,25 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" + adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/services" "github.com/Authula/authula/plugins/admin/types" + rootservices "github.com/Authula/authula/services" ) type StateUseCase struct { - service *services.StateService + service *services.StateService + authorizer rootservices.Authorizer } -func NewStateUseCase(service *services.StateService) StateUseCase { - return StateUseCase{service: service} +func NewStateUseCase(service *services.StateService, authorizer rootservices.Authorizer) StateUseCase { + return StateUseCase{service: service, authorizer: authorizer} } func (u StateUseCase) GetUserState(ctx context.Context, actor *models.Actor, userID string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateReadPermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, internalerrors.ErrBadRequest @@ -28,6 +34,9 @@ func (u StateUseCase) GetUserState(ctx context.Context, actor *models.Actor, use } func (u StateUseCase) UpsertUserState(ctx context.Context, actor *models.Actor, userID string, request types.UpsertUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUpdatePermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, internalerrors.ErrBadRequest @@ -37,6 +46,9 @@ func (u StateUseCase) UpsertUserState(ctx context.Context, actor *models.Actor, } func (u StateUseCase) CreateUserState(ctx context.Context, actor *models.Actor, userID string, request types.CreateUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateCreatePermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, internalerrors.ErrBadRequest @@ -46,6 +58,9 @@ func (u StateUseCase) CreateUserState(ctx context.Context, actor *models.Actor, } func (u StateUseCase) UpdateUserState(ctx context.Context, actor *models.Actor, userID string, request types.UpsertUserStateRequest, actorUserID *string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUpdatePermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, internalerrors.ErrBadRequest @@ -55,6 +70,9 @@ func (u StateUseCase) UpdateUserState(ctx context.Context, actor *models.Actor, } func (u StateUseCase) DeleteUserState(ctx context.Context, actor *models.Actor, userID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateDeletePermission); err != nil { + return err + } userID = strings.TrimSpace(userID) if userID == "" { return internalerrors.ErrBadRequest @@ -64,10 +82,16 @@ func (u StateUseCase) DeleteUserState(ctx context.Context, actor *models.Actor, } func (u StateUseCase) GetBannedUserStates(ctx context.Context, actor *models.Actor) ([]types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateListBannedPermission); err != nil { + return nil, err + } return u.service.GetBannedUserStates(ctx, actor) } func (u StateUseCase) GetSessionState(ctx context.Context, actor *models.Actor, sessionID string) (*types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateReadPermission); err != nil { + return nil, err + } sessionID = strings.TrimSpace(sessionID) if sessionID == "" { return nil, internalerrors.ErrBadRequest @@ -77,6 +101,9 @@ func (u StateUseCase) GetSessionState(ctx context.Context, actor *models.Actor, } func (u StateUseCase) UpsertSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.UpsertSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateUpdatePermission); err != nil { + return nil, err + } sessionID = strings.TrimSpace(sessionID) if sessionID == "" { return nil, internalerrors.ErrBadRequest @@ -86,6 +113,9 @@ func (u StateUseCase) UpsertSessionState(ctx context.Context, actor *models.Acto } func (u StateUseCase) CreateSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.CreateSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateCreatePermission); err != nil { + return nil, err + } sessionID = strings.TrimSpace(sessionID) if sessionID == "" { return nil, internalerrors.ErrBadRequest @@ -95,6 +125,9 @@ func (u StateUseCase) CreateSessionState(ctx context.Context, actor *models.Acto } func (u StateUseCase) UpdateSessionState(ctx context.Context, actor *models.Actor, sessionID string, request types.UpsertSessionStateRequest, actorUserID *string) (*types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateUpdatePermission); err != nil { + return nil, err + } sessionID = strings.TrimSpace(sessionID) if sessionID == "" { return nil, internalerrors.ErrBadRequest @@ -104,6 +137,9 @@ func (u StateUseCase) UpdateSessionState(ctx context.Context, actor *models.Acto } func (u StateUseCase) DeleteSessionState(ctx context.Context, actor *models.Actor, sessionID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateDeletePermission); err != nil { + return err + } sessionID = strings.TrimSpace(sessionID) if sessionID == "" { return internalerrors.ErrBadRequest @@ -131,6 +167,9 @@ func (u StateUseCase) GetSelfSessionState(ctx context.Context, sessionID string) } func (u StateUseCase) GetUserAdminSessions(ctx context.Context, actor *models.Actor, userID string) ([]types.AdminUserSession, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateListSessionsPermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { return nil, internalerrors.ErrBadRequest @@ -140,17 +179,29 @@ func (u StateUseCase) GetUserAdminSessions(ctx context.Context, actor *models.Ac } func (u StateUseCase) RevokeSession(ctx context.Context, actor *models.Actor, sessionID string, reason *string, actorUserID *string) (*types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateRevokePermission); err != nil { + return nil, err + } return u.service.RevokeSession(ctx, actor, sessionID, reason, actorUserID) } func (u StateUseCase) GetRevokedSessionStates(ctx context.Context, actor *models.Actor) ([]types.AdminSessionState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.SessionStateListRevokedPermission); err != nil { + return nil, err + } return u.service.GetRevokedSessionStates(ctx, actor) } func (u StateUseCase) BanUser(ctx context.Context, actor *models.Actor, userID string, request types.BanUserRequest, actorUserID *string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateBanPermission); err != nil { + return nil, err + } return u.service.BanUser(ctx, actor, userID, request, actorUserID) } func (u StateUseCase) UnbanUser(ctx context.Context, actor *models.Actor, userID string) (*types.AdminUserState, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UserStateUnbanPermission); err != nil { + return nil, err + } return u.service.UnbanUser(ctx, actor, userID) } diff --git a/plugins/admin/usecases/users_usecase.go b/plugins/admin/usecases/users_usecase.go index 45b7ba53..cd8a0bbc 100644 --- a/plugins/admin/usecases/users_usecase.go +++ b/plugins/admin/usecases/users_usecase.go @@ -6,20 +6,25 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/admin/constants" + adminconstants "github.com/Authula/authula/plugins/admin/constants" "github.com/Authula/authula/plugins/admin/services" "github.com/Authula/authula/plugins/admin/types" + rootservices "github.com/Authula/authula/services" ) type UsersUseCase struct { - service *services.UsersService + service *services.UsersService + authorizer rootservices.Authorizer } -func NewUsersUseCase(service *services.UsersService) UsersUseCase { - return UsersUseCase{service: service} +func NewUsersUseCase(service *services.UsersService, authorizer rootservices.Authorizer) UsersUseCase { + return UsersUseCase{service: service, authorizer: authorizer} } func (u UsersUseCase) Create(ctx context.Context, actor *models.Actor, request types.CreateUserRequest) (*models.User, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersCreatePermission); err != nil { + return nil, err + } name := strings.TrimSpace(request.Name) email := strings.TrimSpace(strings.ToLower(request.Email)) @@ -43,6 +48,9 @@ func (u UsersUseCase) Create(ctx context.Context, actor *models.Actor, request t } func (u UsersUseCase) GetAll(ctx context.Context, actor *models.Actor, cursor *string, limit int) (*types.UsersPage, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersListPermission); err != nil { + return nil, err + } if limit <= 0 { limit = 10 } @@ -56,18 +64,24 @@ func (u UsersUseCase) GetAll(ctx context.Context, actor *models.Actor, cursor *s } func (u UsersUseCase) GetByID(ctx context.Context, actor *models.Actor, userID string) (*models.User, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersReadPermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { - return nil, constants.ErrUserIDRequired + return nil, adminconstants.ErrUserIDRequired } return u.service.GetByID(ctx, actor, userID) } func (u UsersUseCase) Update(ctx context.Context, actor *models.Actor, userID string, request types.UpdateUserRequest) (*models.User, error) { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersUpdatePermission); err != nil { + return nil, err + } userID = strings.TrimSpace(userID) if userID == "" { - return nil, constants.ErrUserIDRequired + return nil, adminconstants.ErrUserIDRequired } if request.Name == nil && request.Email == nil && request.EmailVerified == nil && request.Image == nil && len(request.Metadata) == 0 { return nil, internalerrors.ErrBadRequest @@ -77,6 +91,9 @@ func (u UsersUseCase) Update(ctx context.Context, actor *models.Actor, userID st } func (u UsersUseCase) Delete(ctx context.Context, actor *models.Actor, userID string) error { + if err := u.authorizer.AuthorizeScope(ctx, actor, adminconstants.UsersDeletePermission); err != nil { + return err + } userID = strings.TrimSpace(userID) if userID == "" { return internalerrors.ErrBadRequest diff --git a/plugins/api-key/api.go b/plugins/api-key/api.go index 051159d6..48f2916a 100644 --- a/plugins/api-key/api.go +++ b/plugins/api-key/api.go @@ -5,50 +5,50 @@ import ( "time" "github.com/Authula/authula/models" - apiservices "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type API struct { - service apiservices.ApiKeyService + useCases *usecases.UseCases } -func NewAPI(service apiservices.ApiKeyService) *API { - return &API{service: service} +func NewAPI(useCases *usecases.UseCases) *API { + return &API{useCases: useCases} } func (a *API) Create(ctx context.Context, actor *models.Actor, req types.CreateApiKeyRequest) (*types.CreateApiKeyResponse, error) { - return a.service.Create(ctx, actor, req) + return a.useCases.Create(ctx, actor, req) } func (a *API) GetByID(ctx context.Context, actor *models.Actor, id string) (*types.ApiKey, error) { - return a.service.GetByID(ctx, actor, id) + return a.useCases.GetByID(ctx, actor, id) } func (a *API) GetAll(ctx context.Context, actor *models.Actor, req types.GetApiKeysRequest) (*types.GetAllApiKeysResponse, error) { - return a.service.GetAll(ctx, actor, req) + return a.useCases.GetAll(ctx, actor, req) } func (a *API) Update(ctx context.Context, actor *models.Actor, id string, req types.UpdateApiKeyData) (*types.ApiKey, error) { - return a.service.Update(ctx, actor, id, req) + return a.useCases.Update(ctx, actor, id, req) } func (a *API) Delete(ctx context.Context, actor *models.Actor, id string) error { - return a.service.Delete(ctx, actor, id) + return a.useCases.Delete(ctx, actor, id) } func (a *API) DeleteExpired(ctx context.Context) error { - return a.service.DeleteExpired(ctx) + return a.useCases.DeleteExpired(ctx) } func (a *API) DeleteAllByOwner(ctx context.Context, actor *models.Actor, ownerType string, ownerID string) error { - return a.service.DeleteAllByOwner(ctx, actor, ownerType, ownerID) + return a.useCases.DeleteAllByOwner(ctx, actor, ownerType, ownerID) } func (a *API) RecordLastRequest(ctx context.Context, id string, timestamp time.Time) (*types.ApiKey, error) { - return a.service.RecordLastRequest(ctx, id, timestamp) + return a.useCases.RecordLastRequest(ctx, id, timestamp) } func (a *API) Verify(ctx context.Context, req types.VerifyApiKeyRequest) (*types.VerifyApiKeyResult, error) { - return a.service.Verify(ctx, req) + return a.useCases.Verify(ctx, req) } diff --git a/plugins/api-key/handlers/create_api_key_handler.go b/plugins/api-key/handlers/create_api_key_handler.go index 4a5d89cc..4280272a 100644 --- a/plugins/api-key/handlers/create_api_key_handler.go +++ b/plugins/api-key/handlers/create_api_key_handler.go @@ -6,12 +6,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type CreateApiKeyHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *CreateApiKeyHandler) Handle() http.HandlerFunc { @@ -31,7 +31,7 @@ func (h *CreateApiKeyHandler) Handle() http.HandlerFunc { return } - result, err := h.Service.Create(ctx, reqCtx.Actor, req) + result, err := h.UseCases.Create(ctx, reqCtx.Actor, req) if err != nil { internalerrors.HandleError(err, reqCtx) return diff --git a/plugins/api-key/handlers/create_api_key_handler_test.go b/plugins/api-key/handlers/create_api_key_handler_test.go index 3689c4b1..07cdfc38 100644 --- a/plugins/api-key/handlers/create_api_key_handler_test.go +++ b/plugins/api-key/handlers/create_api_key_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestCreateApiKeyHandler(t *testing.T) { @@ -72,7 +73,7 @@ func TestCreateApiKeyHandler(t *testing.T) { tt.prepare(service) } - handler := &CreateApiKeyHandler{Service: service} + handler := &CreateApiKeyHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} req, w, reqCtx := internaltests.NewHandlerRequest(t, http.MethodPost, "/api-keys", tt.body, nil) handler.Handle().ServeHTTP(w, req) diff --git a/plugins/api-key/handlers/delete_api_key_handler.go b/plugins/api-key/handlers/delete_api_key_handler.go index e63ad5c4..e10780c2 100644 --- a/plugins/api-key/handlers/delete_api_key_handler.go +++ b/plugins/api-key/handlers/delete_api_key_handler.go @@ -5,12 +5,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type DeleteApiKeyHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *DeleteApiKeyHandler) Handle() http.HandlerFunc { @@ -25,7 +25,7 @@ func (h *DeleteApiKeyHandler) Handle() http.HandlerFunc { return } - if err := h.Service.Delete(ctx, reqCtx.Actor, id); err != nil { + if err := h.UseCases.Delete(ctx, reqCtx.Actor, id); err != nil { internalerrors.HandleError(err, reqCtx) return } diff --git a/plugins/api-key/handlers/delete_api_key_handler_test.go b/plugins/api-key/handlers/delete_api_key_handler_test.go index f9f67da4..5a991a6a 100644 --- a/plugins/api-key/handlers/delete_api_key_handler_test.go +++ b/plugins/api-key/handlers/delete_api_key_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestDeleteApiKeyHandler(t *testing.T) { @@ -32,12 +33,14 @@ func TestDeleteApiKeyHandler(t *testing.T) { { name: "service_error", path: "/api-keys/api-key-1", prepare: func(m *apiKeyTests.MockApiKeyService) { + m.On("GetByID", mock.Anything, mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeUser, OwnerID: "user-1"}, nil).Once() m.On("Delete", mock.Anything, mock.Anything, "api-key-1").Return(internalerrors.ErrNotFound).Once() }, expectedStatus: http.StatusNotFound, }, { name: "success", path: "/api-keys/api-key-1", prepare: func(m *apiKeyTests.MockApiKeyService) { + m.On("GetByID", mock.Anything, mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeUser, OwnerID: "user-1"}, nil).Once() m.On("Delete", mock.Anything, mock.Anything, "api-key-1").Return(nil).Once() }, expectedStatus: http.StatusOK, @@ -57,7 +60,7 @@ func TestDeleteApiKeyHandler(t *testing.T) { tt.prepare(service) } - handler := &DeleteApiKeyHandler{Service: service} + handler := &DeleteApiKeyHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} req, w, reqCtx := internaltests.NewHandlerRequest(t, http.MethodDelete, tt.path, nil, nil) if tt.path != "/api-keys" { req.SetPathValue("id", "api-key-1") diff --git a/plugins/api-key/handlers/get_all_api_keys_handler.go b/plugins/api-key/handlers/get_all_api_keys_handler.go index a384fa96..84019506 100644 --- a/plugins/api-key/handlers/get_all_api_keys_handler.go +++ b/plugins/api-key/handlers/get_all_api_keys_handler.go @@ -6,12 +6,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type GetAllApiKeysHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *GetAllApiKeysHandler) Handle() http.HandlerFunc { @@ -34,7 +34,7 @@ func (h *GetAllApiKeysHandler) Handle() http.HandlerFunc { req.OwnerID = &ownerID } - resp, err := h.Service.GetAll(ctx, reqCtx.Actor, req) + resp, err := h.UseCases.GetAll(ctx, reqCtx.Actor, req) if err != nil { internalerrors.HandleError(err, reqCtx) return diff --git a/plugins/api-key/handlers/get_all_api_keys_handler_test.go b/plugins/api-key/handlers/get_all_api_keys_handler_test.go index cf8947e1..262390a1 100644 --- a/plugins/api-key/handlers/get_all_api_keys_handler_test.go +++ b/plugins/api-key/handlers/get_all_api_keys_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestGetAllApiKeysHandler(t *testing.T) { @@ -70,7 +71,7 @@ func TestGetAllApiKeysHandler(t *testing.T) { tt.prepare(service) } - handler := &GetAllApiKeysHandler{Service: service} + handler := &GetAllApiKeysHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} req, w, reqCtx := internaltests.NewHandlerRequest(t, http.MethodGet, tt.path, nil, nil) handler.Handle().ServeHTTP(w, req) diff --git a/plugins/api-key/handlers/get_api_key_handler.go b/plugins/api-key/handlers/get_api_key_handler.go index 68eab97a..18e788b5 100644 --- a/plugins/api-key/handlers/get_api_key_handler.go +++ b/plugins/api-key/handlers/get_api_key_handler.go @@ -5,12 +5,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type GetApiKeyHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *GetApiKeyHandler) Handle() http.HandlerFunc { @@ -25,7 +25,7 @@ func (h *GetApiKeyHandler) Handle() http.HandlerFunc { return } - apiKey, err := h.Service.GetByID(ctx, reqCtx.Actor, id) + apiKey, err := h.UseCases.GetByID(ctx, reqCtx.Actor, id) if err != nil { internalerrors.HandleError(err, reqCtx) return diff --git a/plugins/api-key/handlers/get_api_key_handler_test.go b/plugins/api-key/handlers/get_api_key_handler_test.go index f581a009..aae2b70a 100644 --- a/plugins/api-key/handlers/get_api_key_handler_test.go +++ b/plugins/api-key/handlers/get_api_key_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestGetApiKeyHandler(t *testing.T) { @@ -61,7 +62,7 @@ func TestGetApiKeyHandler(t *testing.T) { tt.prepare(service) } - handler := &GetApiKeyHandler{Service: service} + handler := &GetApiKeyHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} req, w, reqCtx := internaltests.NewHandlerRequest(t, http.MethodGet, tt.path, nil, nil) if tt.path != "/api-keys" { req.SetPathValue("id", "api-key-1") diff --git a/plugins/api-key/handlers/update_api_key_handler.go b/plugins/api-key/handlers/update_api_key_handler.go index 1877ffcd..006a3e3f 100644 --- a/plugins/api-key/handlers/update_api_key_handler.go +++ b/plugins/api-key/handlers/update_api_key_handler.go @@ -6,12 +6,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type UpdateApiKeyHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *UpdateApiKeyHandler) Handle() http.HandlerFunc { @@ -38,7 +38,7 @@ func (h *UpdateApiKeyHandler) Handle() http.HandlerFunc { return } - apiKey, err := h.Service.Update(ctx, reqCtx.Actor, id, types.UpdateApiKeyData{ + apiKey, err := h.UseCases.Update(ctx, reqCtx.Actor, id, types.UpdateApiKeyData{ Name: req.Name, Enabled: req.Enabled, RateLimitEnabled: req.RateLimitEnabled, diff --git a/plugins/api-key/handlers/update_api_key_handler_test.go b/plugins/api-key/handlers/update_api_key_handler_test.go index e92cb5e4..dea5689f 100644 --- a/plugins/api-key/handlers/update_api_key_handler_test.go +++ b/plugins/api-key/handlers/update_api_key_handler_test.go @@ -8,11 +8,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - internalerrors "github.com/Authula/authula/internal/errors" internaltests "github.com/Authula/authula/internal/tests" "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestUpdateApiKeyHandler(t *testing.T) { @@ -49,7 +49,7 @@ func TestUpdateApiKeyHandler(t *testing.T) { path: "/api-keys/api-key-1", body: internaltests.MarshalToJSON(t, types.UpdateApiKeyRequest{Name: &name}), prepare: func(m *apiKeyTests.MockApiKeyService) { - m.On("Update", mock.Anything, mock.Anything, "api-key-1", types.UpdateApiKeyData{Name: &name}).Return((*types.ApiKey)(nil), internalerrors.ErrNotFound).Once() + m.On("GetByID", mock.Anything, mock.Anything, "api-key-1").Return((*types.ApiKey)(nil), nil).Once() }, expectedStatus: http.StatusNotFound, }, @@ -58,6 +58,7 @@ func TestUpdateApiKeyHandler(t *testing.T) { path: "/api-keys/api-key-1", body: internaltests.MarshalToJSON(t, types.UpdateApiKeyRequest{Name: &name}), prepare: func(m *apiKeyTests.MockApiKeyService) { + m.On("GetByID", mock.Anything, mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeUser, OwnerID: "user-1"}, nil).Once() m.On("Update", mock.Anything, mock.Anything, "api-key-1", types.UpdateApiKeyData{Name: &name}).Return(apiKey, nil).Once() }, expectedStatus: http.StatusOK, @@ -77,7 +78,7 @@ func TestUpdateApiKeyHandler(t *testing.T) { tt.prepare(service) } - handler := &UpdateApiKeyHandler{Service: service} + handler := &UpdateApiKeyHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} path := tt.path if path == "" { path = "/api-keys/api-key-1" diff --git a/plugins/api-key/handlers/verify_api_key_handler.go b/plugins/api-key/handlers/verify_api_key_handler.go index 8a1dd805..f2d96df2 100644 --- a/plugins/api-key/handlers/verify_api_key_handler.go +++ b/plugins/api-key/handlers/verify_api_key_handler.go @@ -6,12 +6,12 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) type VerifyApiKeyHandler struct { - Service services.ApiKeyService + UseCases *usecases.UseCases } func (h *VerifyApiKeyHandler) Handle() http.HandlerFunc { @@ -31,7 +31,7 @@ func (h *VerifyApiKeyHandler) Handle() http.HandlerFunc { return } - result, err := h.Service.Verify(ctx, req) + result, err := h.UseCases.Verify(ctx, req) if err != nil { internalerrors.HandleError(err, reqCtx) return diff --git a/plugins/api-key/handlers/verify_api_key_handler_test.go b/plugins/api-key/handlers/verify_api_key_handler_test.go index 9400f371..f3f87d6a 100644 --- a/plugins/api-key/handlers/verify_api_key_handler_test.go +++ b/plugins/api-key/handlers/verify_api_key_handler_test.go @@ -13,6 +13,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" ) func TestVerifyApiKeyHandler(t *testing.T) { @@ -75,7 +76,7 @@ func TestVerifyApiKeyHandler(t *testing.T) { tt.prepare(service) } - handler := &VerifyApiKeyHandler{Service: service} + handler := &VerifyApiKeyHandler{UseCases: usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})} req, w, reqCtx := internaltests.NewHandlerRequest(t, http.MethodPost, "/api-keys/verify", tt.body, nil) handler.Handle().ServeHTTP(w, req) diff --git a/plugins/api-key/hooks_test.go b/plugins/api-key/hooks_test.go index 78008538..5acd0d12 100644 --- a/plugins/api-key/hooks_test.go +++ b/plugins/api-key/hooks_test.go @@ -14,6 +14,7 @@ import ( "github.com/Authula/authula/models" apiKeyTests "github.com/Authula/authula/plugins/api-key/tests" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" rootservices "github.com/Authula/authula/services" ) @@ -233,7 +234,7 @@ func TestApiKeyPluginHook_ValidateApiKey(t *testing.T) { rateLimiterService: rateLimiterService, userService: mockUserService, organizationService: mockOrgService, - Api: NewAPI(service), + Api: NewAPI(usecases.NewUseCases(service, &internaltests.NoopAuthorizer{})), } reqCtx := internaltests.NewRequestContext(t, http.MethodGet, "/protected", map[string]string{"X-Test-API-Key": "good-key"}) diff --git a/plugins/api-key/plugin.go b/plugins/api-key/plugin.go index 147d79ba..dcbfeb99 100644 --- a/plugins/api-key/plugin.go +++ b/plugins/api-key/plugin.go @@ -15,6 +15,7 @@ import ( apirepositories "github.com/Authula/authula/plugins/api-key/repositories" apiservices "github.com/Authula/authula/plugins/api-key/services" "github.com/Authula/authula/plugins/api-key/types" + "github.com/Authula/authula/plugins/api-key/usecases" orgplugins "github.com/Authula/authula/plugins/organizations" rootservices "github.com/Authula/authula/services" ) @@ -98,9 +99,10 @@ func (p *ApiKeyPlugin) Init(ctx *models.PluginContext) error { apiKeyRepo := apirepositories.NewBunApiKeyRepository(p.db) authorizer := rootservices.NewDefaultAuthorizer() - service := apiservices.NewApiKeyService(p.config, userService, tokenService, accessControlService, rateLimiterService, organizationService, authorizer, apiKeyRepo) + service := apiservices.NewApiKeyService(p.config, userService, tokenService, accessControlService, rateLimiterService, organizationService, apiKeyRepo) + useCases := usecases.NewUseCases(service, authorizer) - p.Api = NewAPI(service) + p.Api = NewAPI(useCases) if p.config.AutoCleanup { p.stopCleanup = make(chan struct{}) diff --git a/plugins/api-key/routes.go b/plugins/api-key/routes.go index 860d9d30..7ad7ac50 100644 --- a/plugins/api-key/routes.go +++ b/plugins/api-key/routes.go @@ -9,12 +9,12 @@ import ( ) func Routes(api *API) []models.Route { - createApiKeyHandler := &handlers.CreateApiKeyHandler{Service: api.service} - getAllApiKeysHandler := &handlers.GetAllApiKeysHandler{Service: api.service} - getApiKeyHandler := &handlers.GetApiKeyHandler{Service: api.service} - updateApiKeyHandler := &handlers.UpdateApiKeyHandler{Service: api.service} - deleteApiKeyHandler := &handlers.DeleteApiKeyHandler{Service: api.service} - verifyApiKeyHandler := &handlers.VerifyApiKeyHandler{Service: api.service} + createApiKeyHandler := &handlers.CreateApiKeyHandler{UseCases: api.useCases} + getAllApiKeysHandler := &handlers.GetAllApiKeysHandler{UseCases: api.useCases} + getApiKeyHandler := &handlers.GetApiKeyHandler{UseCases: api.useCases} + updateApiKeyHandler := &handlers.UpdateApiKeyHandler{UseCases: api.useCases} + deleteApiKeyHandler := &handlers.DeleteApiKeyHandler{UseCases: api.useCases} + verifyApiKeyHandler := &handlers.VerifyApiKeyHandler{UseCases: api.useCases} return []models.Route{ { diff --git a/plugins/api-key/services/api_key_service.go b/plugins/api-key/services/api_key_service.go index 1a2fd44f..a7aa4de9 100644 --- a/plugins/api-key/services/api_key_service.go +++ b/plugins/api-key/services/api_key_service.go @@ -10,7 +10,6 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/api-key/constants" "github.com/Authula/authula/plugins/api-key/repositories" "github.com/Authula/authula/plugins/api-key/types" rootservices "github.com/Authula/authula/services" @@ -23,7 +22,6 @@ type apiKeyService struct { accessControlService rootservices.AccessControlService rateLimiterService rootservices.RateLimiterService organizationService rootservices.OrganizationService - authorizer rootservices.Authorizer apiKeyRepo repositories.ApiKeyRepository } @@ -39,7 +37,6 @@ func NewApiKeyService( accessControlService rootservices.AccessControlService, rateLimiterService rootservices.RateLimiterService, organizationService rootservices.OrganizationService, - authorizer rootservices.Authorizer, apiKeyRepo repositories.ApiKeyRepository, ) ApiKeyService { return &apiKeyService{ @@ -52,13 +49,12 @@ func NewApiKeyService( accessControlService: accessControlService, rateLimiterService: rateLimiterService, organizationService: organizationService, - authorizer: authorizer, apiKeyRepo: apiKeyRepo, } } func (s *apiKeyService) Create(ctx context.Context, actor *models.Actor, req types.CreateApiKeyRequest) (*types.CreateApiKeyResponse, error) { - if err := s.authorizeCreate(ctx, actor, req); err != nil { + if err := s.authorizeCreate(actor, req); err != nil { return nil, err } @@ -173,7 +169,7 @@ func (s *apiKeyService) Create(ctx context.Context, actor *models.Actor, req typ }, nil } -func (s *apiKeyService) authorizeCreate(ctx context.Context, actor *models.Actor, req types.CreateApiKeyRequest) error { +func (s *apiKeyService) authorizeCreate(actor *models.Actor, req types.CreateApiKeyRequest) error { switch req.OwnerType { case types.OwnerTypeUser: if req.OwnerID != "" && req.OwnerID != actor.ID { @@ -189,9 +185,6 @@ func (s *apiKeyService) authorizeCreate(ctx context.Context, actor *models.Actor if s.organizationService == nil { return fmt.Errorf("%w: organization service is not available", internalerrors.ErrUnprocessableEntity) } - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyCreate); err != nil { - return err - } if err := s.validatePermissionsSubset(actor.Scopes, req.Permissions); err != nil { return err } @@ -213,10 +206,6 @@ func (s *apiKeyService) GetByID(ctx context.Context, actor *models.Actor, id str if apiKey.OwnerID != actor.ID { return nil, fmt.Errorf("%w: you do not have access to this API key", internalerrors.ErrForbidden) } - case types.OwnerTypeOrganization: - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyRead); err != nil { - return nil, err - } } return apiKey, nil @@ -242,10 +231,6 @@ func (s *apiKeyService) GetAll(ctx context.Context, actor *models.Actor, req typ req.OwnerID = &ownerID ownerType := types.OwnerTypeUser req.OwnerType = &ownerType - case *req.OwnerType == types.OwnerTypeOrganization: - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyList); err != nil { - return nil, err - } } items, total, err := s.apiKeyRepo.GetAll(ctx, req.OwnerType, req.OwnerID, page, limit) @@ -284,9 +269,6 @@ func (s *apiKeyService) Update(ctx context.Context, actor *models.Actor, id stri } } case types.OwnerTypeOrganization: - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyUpdate); err != nil { - return nil, err - } if len(req.Permissions) > 0 { if err := s.validatePermissionsSubset(actor.Scopes, req.Permissions); err != nil { return nil, err @@ -348,10 +330,6 @@ func (s *apiKeyService) Delete(ctx context.Context, actor *models.Actor, id stri if apiKey.OwnerID != actor.ID { return fmt.Errorf("%w: you do not have access to this API key", internalerrors.ErrForbidden) } - case types.OwnerTypeOrganization: - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyDelete); err != nil { - return err - } } if s.rateLimiterService != nil && apiKey.RateLimitEnabled { @@ -372,10 +350,6 @@ func (s *apiKeyService) DeleteAllByOwner(ctx context.Context, actor *models.Acto if ownerID != actor.ID { return fmt.Errorf("%w: you cannot delete API keys for another user", internalerrors.ErrForbidden) } - case types.OwnerTypeOrganization: - if err := s.authorizer.AuthorizeScope(ctx, actor, constants.OrgApiKeyDelete); err != nil { - return err - } } return s.apiKeyRepo.DeleteAllByOwner(ctx, ownerType, ownerID) } diff --git a/plugins/api-key/services/api_key_service_test.go b/plugins/api-key/services/api_key_service_test.go index 27409c45..f250b480 100644 --- a/plugins/api-key/services/api_key_service_test.go +++ b/plugins/api-key/services/api_key_service_test.go @@ -23,7 +23,6 @@ type apiKeyServiceFixture struct { mockTokenService *roottests.MockTokenService mockOrgService *internaltests.MockOrganizationService mockAccessControlService *apiKeyTests.MockAccessControlService - mockAuthorizer *internaltests.MockAuthorizer mockRateLimiterService *roottests.MockRateLimitService mockApiKeyService *apiKeyService mockApiKeyRepo *apiKeyTests.MockApiKeyRepository @@ -35,11 +34,10 @@ func newApiKeyServiceFixture(pluginConfig types.ApiKeyPluginConfig) *apiKeyServi mockTokenService := &roottests.MockTokenService{} mockRateLimiterService := &roottests.MockRateLimitService{} mockAccessControlService := &apiKeyTests.MockAccessControlService{} - mockAuthorizer := &internaltests.MockAuthorizer{} mockApiKeyRepo := &apiKeyTests.MockApiKeyRepository{} - service := NewApiKeyService(pluginConfig, mockUserService, mockTokenService, mockAccessControlService, mockRateLimiterService, mockOrgService, mockAuthorizer, mockApiKeyRepo).(*apiKeyService) - return &apiKeyServiceFixture{mockApiKeyService: service, mockApiKeyRepo: mockApiKeyRepo, mockUserService: mockUserService, mockTokenService: mockTokenService, mockOrgService: mockOrgService, mockAccessControlService: mockAccessControlService, mockAuthorizer: mockAuthorizer, mockRateLimiterService: mockRateLimiterService} + service := NewApiKeyService(pluginConfig, mockUserService, mockTokenService, mockAccessControlService, mockRateLimiterService, mockOrgService, mockApiKeyRepo).(*apiKeyService) + return &apiKeyServiceFixture{mockApiKeyService: service, mockApiKeyRepo: mockApiKeyRepo, mockUserService: mockUserService, mockTokenService: mockTokenService, mockOrgService: mockOrgService, mockAccessControlService: mockAccessControlService, mockRateLimiterService: mockRateLimiterService} } func userActor(id string) *models.Actor { @@ -115,23 +113,10 @@ func TestApiKeyServiceCreate(t *testing.T) { }, }, { - name: "org_create_requires_permission", - actor: userActor(userID), - config: types.ApiKeyPluginConfig{AllowOrgKeys: true}, - req: types.CreateApiKeyRequest{Name: "Key", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, - setup: func(f *apiKeyServiceFixture) { - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:create").Return(internalerrors.ErrForbidden).Once() - }, - wantErr: internalerrors.ErrForbidden, - }, - { - name: "org_create_privilege_escalation_rejected", - actor: &models.Actor{ID: userID, Type: models.ActorUser, Scopes: []string{"org:api-key:create"}}, - config: types.ApiKeyPluginConfig{AllowOrgKeys: true}, - req: types.CreateApiKeyRequest{Name: "Key", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID, Permissions: []string{"admin"}}, - setup: func(f *apiKeyServiceFixture) { - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:create").Return(nil).Once() - }, + name: "org_create_privilege_escalation_rejected", + actor: &models.Actor{ID: userID, Type: models.ActorUser, Scopes: []string{"org:api-key:create"}}, + config: types.ApiKeyPluginConfig{AllowOrgKeys: true}, + req: types.CreateApiKeyRequest{Name: "Key", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID, Permissions: []string{"admin"}}, wantErr: internalerrors.ErrForbidden, }, { @@ -141,7 +126,6 @@ func TestApiKeyServiceCreate(t *testing.T) { req: types.CreateApiKeyRequest{Name: "Key", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID, Permissions: []string{"read"}}, setup: func(f *apiKeyServiceFixture) { f.mockAccessControlService.On("ValidatePermissionKeys", mock.Anything, []string{"read"}).Return(nil).Once() - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:create").Return(nil).Once() f.mockOrgService.On("ExistsByID", mock.Anything, orgID).Return(true, nil).Once() f.mockTokenService.On("Generate").Return(rawApiKey, nil).Once() f.mockTokenService.On("Hash", rawApiKey).Return("hashed-key").Once() @@ -174,7 +158,6 @@ func TestApiKeyServiceCreate(t *testing.T) { config: types.ApiKeyPluginConfig{AllowOrgKeys: true}, req: types.CreateApiKeyRequest{Name: "Key", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, setup: func(f *apiKeyServiceFixture) { - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:create").Return(nil).Once() f.mockOrgService.On("ExistsByID", mock.Anything, orgID).Return(false, nil).Once() }, wantErr: internalerrors.ErrNotFound, @@ -229,7 +212,6 @@ func TestApiKeyServiceCreate(t *testing.T) { fixture.mockTokenService.AssertExpectations(t) fixture.mockOrgService.AssertExpectations(t) fixture.mockAccessControlService.AssertExpectations(t) - fixture.mockAuthorizer.AssertExpectations(t) fixture.mockRateLimiterService.AssertExpectations(t) fixture.mockApiKeyRepo.AssertExpectations(t) }) @@ -316,63 +298,10 @@ func TestApiKeyServiceGetAll(t *testing.T) { } } -func TestApiKeyServiceGetAllOrgKeys(t *testing.T) { - t.Parallel() - - orgID := "org-1" - orgType := types.OwnerTypeOrganization - - tests := []struct { - name string - actor *models.Actor - req types.GetApiKeysRequest - setup func(*apiKeyServiceFixture) - wantErr error - }{ - { - name: "org_list_requires_permission", - actor: userActor("user-1"), - req: types.GetApiKeysRequest{OwnerType: &orgType, OwnerID: &orgID}, - setup: func(f *apiKeyServiceFixture) { - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:list").Return(internalerrors.ErrForbidden).Once() - }, - wantErr: internalerrors.ErrForbidden, - }, - { - name: "org_list_allowed", - actor: &models.Actor{ID: "user-1", Type: models.ActorUser, Scopes: []string{"org:api-key:list"}}, - req: types.GetApiKeysRequest{OwnerType: &orgType, OwnerID: &orgID}, - setup: func(f *apiKeyServiceFixture) { - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:list").Return(nil).Once() - f.mockApiKeyRepo.On("GetAll", mock.Anything, &orgType, &orgID, 1, 10).Return([]*types.ApiKey{{ID: "api-key-1"}}, 1, nil).Once() - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - t.Parallel() - fixture := newApiKeyServiceFixture(types.ApiKeyPluginConfig{}) - tc.setup(fixture) - - _, err := fixture.mockApiKeyService.GetAll(context.Background(), tc.actor, tc.req) - if tc.wantErr == nil { - require.NoError(t, err) - } else { - require.Error(t, err) - assert.ErrorContains(t, err, tc.wantErr.Error()) - } - fixture.mockAuthorizer.AssertExpectations(t) - fixture.mockApiKeyRepo.AssertExpectations(t) - }) - } -} - func TestApiKeyServiceGetByID(t *testing.T) { t.Parallel() userID := "user-1" - orgID := "org-1" tests := []struct { name string @@ -411,23 +340,6 @@ func TestApiKeyServiceGetByID(t *testing.T) { f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeUser, OwnerID: userID}, nil).Once() }, }, - { - name: "org_key_requires_read_permission", - actor: userActor(userID), - setup: func(f *apiKeyServiceFixture) { - f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-2").Return(&types.ApiKey{ID: "api-key-2", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, nil).Once() - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:read").Return(internalerrors.ErrForbidden).Once() - }, - wantErr: internalerrors.ErrForbidden, - }, - { - name: "org_key_read_allowed", - actor: &models.Actor{ID: userID, Type: models.ActorUser, Scopes: []string{"org:api-key:read"}}, - setup: func(f *apiKeyServiceFixture) { - f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-2").Return(&types.ApiKey{ID: "api-key-2", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, nil).Once() - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:read").Return(nil).Once() - }, - }, } for _, tc := range tests { @@ -436,11 +348,7 @@ func TestApiKeyServiceGetByID(t *testing.T) { fixture := newApiKeyServiceFixture(types.ApiKeyPluginConfig{}) tc.setup(fixture) - keyID := "api-key-1" - if tc.name == "org_key_requires_read_permission" || tc.name == "org_key_read_allowed" { - keyID = "api-key-2" - } - resp, err := fixture.mockApiKeyService.GetByID(context.Background(), tc.actor, keyID) + resp, err := fixture.mockApiKeyService.GetByID(context.Background(), tc.actor, "api-key-1") if tc.wantErr == nil { require.NoError(t, err) require.NotNil(t, resp) @@ -513,13 +421,15 @@ func TestApiKeyServiceUpdate(t *testing.T) { wantErr: internalerrors.ErrNotFound, }, { - name: "org_update_requires_permission", - actor: userActor(userID), + name: "org_update_allowed", + actor: &models.Actor{ID: userID, Type: models.ActorUser, Scopes: []string{"org:api-key:update", "read", "write"}}, setup: func(f *apiKeyServiceFixture) { - f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, nil).Once() - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:update").Return(internalerrors.ErrForbidden).Once() + f.mockAccessControlService.On("ValidatePermissionKeys", mock.Anything, permissions).Return(nil).Once() + f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", Name: "old", Enabled: true, OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, nil).Once() + f.mockApiKeyRepo.On("Update", mock.Anything, mock.MatchedBy(func(apiKey *types.ApiKey) bool { + return apiKey != nil && apiKey.ID == "api-key-1" && apiKey.Name == name && !apiKey.Enabled && apiKey.RateLimitEnabled && len(apiKey.Permissions) == len(permissions) && apiKey.Metadata != nil && len(apiKey.Metadata) == len(metadata) + })).Return(&types.ApiKey{ID: "api-key-1", Name: name}, nil).Once() }, - wantErr: internalerrors.ErrForbidden, }, } @@ -560,7 +470,6 @@ func TestApiKeyServiceDelete(t *testing.T) { t.Parallel() userID := "user-1" - orgID := "org-1" tests := []struct { name string @@ -592,15 +501,6 @@ func TestApiKeyServiceDelete(t *testing.T) { f.mockApiKeyRepo.On("Delete", mock.Anything, "api-key-1").Return(nil).Once() }, }, - { - name: "org_delete_requires_permission", - actor: userActor(userID), - setup: func(f *apiKeyServiceFixture) { - f.mockApiKeyRepo.On("GetByID", mock.Anything, "api-key-1").Return(&types.ApiKey{ID: "api-key-1", OwnerType: types.OwnerTypeOrganization, OwnerID: orgID}, nil).Once() - f.mockAuthorizer.On("AuthorizeScope", mock.Anything, mock.Anything, "org:api-key:delete").Return(internalerrors.ErrForbidden).Once() - }, - wantErr: internalerrors.ErrForbidden, - }, } for _, tc := range tests { diff --git a/plugins/api-key/usecases/usecases.go b/plugins/api-key/usecases/usecases.go new file mode 100644 index 00000000..be444e7e --- /dev/null +++ b/plugins/api-key/usecases/usecases.go @@ -0,0 +1,109 @@ +package usecases + +import ( + "context" + "time" + + internalerrors "github.com/Authula/authula/internal/errors" + "github.com/Authula/authula/models" + apiconstants "github.com/Authula/authula/plugins/api-key/constants" + apiservices "github.com/Authula/authula/plugins/api-key/services" + "github.com/Authula/authula/plugins/api-key/types" + rootservices "github.com/Authula/authula/services" +) + +type UseCases struct { + service apiservices.ApiKeyService + authorizer rootservices.Authorizer +} + +func NewUseCases(service apiservices.ApiKeyService, authorizer rootservices.Authorizer) *UseCases { + return &UseCases{service: service, authorizer: authorizer} +} + +func (u *UseCases) Create(ctx context.Context, actor *models.Actor, req types.CreateApiKeyRequest) (*types.CreateApiKeyResponse, error) { + if req.OwnerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyCreate); err != nil { + return nil, err + } + } + return u.service.Create(ctx, actor, req) +} + +func (u *UseCases) GetByID(ctx context.Context, actor *models.Actor, id string) (*types.ApiKey, error) { + apiKey, err := u.service.GetByID(ctx, actor, id) + if err != nil { + return nil, err + } + if apiKey == nil { + return apiKey, nil + } + if apiKey.OwnerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyRead); err != nil { + return nil, err + } + } + return apiKey, nil +} + +func (u *UseCases) GetAll(ctx context.Context, actor *models.Actor, req types.GetApiKeysRequest) (*types.GetAllApiKeysResponse, error) { + if req.OwnerType != nil && *req.OwnerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyList); err != nil { + return nil, err + } + } + return u.service.GetAll(ctx, actor, req) +} + +func (u *UseCases) Update(ctx context.Context, actor *models.Actor, id string, req types.UpdateApiKeyData) (*types.ApiKey, error) { + apiKey, err := u.service.GetByID(ctx, actor, id) + if err != nil { + return nil, err + } + if apiKey == nil { + return nil, internalerrors.ErrNotFound + } + if apiKey.OwnerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyUpdate); err != nil { + return nil, err + } + } + return u.service.Update(ctx, actor, id, req) +} + +func (u *UseCases) Delete(ctx context.Context, actor *models.Actor, id string) error { + apiKey, err := u.service.GetByID(ctx, actor, id) + if err != nil { + return err + } + if apiKey == nil { + return nil + } + if apiKey.OwnerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyDelete); err != nil { + return err + } + } + return u.service.Delete(ctx, actor, id) +} + +func (u *UseCases) DeleteExpired(ctx context.Context) error { + return u.service.DeleteExpired(ctx) +} + +func (u *UseCases) DeleteAllByOwner(ctx context.Context, actor *models.Actor, ownerType string, ownerID string) error { + if ownerType == types.OwnerTypeOrganization { + if err := u.authorizer.AuthorizeScope(ctx, actor, apiconstants.OrgApiKeyDelete); err != nil { + return err + } + } + return u.service.DeleteAllByOwner(ctx, actor, ownerType, ownerID) +} + +func (u *UseCases) RecordLastRequest(ctx context.Context, id string, timestamp time.Time) (*types.ApiKey, error) { + return u.service.RecordLastRequest(ctx, id, timestamp) +} + +func (u *UseCases) Verify(ctx context.Context, req types.VerifyApiKeyRequest) (*types.VerifyApiKeyResult, error) { + return u.service.Verify(ctx, req) +} diff --git a/plugins/organizations/api.go b/plugins/organizations/api.go index 5bd2c6cd..caaca72e 100644 --- a/plugins/organizations/api.go +++ b/plugins/organizations/api.go @@ -4,138 +4,130 @@ import ( "context" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + "github.com/Authula/authula/plugins/organizations/usecases" ) type API struct { - organizationService services.OrganizationService - invitationService services.OrganizationInvitationService - memberService services.OrganizationMemberService - teamService services.OrganizationTeamService - teamMemberService services.OrganizationTeamMemberService + useCases *usecases.UseCases } func BuildAPI(plugin *OrganizationsPlugin) *API { return &API{ - organizationService: plugin.organizationService, - invitationService: plugin.invitationService, - memberService: plugin.memberService, - teamService: plugin.teamService, - teamMemberService: plugin.teamMemberService, + useCases: plugin.useCases, } } // Organizations func (a *API) ExistsByID(ctx context.Context, organizationID string) (bool, error) { - return a.organizationService.ExistsByID(ctx, organizationID) + return a.useCases.ExistsByID(ctx, organizationID) } func (a *API) CreateOrganization(ctx context.Context, actor *models.Actor, request types.CreateOrganizationRequest) (*types.Organization, error) { - return a.organizationService.CreateOrganization(ctx, actor, request) + return a.useCases.CreateOrganization(ctx, actor, request) } -func (a *API) GetAllOrganizations(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { - return a.organizationService.GetAllOrganizations(ctx, actor) +func (a *API) GetAllOrganizationsByOwner(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { + return a.useCases.GetAllOrganizationsByOwner(ctx, actor) } func (a *API) GetOrganizationByID(ctx context.Context, actor *models.Actor, organizationID string) (*types.Organization, error) { - return a.organizationService.GetOrganizationByID(ctx, actor, organizationID) + return a.useCases.GetOrganizationByID(ctx, actor, organizationID) } func (a *API) UpdateOrganization(ctx context.Context, actor *models.Actor, organizationID string, request types.UpdateOrganizationRequest) (*types.Organization, error) { - return a.organizationService.UpdateOrganization(ctx, actor, organizationID, request) + return a.useCases.UpdateOrganization(ctx, actor, organizationID, request) } func (a *API) DeleteOrganization(ctx context.Context, actor *models.Actor, organizationID string) error { - return a.organizationService.DeleteOrganization(ctx, actor, organizationID) + return a.useCases.DeleteOrganization(ctx, actor, organizationID) } // Invitations func (a *API) CreateInvitation(ctx context.Context, actor *models.Actor, organizationID string, request types.CreateOrganizationInvitationRequest) (*types.OrganizationInvitation, error) { - return a.invitationService.CreateOrganizationInvitation(ctx, actor, organizationID, request) + return a.useCases.CreateOrganizationInvitation(ctx, actor, organizationID, request) } func (a *API) GetInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { - return a.invitationService.GetOrganizationInvitation(ctx, actor, organizationID, invitationID) + return a.useCases.GetOrganizationInvitation(ctx, actor, organizationID, invitationID) } func (a *API) GetAllInvitations(ctx context.Context, actor *models.Actor, organizationID string) ([]types.OrganizationInvitation, error) { - return a.invitationService.GetAllOrganizationInvitations(ctx, actor, organizationID) + return a.useCases.GetAllOrganizationInvitations(ctx, actor, organizationID) } func (a *API) RevokeInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { - return a.invitationService.RevokeOrganizationInvitation(ctx, actor, organizationID, invitationID) + return a.useCases.RevokeOrganizationInvitation(ctx, actor, organizationID, invitationID) } func (a *API) AcceptInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { - return a.invitationService.AcceptOrganizationInvitation(ctx, actor, organizationID, invitationID) + return a.useCases.AcceptOrganizationInvitation(ctx, actor, organizationID, invitationID) } func (a *API) RejectInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { - return a.invitationService.RejectOrganizationInvitation(ctx, actor, organizationID, invitationID) + return a.useCases.RejectOrganizationInvitation(ctx, actor, organizationID, invitationID) } // Members func (a *API) AddMember(ctx context.Context, actor *models.Actor, organizationID string, request types.AddOrganizationMemberRequest) (*types.OrganizationMember, error) { - return a.memberService.AddMember(ctx, actor, organizationID, request) + return a.useCases.AddMember(ctx, actor, organizationID, request) } func (a *API) GetAllMembers(ctx context.Context, actor *models.Actor, organizationID string, page int, limit int) ([]types.OrganizationMember, error) { - return a.memberService.GetAllMembers(ctx, actor, organizationID, page, limit) + return a.useCases.GetAllMembers(ctx, actor, organizationID, page, limit) } func (a *API) GetMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) (*types.OrganizationMember, error) { - return a.memberService.GetMember(ctx, actor, organizationID, memberID) + return a.useCases.GetMember(ctx, actor, organizationID, memberID) } func (a *API) UpdateMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string, request types.UpdateOrganizationMemberRequest) (*types.OrganizationMember, error) { - return a.memberService.UpdateMember(ctx, actor, organizationID, memberID, request) + return a.useCases.UpdateMember(ctx, actor, organizationID, memberID, request) } func (a *API) RemoveMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) error { - return a.memberService.RemoveMember(ctx, actor, organizationID, memberID) + return a.useCases.RemoveMember(ctx, actor, organizationID, memberID) } // Teams func (a *API) CreateTeam(ctx context.Context, actor *models.Actor, organizationID string, request types.CreateOrganizationTeamRequest) (*types.OrganizationTeam, error) { - return a.teamService.CreateTeam(ctx, actor, organizationID, request) + return a.useCases.CreateTeam(ctx, actor, organizationID, request) } func (a *API) GetAllTeams(ctx context.Context, actor *models.Actor, organizationID string) ([]types.OrganizationTeam, error) { - return a.teamService.GetAllTeams(ctx, actor, organizationID) + return a.useCases.GetAllTeams(ctx, actor, organizationID) } func (a *API) GetTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) (*types.OrganizationTeam, error) { - return a.teamService.GetTeam(ctx, actor, organizationID, teamID) + return a.useCases.GetTeam(ctx, actor, organizationID, teamID) } func (a *API) UpdateTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string, request types.UpdateOrganizationTeamRequest) (*types.OrganizationTeam, error) { - return a.teamService.UpdateTeam(ctx, actor, organizationID, teamID, request) + return a.useCases.UpdateTeam(ctx, actor, organizationID, teamID, request) } func (a *API) DeleteTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) error { - return a.teamService.DeleteTeam(ctx, actor, organizationID, teamID) + return a.useCases.DeleteTeam(ctx, actor, organizationID, teamID) } // Team Members func (a *API) AddTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, request types.AddOrganizationTeamMemberRequest) (*types.OrganizationTeamMember, error) { - return a.teamMemberService.AddTeamMember(ctx, actor, organizationID, teamID, request) + return a.useCases.AddTeamMember(ctx, actor, organizationID, teamID, request) } func (a *API) GetAllTeamMembers(ctx context.Context, actor *models.Actor, organizationID string, teamID string, page int, limit int) ([]types.OrganizationTeamMember, error) { - return a.teamMemberService.GetAllTeamMembers(ctx, actor, organizationID, teamID, page, limit) + return a.useCases.GetAllTeamMembers(ctx, actor, organizationID, teamID, page, limit) } func (a *API) GetTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) (*types.OrganizationTeamMember, error) { - return a.teamMemberService.GetTeamMember(ctx, actor, organizationID, teamID, memberID) + return a.useCases.GetTeamMember(ctx, actor, organizationID, teamID, memberID) } func (a *API) RemoveTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) error { - return a.teamMemberService.RemoveTeamMember(ctx, actor, organizationID, teamID, memberID) + return a.useCases.RemoveTeamMember(ctx, actor, organizationID, teamID, memberID) } diff --git a/plugins/organizations/constants/constants.go b/plugins/organizations/constants/constants.go index d5151637..aa02c7d2 100644 --- a/plugins/organizations/constants/constants.go +++ b/plugins/organizations/constants/constants.go @@ -4,8 +4,6 @@ package constants const ( All = "organizations:*" - OrganizationsCreatePermission = "organizations:create" - OrganizationsListPermission = "organizations:list" OrganizationsReadPermission = "organizations:read" OrganizationsUpdatePermission = "organizations:update" OrganizationsDeletePermission = "organizations:delete" diff --git a/plugins/organizations/handlers/handler_test_helpers.go b/plugins/organizations/handlers/handler_test_helpers.go new file mode 100644 index 00000000..eda0fc4d --- /dev/null +++ b/plugins/organizations/handlers/handler_test_helpers.go @@ -0,0 +1,75 @@ +package handlers + +import ( + "context" + + "github.com/Authula/authula/models" + orgservices "github.com/Authula/authula/plugins/organizations/services" + orgtests "github.com/Authula/authula/plugins/organizations/tests" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" +) + +type noopAuthorizer struct{} + +func (a *noopAuthorizer) AuthorizeScope(_ context.Context, _ *models.Actor, _ string) error { + return nil +} + +func (a *noopAuthorizer) AuthorizeOrganizationAccess(_ context.Context, _ *models.Actor, _ string, _ string) error { + return nil +} + +func newOrgUseCases(svc orgservices.OrganizationService) *orgusecases.UseCases { + return orgusecases.NewUseCases( + svc, + &orgtests.MockOrganizationInvitationService{}, + &orgtests.MockOrganizationMemberService{}, + &orgtests.MockOrganizationTeamService{}, + &orgtests.MockOrganizationTeamMemberService{}, + &noopAuthorizer{}, + ) +} + +func newInvitationUseCases(svc orgservices.OrganizationInvitationService) *orgusecases.UseCases { + return orgusecases.NewUseCases( + &orgtests.MockOrganizationService{}, + svc, + &orgtests.MockOrganizationMemberService{}, + &orgtests.MockOrganizationTeamService{}, + &orgtests.MockOrganizationTeamMemberService{}, + &noopAuthorizer{}, + ) +} + +func newMemberUseCases(svc orgservices.OrganizationMemberService) *orgusecases.UseCases { + return orgusecases.NewUseCases( + &orgtests.MockOrganizationService{}, + &orgtests.MockOrganizationInvitationService{}, + svc, + &orgtests.MockOrganizationTeamService{}, + &orgtests.MockOrganizationTeamMemberService{}, + &noopAuthorizer{}, + ) +} + +func newTeamUseCases(svc orgservices.OrganizationTeamService) *orgusecases.UseCases { + return orgusecases.NewUseCases( + &orgtests.MockOrganizationService{}, + &orgtests.MockOrganizationInvitationService{}, + &orgtests.MockOrganizationMemberService{}, + svc, + &orgtests.MockOrganizationTeamMemberService{}, + &noopAuthorizer{}, + ) +} + +func newTeamMemberUseCases(svc orgservices.OrganizationTeamMemberService) *orgusecases.UseCases { + return orgusecases.NewUseCases( + &orgtests.MockOrganizationService{}, + &orgtests.MockOrganizationInvitationService{}, + &orgtests.MockOrganizationMemberService{}, + &orgtests.MockOrganizationTeamService{}, + svc, + &noopAuthorizer{}, + ) +} diff --git a/plugins/organizations/handlers/organization_handlers.go b/plugins/organizations/handlers/organization_handlers.go index 7eb195be..2dcdbff0 100644 --- a/plugins/organizations/handlers/organization_handlers.go +++ b/plugins/organizations/handlers/organization_handlers.go @@ -6,12 +6,12 @@ import ( "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" orgconstants "github.com/Authula/authula/plugins/organizations/constants" - orgservices "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" ) type CreateOrganizationHandler struct { - OrgService orgservices.OrganizationService + UseCases *orgusecases.UseCases } func (h *CreateOrganizationHandler) Handle() http.HandlerFunc { @@ -32,7 +32,7 @@ func (h *CreateOrganizationHandler) Handle() http.HandlerFunc { return } - organization, err := h.OrgService.CreateOrganization(ctx, actor, request) + organization, err := h.UseCases.CreateOrganization(ctx, actor, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -48,16 +48,16 @@ func (h *CreateOrganizationHandler) Handle() http.HandlerFunc { } } -type GetAllOrganizationsHandler struct { - OrgService orgservices.OrganizationService +type GetAllOrganizationsByOwnerHandler struct { + UseCases *orgusecases.UseCases } -func (h *GetAllOrganizationsHandler) Handle() http.HandlerFunc { +func (h *GetAllOrganizationsByOwnerHandler) Handle() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() reqCtx, _ := models.GetRequestContext(ctx) actor := reqCtx.Actor - organizations, err := h.OrgService.GetAllOrganizations(ctx, actor) + organizations, err := h.UseCases.GetAllOrganizationsByOwner(ctx, actor) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -68,7 +68,7 @@ func (h *GetAllOrganizationsHandler) Handle() http.HandlerFunc { } type GetOrganizationByIDHandler struct { - OrgService orgservices.OrganizationService + UseCases *orgusecases.UseCases } func (h *GetOrganizationByIDHandler) Handle() http.HandlerFunc { @@ -78,7 +78,7 @@ func (h *GetOrganizationByIDHandler) Handle() http.HandlerFunc { actor := reqCtx.Actor organizationID := r.PathValue("organization_id") - organization, err := h.OrgService.GetOrganizationByID(ctx, actor, organizationID) + organization, err := h.UseCases.GetOrganizationByID(ctx, actor, organizationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -89,7 +89,7 @@ func (h *GetOrganizationByIDHandler) Handle() http.HandlerFunc { } type UpdateOrganizationHandler struct { - OrgService orgservices.OrganizationService + UseCases *orgusecases.UseCases } func (h *UpdateOrganizationHandler) Handle() http.HandlerFunc { @@ -112,7 +112,7 @@ func (h *UpdateOrganizationHandler) Handle() http.HandlerFunc { return } - organization, err := h.OrgService.UpdateOrganization(ctx, actor, organizationID, request) + organization, err := h.UseCases.UpdateOrganization(ctx, actor, organizationID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -123,7 +123,7 @@ func (h *UpdateOrganizationHandler) Handle() http.HandlerFunc { } type DeleteOrganizationHandler struct { - OrgService orgservices.OrganizationService + UseCases *orgusecases.UseCases } func (h *DeleteOrganizationHandler) Handle() http.HandlerFunc { @@ -133,7 +133,7 @@ func (h *DeleteOrganizationHandler) Handle() http.HandlerFunc { actor := reqCtx.Actor organizationID := r.PathValue("organization_id") - if err := h.OrgService.DeleteOrganization(ctx, actor, organizationID); err != nil { + if err := h.UseCases.DeleteOrganization(ctx, actor, organizationID); err != nil { orgconstants.HandleError(err, reqCtx) return } diff --git a/plugins/organizations/handlers/organization_handlers_test.go b/plugins/organizations/handlers/organization_handlers_test.go index 525660a5..99a5bc15 100644 --- a/plugins/organizations/handlers/organization_handlers_test.go +++ b/plugins/organizations/handlers/organization_handlers_test.go @@ -159,7 +159,7 @@ func TestCreateOrganizationHandler(t *testing.T) { tt.prepare(fixture) } - handler := &CreateOrganizationHandler{OrgService: fixture.service} + handler := &CreateOrganizationHandler{UseCases: newOrgUseCases(fixture.service)} req, w, reqCtx := fixture.newRequest(t, http.MethodPost, "/organizations", tt.body, tt.userID, "") if tt.name == "missing_user" { reqCtx.SetJSONResponse(http.StatusUnauthorized, map[string]any{"message": "Unauthorized"}) @@ -180,7 +180,7 @@ func TestCreateOrganizationHandler(t *testing.T) { } } -func TestGetAllOrganizationsHandler(t *testing.T) { +func TestGetAllOrganizationsByOwnerHandler(t *testing.T) { t.Parallel() tests := []organizationHandlerCase{ @@ -193,7 +193,7 @@ func TestGetAllOrganizationsHandler(t *testing.T) { name: "service_error", userID: new("user-1"), prepare: func(f *organizationHandlerFixture) { - f.service.On("GetAllOrganizations", mock.Anything, "user-1").Return(([]orgtypes.Organization)(nil), errors.New("some error")).Once() + f.service.On("GetAllOrganizationsByOwner", mock.Anything, "user-1").Return(([]orgtypes.Organization)(nil), errors.New("some error")).Once() }, expectedStatus: http.StatusBadRequest, expectedMessage: "some error", @@ -202,7 +202,7 @@ func TestGetAllOrganizationsHandler(t *testing.T) { name: "success", userID: new("user-1"), prepare: func(f *organizationHandlerFixture) { - f.service.On("GetAllOrganizations", mock.Anything, "user-1").Return([]orgtypes.Organization{{ID: "org-1", OwnerID: "user-1", Name: "Acme Inc", Slug: "acme-inc"}}, nil).Once() + f.service.On("GetAllOrganizationsByOwner", mock.Anything, "user-1").Return([]orgtypes.Organization{{ID: "org-1", OwnerID: "user-1", Name: "Acme Inc", Slug: "acme-inc"}}, nil).Once() }, expectedStatus: http.StatusOK, checkResponse: func(t *testing.T, reqCtx *models.RequestContext) { @@ -224,7 +224,7 @@ func TestGetAllOrganizationsHandler(t *testing.T) { tt.prepare(fixture) } - handler := &GetAllOrganizationsHandler{OrgService: fixture.service} + handler := &GetAllOrganizationsByOwnerHandler{UseCases: newOrgUseCases(fixture.service)} req, w, reqCtx := fixture.newRequest(t, http.MethodGet, "/organizations", nil, tt.userID, "") if tt.name == "missing_user" { reqCtx.SetJSONResponse(http.StatusUnauthorized, map[string]any{"message": "Unauthorized"}) @@ -318,7 +318,7 @@ func TestGetOrganizationByIDHandler(t *testing.T) { tt.prepare(fixture) } - handler := &GetOrganizationByIDHandler{OrgService: fixture.service} + handler := &GetOrganizationByIDHandler{UseCases: newOrgUseCases(fixture.service)} req, w, reqCtx := fixture.newRequest(t, http.MethodGet, "/organizations/test-id", nil, tt.userID, tt.organizationID) if tt.name == "missing_user" { reqCtx.SetJSONResponse(http.StatusUnauthorized, map[string]any{"message": "Unauthorized"}) @@ -467,7 +467,7 @@ func TestUpdateOrganizationHandler(t *testing.T) { tt.prepare(fixture) } - handler := &UpdateOrganizationHandler{OrgService: fixture.service} + handler := &UpdateOrganizationHandler{UseCases: newOrgUseCases(fixture.service)} req, w, reqCtx := fixture.newRequest(t, http.MethodPatch, "/organizations/test-id", tt.body, tt.userID, tt.organizationID) if tt.name == "missing_user" { reqCtx.SetJSONResponse(http.StatusUnauthorized, map[string]any{"message": "Unauthorized"}) @@ -542,7 +542,7 @@ func TestDeleteOrganizationHandler(t *testing.T) { tt.prepare(fixture) } - handler := &DeleteOrganizationHandler{OrgService: fixture.service} + handler := &DeleteOrganizationHandler{UseCases: newOrgUseCases(fixture.service)} req, w, reqCtx := fixture.newRequest(t, http.MethodDelete, "/organizations/test-id", nil, tt.userID, tt.organizationID) if tt.name == "missing_user" { reqCtx.SetJSONResponse(http.StatusUnauthorized, map[string]any{"message": "Unauthorized"}) diff --git a/plugins/organizations/handlers/organization_invitation_handlers.go b/plugins/organizations/handlers/organization_invitation_handlers.go index c69132ac..c037b570 100644 --- a/plugins/organizations/handlers/organization_invitation_handlers.go +++ b/plugins/organizations/handlers/organization_invitation_handlers.go @@ -6,12 +6,12 @@ import ( "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" orgconstants "github.com/Authula/authula/plugins/organizations/constants" - orgservices "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" ) type CreateOrganizationInvitationHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *CreateOrganizationInvitationHandler) Handle() http.HandlerFunc { @@ -34,7 +34,7 @@ func (h *CreateOrganizationInvitationHandler) Handle() http.HandlerFunc { return } - invitation, err := h.OrgInvitationService.CreateOrganizationInvitation(ctx, actor, organizationID, request) + invitation, err := h.UseCases.CreateOrganizationInvitation(ctx, actor, organizationID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -45,7 +45,7 @@ func (h *CreateOrganizationInvitationHandler) Handle() http.HandlerFunc { } type GetAllOrganizationInvitationsHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *GetAllOrganizationInvitationsHandler) Handle() http.HandlerFunc { @@ -55,7 +55,7 @@ func (h *GetAllOrganizationInvitationsHandler) Handle() http.HandlerFunc { actor := reqCtx.Actor organizationID := r.PathValue("organization_id") - invitations, err := h.OrgInvitationService.GetAllOrganizationInvitations(ctx, actor, organizationID) + invitations, err := h.UseCases.GetAllOrganizationInvitations(ctx, actor, organizationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -66,7 +66,7 @@ func (h *GetAllOrganizationInvitationsHandler) Handle() http.HandlerFunc { } type GetOrganizationInvitationHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *GetOrganizationInvitationHandler) Handle() http.HandlerFunc { @@ -77,7 +77,7 @@ func (h *GetOrganizationInvitationHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") invitationID := r.PathValue("invitation_id") - invitation, err := h.OrgInvitationService.GetOrganizationInvitation(ctx, actor, organizationID, invitationID) + invitation, err := h.UseCases.GetOrganizationInvitation(ctx, actor, organizationID, invitationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -88,7 +88,7 @@ func (h *GetOrganizationInvitationHandler) Handle() http.HandlerFunc { } type RevokeOrganizationInvitationHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *RevokeOrganizationInvitationHandler) Handle() http.HandlerFunc { @@ -99,7 +99,7 @@ func (h *RevokeOrganizationInvitationHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") invitationID := r.PathValue("invitation_id") - invitation, err := h.OrgInvitationService.RevokeOrganizationInvitation(ctx, actor, organizationID, invitationID) + invitation, err := h.UseCases.RevokeOrganizationInvitation(ctx, actor, organizationID, invitationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -110,7 +110,7 @@ func (h *RevokeOrganizationInvitationHandler) Handle() http.HandlerFunc { } type AcceptOrganizationInvitationHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *AcceptOrganizationInvitationHandler) Handle() http.HandlerFunc { @@ -121,7 +121,7 @@ func (h *AcceptOrganizationInvitationHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") invitationID := r.PathValue("invitation_id") - invitation, err := h.OrgInvitationService.AcceptOrganizationInvitation(ctx, actor, organizationID, invitationID) + invitation, err := h.UseCases.AcceptOrganizationInvitation(ctx, actor, organizationID, invitationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -151,7 +151,7 @@ func (h *AcceptOrganizationInvitationHandler) Handle() http.HandlerFunc { } type RejectOrganizationInvitationHandler struct { - OrgInvitationService orgservices.OrganizationInvitationService + UseCases *orgusecases.UseCases } func (h *RejectOrganizationInvitationHandler) Handle() http.HandlerFunc { @@ -167,7 +167,7 @@ func (h *RejectOrganizationInvitationHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") invitationID := r.PathValue("invitation_id") - invitation, err := h.OrgInvitationService.RejectOrganizationInvitation(ctx, actor, organizationID, invitationID) + invitation, err := h.UseCases.RejectOrganizationInvitation(ctx, actor, organizationID, invitationID) if err != nil { orgconstants.HandleError(err, reqCtx) return diff --git a/plugins/organizations/handlers/organization_invitation_handlers_test.go b/plugins/organizations/handlers/organization_invitation_handlers_test.go index 2f60466f..73cd28d4 100644 --- a/plugins/organizations/handlers/organization_invitation_handlers_test.go +++ b/plugins/organizations/handlers/organization_invitation_handlers_test.go @@ -92,7 +92,7 @@ func TestCreateOrganizationInvitationHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodPost, "/organizations/org-1/invitations", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&CreateOrganizationInvitationHandler{OrgInvitationService: fixture.service}).Handle() + return (&CreateOrganizationInvitationHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "missing_user", @@ -155,7 +155,7 @@ func TestGetAllOrganizationInvitationsHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodGet, "/organizations/org-1/invitations", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&GetAllOrganizationInvitationsHandler{OrgInvitationService: fixture.service}).Handle() + return (&GetAllOrganizationInvitationsHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "missing_user", @@ -195,7 +195,7 @@ func TestGetOrganizationInvitationHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodGet, "/organizations/org-1/invitations/inv-1", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&GetOrganizationInvitationHandler{OrgInvitationService: fixture.service}).Handle() + return (&GetOrganizationInvitationHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "missing_user", @@ -237,7 +237,7 @@ func TestRevokeOrganizationInvitationHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodPatch, "/organizations/org-1/invitations/inv-1", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&RevokeOrganizationInvitationHandler{OrgInvitationService: fixture.service}).Handle() + return (&RevokeOrganizationInvitationHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "missing_user", @@ -279,7 +279,7 @@ func TestAcceptOrganizationInvitationHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodPost, "/organizations/org-1/invitations/inv-1/accept", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&AcceptOrganizationInvitationHandler{OrgInvitationService: fixture.service}).Handle() + return (&AcceptOrganizationInvitationHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "redirect_url", @@ -349,7 +349,7 @@ func TestRejectOrganizationInvitationHandler(t *testing.T) { t.Parallel() runOrganizationInvitationHandlerCases(t, http.MethodPost, "/organizations/org-1/invitations/inv-1/reject", func(fixture *organizationInvitationHandlerFixture) http.HandlerFunc { - return (&RejectOrganizationInvitationHandler{OrgInvitationService: fixture.service}).Handle() + return (&RejectOrganizationInvitationHandler{UseCases: newInvitationUseCases(fixture.service)}).Handle() }, []organizationInvitationHandlerCase{ { name: "missing_user", diff --git a/plugins/organizations/handlers/organization_member_handlers.go b/plugins/organizations/handlers/organization_member_handlers.go index aecf1224..387e0f6b 100644 --- a/plugins/organizations/handlers/organization_member_handlers.go +++ b/plugins/organizations/handlers/organization_member_handlers.go @@ -6,12 +6,12 @@ import ( "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" orgconstants "github.com/Authula/authula/plugins/organizations/constants" - orgservices "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" ) type AddOrganizationMemberHandler struct { - OrgMemberService orgservices.OrganizationMemberService + UseCases *orgusecases.UseCases } func (h *AddOrganizationMemberHandler) Handle() http.HandlerFunc { @@ -34,7 +34,7 @@ func (h *AddOrganizationMemberHandler) Handle() http.HandlerFunc { return } - member, err := h.OrgMemberService.AddMember(ctx, actor, organizationID, request) + member, err := h.UseCases.AddMember(ctx, actor, organizationID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -51,7 +51,7 @@ func (h *AddOrganizationMemberHandler) Handle() http.HandlerFunc { } type GetAllOrganizationMembersHandler struct { - OrgMemberService orgservices.OrganizationMemberService + UseCases *orgusecases.UseCases } func (h *GetAllOrganizationMembersHandler) Handle() http.HandlerFunc { @@ -63,7 +63,7 @@ func (h *GetAllOrganizationMembersHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") page := util.GetQueryInt(r, "page", 1) limit := util.GetQueryInt(r, "limit", 10) - members, err := h.OrgMemberService.GetAllMembers(ctx, actor, organizationID, page, limit) + members, err := h.UseCases.GetAllMembers(ctx, actor, organizationID, page, limit) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -74,7 +74,7 @@ func (h *GetAllOrganizationMembersHandler) Handle() http.HandlerFunc { } type GetOrganizationMemberHandler struct { - OrgMemberService orgservices.OrganizationMemberService + UseCases *orgusecases.UseCases } func (h *GetOrganizationMemberHandler) Handle() http.HandlerFunc { @@ -85,7 +85,7 @@ func (h *GetOrganizationMemberHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") memberID := r.PathValue("member_id") - member, err := h.OrgMemberService.GetMember(ctx, actor, organizationID, memberID) + member, err := h.UseCases.GetMember(ctx, actor, organizationID, memberID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -96,7 +96,7 @@ func (h *GetOrganizationMemberHandler) Handle() http.HandlerFunc { } type UpdateOrganizationMemberHandler struct { - OrgMemberService orgservices.OrganizationMemberService + UseCases *orgusecases.UseCases } func (h *UpdateOrganizationMemberHandler) Handle() http.HandlerFunc { @@ -120,7 +120,7 @@ func (h *UpdateOrganizationMemberHandler) Handle() http.HandlerFunc { return } - member, err := h.OrgMemberService.UpdateMember(ctx, actor, organizationID, memberID, request) + member, err := h.UseCases.UpdateMember(ctx, actor, organizationID, memberID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -137,7 +137,7 @@ func (h *UpdateOrganizationMemberHandler) Handle() http.HandlerFunc { } type DeleteOrganizationMemberHandler struct { - OrgMemberService orgservices.OrganizationMemberService + UseCases *orgusecases.UseCases } func (h *DeleteOrganizationMemberHandler) Handle() http.HandlerFunc { @@ -149,7 +149,7 @@ func (h *DeleteOrganizationMemberHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") memberID := r.PathValue("member_id") - if err := h.OrgMemberService.RemoveMember(ctx, actor, organizationID, memberID); err != nil { + if err := h.UseCases.RemoveMember(ctx, actor, organizationID, memberID); err != nil { orgconstants.HandleError(err, reqCtx) return } diff --git a/plugins/organizations/handlers/organization_member_handlers_test.go b/plugins/organizations/handlers/organization_member_handlers_test.go index 8f854584..a2c73891 100644 --- a/plugins/organizations/handlers/organization_member_handlers_test.go +++ b/plugins/organizations/handlers/organization_member_handlers_test.go @@ -91,7 +91,7 @@ func TestAddOrganizationMemberHandler(t *testing.T) { t.Parallel() runOrganizationMemberHandlerCases(t, http.MethodPost, "/organizations/org-1/members", func(fixture *organizationMemberHandlerFixture) http.HandlerFunc { - return (&AddOrganizationMemberHandler{OrgMemberService: fixture.service}).Handle() + return (&AddOrganizationMemberHandler{UseCases: newMemberUseCases(fixture.service)}).Handle() }, []organizationMemberHandlerCase{ { name: "missing_user", @@ -160,7 +160,7 @@ func TestGetAllOrganizationMembersHandler(t *testing.T) { t.Parallel() runOrganizationMemberHandlerCases(t, http.MethodGet, "/organizations/org-1/members", func(fixture *organizationMemberHandlerFixture) http.HandlerFunc { - return (&GetAllOrganizationMembersHandler{OrgMemberService: fixture.service}).Handle() + return (&GetAllOrganizationMembersHandler{UseCases: newMemberUseCases(fixture.service)}).Handle() }, []organizationMemberHandlerCase{ { name: "missing_user", @@ -199,7 +199,7 @@ func TestGetOrganizationMemberHandler(t *testing.T) { t.Parallel() runOrganizationMemberHandlerCases(t, http.MethodGet, "/organizations/org-1/members/mem-1", func(fixture *organizationMemberHandlerFixture) http.HandlerFunc { - return (&GetOrganizationMemberHandler{OrgMemberService: fixture.service}).Handle() + return (&GetOrganizationMemberHandler{UseCases: newMemberUseCases(fixture.service)}).Handle() }, []organizationMemberHandlerCase{ { name: "missing_user", @@ -241,7 +241,7 @@ func TestUpdateOrganizationMemberHandler(t *testing.T) { t.Parallel() runOrganizationMemberHandlerCases(t, http.MethodPatch, "/organizations/org-1/members/mem-1", func(fixture *organizationMemberHandlerFixture) http.HandlerFunc { - return (&UpdateOrganizationMemberHandler{OrgMemberService: fixture.service}).Handle() + return (&UpdateOrganizationMemberHandler{UseCases: newMemberUseCases(fixture.service)}).Handle() }, []organizationMemberHandlerCase{ { name: "missing_user", @@ -301,7 +301,7 @@ func TestDeleteOrganizationMemberHandler(t *testing.T) { t.Parallel() runOrganizationMemberHandlerCases(t, http.MethodDelete, "/organizations/org-1/members/mem-1", func(fixture *organizationMemberHandlerFixture) http.HandlerFunc { - return (&DeleteOrganizationMemberHandler{OrgMemberService: fixture.service}).Handle() + return (&DeleteOrganizationMemberHandler{UseCases: newMemberUseCases(fixture.service)}).Handle() }, []organizationMemberHandlerCase{ { name: "missing_user", diff --git a/plugins/organizations/handlers/organization_team_handlers.go b/plugins/organizations/handlers/organization_team_handlers.go index 1b0c69c5..21292f24 100644 --- a/plugins/organizations/handlers/organization_team_handlers.go +++ b/plugins/organizations/handlers/organization_team_handlers.go @@ -6,12 +6,12 @@ import ( "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" orgconstants "github.com/Authula/authula/plugins/organizations/constants" - orgservices "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" ) type CreateOrganizationTeamHandler struct { - OrgTeamService orgservices.OrganizationTeamService + UseCases *orgusecases.UseCases } func (h *CreateOrganizationTeamHandler) Handle() http.HandlerFunc { @@ -34,7 +34,7 @@ func (h *CreateOrganizationTeamHandler) Handle() http.HandlerFunc { return } - team, err := h.OrgTeamService.CreateTeam(ctx, actor, organizationID, request) + team, err := h.UseCases.CreateTeam(ctx, actor, organizationID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -45,7 +45,7 @@ func (h *CreateOrganizationTeamHandler) Handle() http.HandlerFunc { } type GetAllOrganizationTeamsHandler struct { - OrgTeamService orgservices.OrganizationTeamService + UseCases *orgusecases.UseCases } func (h *GetAllOrganizationTeamsHandler) Handle() http.HandlerFunc { @@ -55,7 +55,7 @@ func (h *GetAllOrganizationTeamsHandler) Handle() http.HandlerFunc { actor := reqCtx.Actor organizationID := r.PathValue("organization_id") - teams, err := h.OrgTeamService.GetAllTeams(ctx, actor, organizationID) + teams, err := h.UseCases.GetAllTeams(ctx, actor, organizationID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -66,7 +66,7 @@ func (h *GetAllOrganizationTeamsHandler) Handle() http.HandlerFunc { } type GetOrganizationTeamHandler struct { - OrgTeamService orgservices.OrganizationTeamService + UseCases *orgusecases.UseCases } func (h *GetOrganizationTeamHandler) Handle() http.HandlerFunc { @@ -77,7 +77,7 @@ func (h *GetOrganizationTeamHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") teamID := r.PathValue("team_id") - team, err := h.OrgTeamService.GetTeam(ctx, actor, organizationID, teamID) + team, err := h.UseCases.GetTeam(ctx, actor, organizationID, teamID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -88,7 +88,7 @@ func (h *GetOrganizationTeamHandler) Handle() http.HandlerFunc { } type UpdateOrganizationTeamHandler struct { - OrgTeamService orgservices.OrganizationTeamService + UseCases *orgusecases.UseCases } func (h *UpdateOrganizationTeamHandler) Handle() http.HandlerFunc { @@ -112,7 +112,7 @@ func (h *UpdateOrganizationTeamHandler) Handle() http.HandlerFunc { return } - team, err := h.OrgTeamService.UpdateTeam(ctx, actor, organizationID, teamID, request) + team, err := h.UseCases.UpdateTeam(ctx, actor, organizationID, teamID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -123,7 +123,7 @@ func (h *UpdateOrganizationTeamHandler) Handle() http.HandlerFunc { } type DeleteOrganizationTeamHandler struct { - OrgTeamService orgservices.OrganizationTeamService + UseCases *orgusecases.UseCases } func (h *DeleteOrganizationTeamHandler) Handle() http.HandlerFunc { @@ -134,7 +134,7 @@ func (h *DeleteOrganizationTeamHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") teamID := r.PathValue("team_id") - if err := h.OrgTeamService.DeleteTeam(ctx, actor, organizationID, teamID); err != nil { + if err := h.UseCases.DeleteTeam(ctx, actor, organizationID, teamID); err != nil { orgconstants.HandleError(err, reqCtx) return } diff --git a/plugins/organizations/handlers/organization_team_handlers_test.go b/plugins/organizations/handlers/organization_team_handlers_test.go index 548d4944..b9f676c8 100644 --- a/plugins/organizations/handlers/organization_team_handlers_test.go +++ b/plugins/organizations/handlers/organization_team_handlers_test.go @@ -90,7 +90,7 @@ func TestCreateOrganizationTeamHandler(t *testing.T) { t.Parallel() runOrganizationTeamHandlerCases(t, http.MethodPost, "/organizations/org-1/teams", func(fixture *organizationTeamHandlerFixture) http.HandlerFunc { - return (&CreateOrganizationTeamHandler{OrgTeamService: fixture.service}).Handle() + return (&CreateOrganizationTeamHandler{UseCases: newTeamUseCases(fixture.service)}).Handle() }, []organizationTeamHandlerCase{ { name: "missing_user", @@ -141,7 +141,7 @@ func TestGetAllOrganizationTeamsHandler(t *testing.T) { t.Parallel() runOrganizationTeamHandlerCases(t, http.MethodGet, "/organizations/org-1/teams", func(fixture *organizationTeamHandlerFixture) http.HandlerFunc { - return (&GetAllOrganizationTeamsHandler{OrgTeamService: fixture.service}).Handle() + return (&GetAllOrganizationTeamsHandler{UseCases: newTeamUseCases(fixture.service)}).Handle() }, []organizationTeamHandlerCase{ { name: "missing_user", @@ -180,7 +180,7 @@ func TestGetOrganizationTeamHandler(t *testing.T) { t.Parallel() runOrganizationTeamHandlerCases(t, http.MethodGet, "/organizations/org-1/teams/team-1", func(fixture *organizationTeamHandlerFixture) http.HandlerFunc { - return (&GetOrganizationTeamHandler{OrgTeamService: fixture.service}).Handle() + return (&GetOrganizationTeamHandler{UseCases: newTeamUseCases(fixture.service)}).Handle() }, []organizationTeamHandlerCase{ { name: "missing_user", @@ -221,7 +221,7 @@ func TestUpdateOrganizationTeamHandler(t *testing.T) { t.Parallel() runOrganizationTeamHandlerCases(t, http.MethodPatch, "/organizations/org-1/teams/team-1", func(fixture *organizationTeamHandlerFixture) http.HandlerFunc { - return (&UpdateOrganizationTeamHandler{OrgTeamService: fixture.service}).Handle() + return (&UpdateOrganizationTeamHandler{UseCases: newTeamUseCases(fixture.service)}).Handle() }, []organizationTeamHandlerCase{ { name: "missing_user", @@ -274,7 +274,7 @@ func TestDeleteOrganizationTeamHandler(t *testing.T) { t.Parallel() runOrganizationTeamHandlerCases(t, http.MethodDelete, "/organizations/org-1/teams/team-1", func(fixture *organizationTeamHandlerFixture) http.HandlerFunc { - return (&DeleteOrganizationTeamHandler{OrgTeamService: fixture.service}).Handle() + return (&DeleteOrganizationTeamHandler{UseCases: newTeamUseCases(fixture.service)}).Handle() }, []organizationTeamHandlerCase{ { name: "missing_user", diff --git a/plugins/organizations/handlers/organization_team_member_handlers.go b/plugins/organizations/handlers/organization_team_member_handlers.go index d67ebbf6..f32093c2 100644 --- a/plugins/organizations/handlers/organization_team_member_handlers.go +++ b/plugins/organizations/handlers/organization_team_member_handlers.go @@ -6,12 +6,12 @@ import ( "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" orgconstants "github.com/Authula/authula/plugins/organizations/constants" - orgservices "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + orgusecases "github.com/Authula/authula/plugins/organizations/usecases" ) type AddOrganizationTeamMemberHandler struct { - OrgTeamMemberService orgservices.OrganizationTeamMemberService + UseCases *orgusecases.UseCases } func (h *AddOrganizationTeamMemberHandler) Handle() http.HandlerFunc { @@ -35,7 +35,7 @@ func (h *AddOrganizationTeamMemberHandler) Handle() http.HandlerFunc { return } - teamMember, err := h.OrgTeamMemberService.AddTeamMember(ctx, actor, organizationID, teamID, request) + teamMember, err := h.UseCases.AddTeamMember(ctx, actor, organizationID, teamID, request) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -46,7 +46,7 @@ func (h *AddOrganizationTeamMemberHandler) Handle() http.HandlerFunc { } type GetAllOrganizationTeamMembersHandler struct { - OrgTeamMemberService orgservices.OrganizationTeamMemberService + UseCases *orgusecases.UseCases } func (h *GetAllOrganizationTeamMembersHandler) Handle() http.HandlerFunc { @@ -59,7 +59,7 @@ func (h *GetAllOrganizationTeamMembersHandler) Handle() http.HandlerFunc { teamID := r.PathValue("team_id") page := util.GetQueryInt(r, "page", 1) limit := util.GetQueryInt(r, "limit", 10) - teamMembers, err := h.OrgTeamMemberService.GetAllTeamMembers(ctx, actor, organizationID, teamID, page, limit) + teamMembers, err := h.UseCases.GetAllTeamMembers(ctx, actor, organizationID, teamID, page, limit) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -70,7 +70,7 @@ func (h *GetAllOrganizationTeamMembersHandler) Handle() http.HandlerFunc { } type GetOrganizationTeamMemberHandler struct { - OrgTeamMemberService orgservices.OrganizationTeamMemberService + UseCases *orgusecases.UseCases } func (h *GetOrganizationTeamMemberHandler) Handle() http.HandlerFunc { @@ -82,7 +82,7 @@ func (h *GetOrganizationTeamMemberHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") teamID := r.PathValue("team_id") memberID := r.PathValue("member_id") - teamMember, err := h.OrgTeamMemberService.GetTeamMember(ctx, actor, organizationID, teamID, memberID) + teamMember, err := h.UseCases.GetTeamMember(ctx, actor, organizationID, teamID, memberID) if err != nil { orgconstants.HandleError(err, reqCtx) return @@ -93,7 +93,7 @@ func (h *GetOrganizationTeamMemberHandler) Handle() http.HandlerFunc { } type DeleteOrganizationTeamMemberHandler struct { - OrgTeamMemberService orgservices.OrganizationTeamMemberService + UseCases *orgusecases.UseCases } func (h *DeleteOrganizationTeamMemberHandler) Handle() http.HandlerFunc { @@ -105,7 +105,7 @@ func (h *DeleteOrganizationTeamMemberHandler) Handle() http.HandlerFunc { organizationID := r.PathValue("organization_id") teamID := r.PathValue("team_id") memberID := r.PathValue("member_id") - if err := h.OrgTeamMemberService.RemoveTeamMember(ctx, actor, organizationID, teamID, memberID); err != nil { + if err := h.UseCases.RemoveTeamMember(ctx, actor, organizationID, teamID, memberID); err != nil { orgconstants.HandleError(err, reqCtx) return } diff --git a/plugins/organizations/handlers/organization_team_member_handlers_test.go b/plugins/organizations/handlers/organization_team_member_handlers_test.go index 32e72e60..9edc45e0 100644 --- a/plugins/organizations/handlers/organization_team_member_handlers_test.go +++ b/plugins/organizations/handlers/organization_team_member_handlers_test.go @@ -94,7 +94,7 @@ func TestAddOrganizationTeamMemberHandler(t *testing.T) { t.Parallel() runOrganizationTeamMemberHandlerCases(t, http.MethodPost, "/organizations/org-1/teams/team-1/members", func(fixture *organizationTeamMemberHandlerFixture) http.HandlerFunc { - return (&AddOrganizationTeamMemberHandler{OrgTeamMemberService: fixture.service}).Handle() + return (&AddOrganizationTeamMemberHandler{UseCases: newTeamMemberUseCases(fixture.service)}).Handle() }, []organizationTeamMemberHandlerCase{ { name: "missing_user", @@ -149,7 +149,7 @@ func TestGetAllOrganizationTeamMembersHandler(t *testing.T) { t.Parallel() runOrganizationTeamMemberHandlerCases(t, http.MethodGet, "/organizations/org-1/teams/team-1/members", func(fixture *organizationTeamMemberHandlerFixture) http.HandlerFunc { - return (&GetAllOrganizationTeamMembersHandler{OrgTeamMemberService: fixture.service}).Handle() + return (&GetAllOrganizationTeamMembersHandler{UseCases: newTeamMemberUseCases(fixture.service)}).Handle() }, []organizationTeamMemberHandlerCase{ { name: "missing_user", @@ -191,7 +191,7 @@ func TestGetOrganizationTeamMemberHandler(t *testing.T) { t.Parallel() runOrganizationTeamMemberHandlerCases(t, http.MethodGet, "/organizations/org-1/teams/team-1/members/mem-1", func(fixture *organizationTeamMemberHandlerFixture) http.HandlerFunc { - return (&GetOrganizationTeamMemberHandler{OrgTeamMemberService: fixture.service}).Handle() + return (&GetOrganizationTeamMemberHandler{UseCases: newTeamMemberUseCases(fixture.service)}).Handle() }, []organizationTeamMemberHandlerCase{ { name: "missing_user", @@ -235,7 +235,7 @@ func TestDeleteOrganizationTeamMemberHandler(t *testing.T) { t.Parallel() runOrganizationTeamMemberHandlerCases(t, http.MethodDelete, "/organizations/org-1/teams/team-1/members/mem-1", func(fixture *organizationTeamMemberHandlerFixture) http.HandlerFunc { - return (&DeleteOrganizationTeamMemberHandler{OrgTeamMemberService: fixture.service}).Handle() + return (&DeleteOrganizationTeamMemberHandler{UseCases: newTeamMemberUseCases(fixture.service)}).Handle() }, []organizationTeamMemberHandlerCase{ { name: "missing_user", diff --git a/plugins/organizations/plugin.go b/plugins/organizations/plugin.go index 36593ba8..5d9c82ed 100644 --- a/plugins/organizations/plugin.go +++ b/plugins/organizations/plugin.go @@ -12,6 +12,7 @@ import ( "github.com/Authula/authula/plugins/organizations/repositories" "github.com/Authula/authula/plugins/organizations/services" "github.com/Authula/authula/plugins/organizations/types" + "github.com/Authula/authula/plugins/organizations/usecases" rootservices "github.com/Authula/authula/services" ) @@ -35,6 +36,7 @@ type OrganizationsPlugin struct { accessControlService rootservices.AccessControlService databaseHooks *OrganizationsHookExecutor emailTemplateManager *emailtmpl.Manager + useCases *usecases.UseCases } func New(config types.OrganizationsPluginConfig) *OrganizationsPlugin { @@ -82,8 +84,6 @@ func (p *OrganizationsPlugin) Init(ctx *models.PluginContext) error { return err } - authorizer := rootservices.NewDefaultAuthorizer() - p.databaseHooks = NewOrganizationsHookExecutor(p.pluginConfig.DatabaseHooks) p.organizationRepo = repositories.NewBunOrganizationRepository(ctx.DB, p.databaseHooks) p.invitationRepo = repositories.NewBunOrganizationInvitationRepository(ctx.DB, p.databaseHooks) @@ -91,7 +91,7 @@ func (p *OrganizationsPlugin) Init(ctx *models.PluginContext) error { p.teamRepo = repositories.NewBunOrganizationTeamRepository(ctx.DB, p.databaseHooks) p.teamMemberRepo = repositories.NewBunOrganizationTeamMemberRepository(ctx.DB, p.databaseHooks) - p.serviceUtils = services.NewServiceUtils(p.organizationRepo, p.memberRepo, p.teamRepo, p.teamMemberRepo, authorizer) + p.serviceUtils = services.NewServiceUtils(p.organizationRepo, p.memberRepo, p.teamRepo, p.teamMemberRepo) p.organizationService = services.NewOrganizationService(p.organizationRepo, p.memberRepo, p.serviceUtils, accessControlService, p.pluginConfig.OrganizationsLimit, ctx.DB) emailTemplateManager, err := newOrganizationEmailTemplateManager() if err != nil { @@ -104,6 +104,9 @@ func (p *OrganizationsPlugin) Init(ctx *models.PluginContext) error { p.teamService = services.NewOrganizationTeamService(p.organizationRepo, p.memberRepo, p.teamRepo, p.teamMemberRepo, p.serviceUtils, ctx.DB) p.teamMemberService = services.NewOrganizationTeamMemberService(p.organizationRepo, p.memberRepo, p.teamRepo, p.teamMemberRepo, p.serviceUtils) + authorizer := rootservices.NewDefaultAuthorizer() + p.useCases = usecases.NewUseCases(p.organizationService, p.invitationService, p.memberService, p.teamService, p.teamMemberService, authorizer) + p.Api = BuildAPI(p) ctx.ServiceRegistry.Register(models.ServiceOrganization.String(), OrganizationLookupService(p.Api)) @@ -130,8 +133,6 @@ func (p *OrganizationsPlugin) Close() error { func (p *OrganizationsPlugin) ensurePermissions() error { if err := p.accessControlService.EnsurePermissions(context.Background(), []rootservices.PermissionDefinition{ {Key: orgconstants.All, Description: "All organizations permissions"}, - {Key: orgconstants.OrganizationsCreatePermission, Description: "Create organizations"}, - {Key: orgconstants.OrganizationsListPermission, Description: "List organizations"}, {Key: orgconstants.OrganizationsReadPermission, Description: "Read organization details"}, {Key: orgconstants.OrganizationsUpdatePermission, Description: "Update organization details"}, {Key: orgconstants.OrganizationsDeletePermission, Description: "Delete organizations"}, diff --git a/plugins/organizations/routes.go b/plugins/organizations/routes.go index 964793d8..a02b9b46 100644 --- a/plugins/organizations/routes.go +++ b/plugins/organizations/routes.go @@ -9,35 +9,35 @@ import ( ) func Routes(plugin *OrganizationsPlugin) []models.Route { - createOrganizationHandler := &handlers.CreateOrganizationHandler{OrgService: plugin.organizationService} - getAllOrganizationsHandler := &handlers.GetAllOrganizationsHandler{OrgService: plugin.organizationService} - getOrganizationByIDHandler := &handlers.GetOrganizationByIDHandler{OrgService: plugin.organizationService} - updateOrganizationHandler := &handlers.UpdateOrganizationHandler{OrgService: plugin.organizationService} - deleteOrganizationHandler := &handlers.DeleteOrganizationHandler{OrgService: plugin.organizationService} + createOrganizationHandler := &handlers.CreateOrganizationHandler{UseCases: plugin.useCases} + getAllOrganizationsByOwnerHandler := &handlers.GetAllOrganizationsByOwnerHandler{UseCases: plugin.useCases} + getOrganizationByIDHandler := &handlers.GetOrganizationByIDHandler{UseCases: plugin.useCases} + updateOrganizationHandler := &handlers.UpdateOrganizationHandler{UseCases: plugin.useCases} + deleteOrganizationHandler := &handlers.DeleteOrganizationHandler{UseCases: plugin.useCases} - createInvitationHandler := &handlers.CreateOrganizationInvitationHandler{OrgInvitationService: plugin.invitationService} - getInvitationHandler := &handlers.GetOrganizationInvitationHandler{OrgInvitationService: plugin.invitationService} - getAllInvitationsHandler := &handlers.GetAllOrganizationInvitationsHandler{OrgInvitationService: plugin.invitationService} - revokeInvitationHandler := &handlers.RevokeOrganizationInvitationHandler{OrgInvitationService: plugin.invitationService} - acceptInvitationHandler := &handlers.AcceptOrganizationInvitationHandler{OrgInvitationService: plugin.invitationService} - rejectInvitationHandler := &handlers.RejectOrganizationInvitationHandler{OrgInvitationService: plugin.invitationService} + createInvitationHandler := &handlers.CreateOrganizationInvitationHandler{UseCases: plugin.useCases} + getInvitationHandler := &handlers.GetOrganizationInvitationHandler{UseCases: plugin.useCases} + getAllInvitationsHandler := &handlers.GetAllOrganizationInvitationsHandler{UseCases: plugin.useCases} + revokeInvitationHandler := &handlers.RevokeOrganizationInvitationHandler{UseCases: plugin.useCases} + acceptInvitationHandler := &handlers.AcceptOrganizationInvitationHandler{UseCases: plugin.useCases} + rejectInvitationHandler := &handlers.RejectOrganizationInvitationHandler{UseCases: plugin.useCases} - addMemberHandler := &handlers.AddOrganizationMemberHandler{OrgMemberService: plugin.memberService} - getAllMembersHandler := &handlers.GetAllOrganizationMembersHandler{OrgMemberService: plugin.memberService} - getMemberHandler := &handlers.GetOrganizationMemberHandler{OrgMemberService: plugin.memberService} - updateMemberHandler := &handlers.UpdateOrganizationMemberHandler{OrgMemberService: plugin.memberService} - deleteMemberHandler := &handlers.DeleteOrganizationMemberHandler{OrgMemberService: plugin.memberService} + addMemberHandler := &handlers.AddOrganizationMemberHandler{UseCases: plugin.useCases} + getAllMembersHandler := &handlers.GetAllOrganizationMembersHandler{UseCases: plugin.useCases} + getMemberHandler := &handlers.GetOrganizationMemberHandler{UseCases: plugin.useCases} + updateMemberHandler := &handlers.UpdateOrganizationMemberHandler{UseCases: plugin.useCases} + deleteMemberHandler := &handlers.DeleteOrganizationMemberHandler{UseCases: plugin.useCases} - createTeamHandler := &handlers.CreateOrganizationTeamHandler{OrgTeamService: plugin.teamService} - getAllTeamsHandler := &handlers.GetAllOrganizationTeamsHandler{OrgTeamService: plugin.teamService} - getTeamHandler := &handlers.GetOrganizationTeamHandler{OrgTeamService: plugin.teamService} - updateTeamHandler := &handlers.UpdateOrganizationTeamHandler{OrgTeamService: plugin.teamService} - deleteTeamHandler := &handlers.DeleteOrganizationTeamHandler{OrgTeamService: plugin.teamService} + createTeamHandler := &handlers.CreateOrganizationTeamHandler{UseCases: plugin.useCases} + getAllTeamsHandler := &handlers.GetAllOrganizationTeamsHandler{UseCases: plugin.useCases} + getTeamHandler := &handlers.GetOrganizationTeamHandler{UseCases: plugin.useCases} + updateTeamHandler := &handlers.UpdateOrganizationTeamHandler{UseCases: plugin.useCases} + deleteTeamHandler := &handlers.DeleteOrganizationTeamHandler{UseCases: plugin.useCases} - addTeamMemberHandler := &handlers.AddOrganizationTeamMemberHandler{OrgTeamMemberService: plugin.teamMemberService} - getAllTeamMembersHandler := &handlers.GetAllOrganizationTeamMembersHandler{OrgTeamMemberService: plugin.teamMemberService} - getTeamMemberHandler := &handlers.GetOrganizationTeamMemberHandler{OrgTeamMemberService: plugin.teamMemberService} - deleteTeamMemberHandler := &handlers.DeleteOrganizationTeamMemberHandler{OrgTeamMemberService: plugin.teamMemberService} + addTeamMemberHandler := &handlers.AddOrganizationTeamMemberHandler{UseCases: plugin.useCases} + getAllTeamMembersHandler := &handlers.GetAllOrganizationTeamMembersHandler{UseCases: plugin.useCases} + getTeamMemberHandler := &handlers.GetOrganizationTeamMemberHandler{UseCases: plugin.useCases} + deleteTeamMemberHandler := &handlers.DeleteOrganizationTeamMemberHandler{UseCases: plugin.useCases} return []models.Route{ // Organizations @@ -55,7 +55,7 @@ func Routes(plugin *OrganizationsPlugin) []models.Route { Middleware: []func(http.Handler) http.Handler{ middleware.RequireAuthenticated(), }, - Handler: getAllOrganizationsHandler.Handle(), + Handler: getAllOrganizationsByOwnerHandler.Handle(), }, { Method: http.MethodGet, diff --git a/plugins/organizations/services/interfaces.go b/plugins/organizations/services/interfaces.go index ccd8584e..d97f0e48 100644 --- a/plugins/organizations/services/interfaces.go +++ b/plugins/organizations/services/interfaces.go @@ -9,7 +9,7 @@ import ( type OrganizationService interface { CreateOrganization(ctx context.Context, actor *models.Actor, request types.CreateOrganizationRequest) (*types.Organization, error) - GetAllOrganizations(ctx context.Context, actor *models.Actor) ([]types.Organization, error) + GetAllOrganizationsByOwner(ctx context.Context, actor *models.Actor) ([]types.Organization, error) GetOrganizationByID(ctx context.Context, actor *models.Actor, organizationID string) (*types.Organization, error) UpdateOrganization(ctx context.Context, actor *models.Actor, organizationID string, request types.UpdateOrganizationRequest) (*types.Organization, error) DeleteOrganization(ctx context.Context, actor *models.Actor, organizationID string) error diff --git a/plugins/organizations/services/organization_invitation_service.go b/plugins/organizations/services/organization_invitation_service.go index 80071a60..d546fd03 100644 --- a/plugins/organizations/services/organization_invitation_service.go +++ b/plugins/organizations/services/organization_invitation_service.go @@ -82,10 +82,6 @@ func (s *organizationInvitationService) CreateOrganizationInvitation(ctx context } actorID := actor.ID - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsCreatePermission); err != nil { - return nil, err - } - organization, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID) if err != nil { return nil, err @@ -115,11 +111,11 @@ func (s *organizationInvitationService) CreateOrganizationInvitation(ctx context invitationRepo := s.orgInvitationRepo.WithTx(tx) memberRepo := s.orgMemberRepo.WithTx(tx) - if err := s.serviceUtils.ensureOrganizationMembersLimit(ctx, memberRepo, organizationID, s.pluginConfig.MembersLimit); err != nil { + if err := ensureOrganizationMembersLimit(ctx, memberRepo, organizationID, s.pluginConfig.MembersLimit); err != nil { return err } - if err := s.serviceUtils.ensureOrganizationInvitationsLimit(ctx, invitationRepo, organizationID, request.Email, s.pluginConfig.InvitationsLimit); err != nil { + if err := ensureOrganizationInvitationsLimit(ctx, invitationRepo, organizationID, request.Email, s.pluginConfig.InvitationsLimit); err != nil { return err } @@ -258,10 +254,6 @@ func (s *organizationInvitationService) GetAllOrganizationInvitations(ctx contex return nil, internalerrors.ErrUnauthorized } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsListPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -279,10 +271,6 @@ func (s *organizationInvitationService) GetOrganizationInvitation(ctx context.Co return nil, internalerrors.ErrUnauthorized } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsReadPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -303,10 +291,6 @@ func (s *organizationInvitationService) RevokeOrganizationInvitation(ctx context return nil, internalerrors.ErrUnauthorized } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsRevokePermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -340,7 +324,7 @@ func (s *organizationInvitationService) AcceptOrganizationInvitation(ctx context } actorID := actor.ID - user, err := s.serviceUtils.ensureEmailVerifiedForInvitationAcceptance(ctx, s.userService, actorID, s.pluginConfig.RequireEmailVerifiedOnInvitation) + user, err := ensureEmailVerifiedForInvitationAcceptance(ctx, s.userService, actorID, s.pluginConfig.RequireEmailVerifiedOnInvitation) if err != nil { return nil, err } @@ -425,7 +409,7 @@ func (s *organizationInvitationService) AcceptPendingOrganizationInvitationsForE } if s.pluginConfig.RequireEmailVerifiedOnInvitation { - if _, err := s.serviceUtils.ensureEmailVerifiedForInvitationAcceptance(ctx, s.userService, userID, true); err != nil { + if _, err := ensureEmailVerifiedForInvitationAcceptance(ctx, s.userService, userID, true); err != nil { return nil, err } } @@ -462,7 +446,7 @@ func (s *organizationInvitationService) acceptOrganizationInvitations(ctx contex return err } if existingMember == nil { - if err := s.serviceUtils.ensureOrganizationMembersLimit(ctx, memberRepo, invitation.OrganizationID, s.pluginConfig.MembersLimit); err != nil { + if err := ensureOrganizationMembersLimit(ctx, memberRepo, invitation.OrganizationID, s.pluginConfig.MembersLimit); err != nil { return err } @@ -515,3 +499,38 @@ func (s *organizationInvitationService) expireOrganizationInvitationIfNeeded(ctx return nil } + +func ensureOrganizationInvitationsLimit(ctx context.Context, invitationRepo repositories.OrganizationInvitationRepository, organizationID string, email string, invitationsLimit *int) error { + if invitationsLimit == nil || *invitationsLimit <= 0 { + return nil + } + + invitationCount, err := invitationRepo.CountByOrganizationIDAndEmail(ctx, organizationID, email) + if err != nil { + return err + } + if invitationCount >= *invitationsLimit { + return orgconstants.ErrInvitationsQuotaExceeded + } + + return nil +} + +func ensureEmailVerifiedForInvitationAcceptance(ctx context.Context, userService rootservices.UserService, userID string, requireEmailVerified bool) (*models.User, error) { + if userID == "" { + return nil, internalerrors.ErrNotFound + } + + user, err := userService.GetByID(ctx, userID) + if err != nil { + return nil, err + } + if user == nil || user.Email == "" { + return nil, internalerrors.ErrNotFound + } + if requireEmailVerified && !user.EmailVerified { + return nil, internalerrors.ErrForbidden + } + + return user, nil +} diff --git a/plugins/organizations/services/organization_invitation_service_test.go b/plugins/organizations/services/organization_invitation_service_test.go index 60b3a286..1f210f1f 100644 --- a/plugins/organizations/services/organization_invitation_service_test.go +++ b/plugins/organizations/services/organization_invitation_service_test.go @@ -50,7 +50,7 @@ func newTestOrganizationInvitationService( invRepo repositories.OrganizationInvitationRepository, memberRepo repositories.OrganizationMemberRepository, ) *organizationInvitationService { - serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo} tmplMgr := emailtmpl.NewManager() _ = tmplMgr.Register(emailtmpl.Definition{ Name: "organization_invitation", @@ -587,7 +587,7 @@ func TestOrganizationInvitationService_CreateOrganizationInvitation(t *testing.T accessControlService = orgtests.NewAccessControlServiceStub() } - serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo} tmplMgr := emailtmpl.NewManager() _ = tmplMgr.Register(emailtmpl.Definition{ Name: "organization_invitation", diff --git a/plugins/organizations/services/organization_member_service.go b/plugins/organizations/services/organization_member_service.go index 2cdac7e7..387484eb 100644 --- a/plugins/organizations/services/organization_member_service.go +++ b/plugins/organizations/services/organization_member_service.go @@ -34,10 +34,6 @@ func NewOrganizationMemberService(userService rootservices.UserService, accessCo } func (s *organizationMemberService) AddMember(ctx context.Context, actor *models.Actor, organizationID string, request types.AddOrganizationMemberRequest) (*types.OrganizationMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsMembersAddPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -84,7 +80,7 @@ func (s *organizationMemberService) AddMember(ctx context.Context, actor *models var created *types.OrganizationMember err = s.txRunner.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { memberRepo := s.orgMemberRepo.WithTx(tx) - if err := s.serviceUtils.ensureOrganizationMembersLimit(ctx, memberRepo, organizationID, s.membersLimit); err != nil { + if err := ensureOrganizationMembersLimit(ctx, memberRepo, organizationID, s.membersLimit); err != nil { return err } @@ -111,10 +107,6 @@ func (s *organizationMemberService) AddMember(ctx context.Context, actor *models } func (s *organizationMemberService) GetAllMembers(ctx context.Context, actor *models.Actor, organizationID string, page int, limit int) ([]types.OrganizationMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsMembersListPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -123,10 +115,6 @@ func (s *organizationMemberService) GetAllMembers(ctx context.Context, actor *mo } func (s *organizationMemberService) GetMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) (*types.OrganizationMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsMembersReadPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -147,10 +135,6 @@ func (s *organizationMemberService) GetMember(ctx context.Context, actor *models } func (s *organizationMemberService) UpdateMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string, request types.UpdateOrganizationMemberRequest) (*types.OrganizationMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsMembersUpdatePermission); err != nil { - return nil, err - } - _, actorMember, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID) if err != nil { return nil, err @@ -199,10 +183,6 @@ func (s *organizationMemberService) UpdateMember(ctx context.Context, actor *mod } func (s *organizationMemberService) RemoveMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) error { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsMembersRemovePermission); err != nil { - return err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return err } @@ -221,3 +201,19 @@ func (s *organizationMemberService) RemoveMember(ctx context.Context, actor *mod return nil } + +func ensureOrganizationMembersLimit(ctx context.Context, memberRepo repositories.OrganizationMemberRepository, organizationID string, membersLimit *int) error { + if membersLimit == nil || *membersLimit <= 0 { + return nil + } + + memberCount, err := memberRepo.CountByOrganizationID(ctx, organizationID) + if err != nil { + return err + } + if memberCount >= *membersLimit { + return constants.ErrMembersQuotaExceeded + } + + return nil +} diff --git a/plugins/organizations/services/organization_member_service_test.go b/plugins/organizations/services/organization_member_service_test.go index 8eb898a7..e5c37b82 100644 --- a/plugins/organizations/services/organization_member_service_test.go +++ b/plugins/organizations/services/organization_member_service_test.go @@ -19,7 +19,7 @@ import ( ) func newTestOrganizationMemberService(userSvc *internaltests.MockUserService, accessControlService rootservices.AccessControlService, orgRepo *orgtests.MockOrganizationRepository, memberRepo *orgtests.MockOrganizationMemberRepository, membersLimit *int) *organizationMemberService { - serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo} return NewOrganizationMemberService(userSvc, accessControlService, orgRepo, memberRepo, membersLimit, &orgtests.MockTxRunner{}, serviceUtils) } diff --git a/plugins/organizations/services/organization_service.go b/plugins/organizations/services/organization_service.go index 9a4c1b1d..4745eb1c 100644 --- a/plugins/organizations/services/organization_service.go +++ b/plugins/organizations/services/organization_service.go @@ -4,7 +4,9 @@ import ( "context" "database/sql" "sort" + "strings" "sync" + "unicode" "github.com/uptrace/bun" @@ -53,10 +55,6 @@ func (s *organizationService) CreateOrganization(ctx context.Context, actor *mod return nil, internalerrors.ErrUnauthorized } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeScope(ctx, actor, constants.OrganizationsCreatePermission); err != nil { - return nil, err - } - name := request.Name if name == "" { return nil, internalerrors.ErrUnprocessableEntity @@ -79,7 +77,7 @@ func (s *organizationService) CreateOrganization(ctx context.Context, actor *mod slug = *request.Slug } if slug == "" { - slug = s.serviceUtils.slugify(name) + slug = slugify(name) } if slug == "" { return nil, internalerrors.ErrUnprocessableEntity @@ -190,15 +188,11 @@ func (s *organizationService) ensureOrganizationLimit(ctx context.Context, actor return nil } -func (s *organizationService) GetAllOrganizations(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { +func (s *organizationService) GetAllOrganizationsByOwner(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { if actor == nil || actor.ID == "" { return nil, internalerrors.ErrUnauthorized } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeScope(ctx, actor, constants.OrganizationsListPermission); err != nil { - return nil, err - } - ownedOrganizations, err := s.orgRepo.GetAllByOwnerID(ctx, actor.ID) if err != nil { return nil, err @@ -248,10 +242,6 @@ func (s *organizationService) GetAllOrganizations(ctx context.Context, actor *mo } func (s *organizationService) GetOrganizationByID(ctx context.Context, actor *models.Actor, organizationID string) (*types.Organization, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsReadPermission); err != nil { - return nil, err - } - organization, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID) if err != nil { return nil, err @@ -261,10 +251,6 @@ func (s *organizationService) GetOrganizationByID(ctx context.Context, actor *mo } func (s *organizationService) UpdateOrganization(ctx context.Context, actor *models.Actor, organizationID string, request types.UpdateOrganizationRequest) (*types.Organization, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsUpdatePermission); err != nil { - return nil, err - } - organization, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID) if err != nil { return nil, err @@ -280,7 +266,7 @@ func (s *organizationService) UpdateOrganization(ctx context.Context, actor *mod slug = *request.Slug } if slug == "" { - slug = s.serviceUtils.slugify(*name) + slug = slugify(*name) } if slug == "" { return nil, internalerrors.ErrUnprocessableEntity @@ -317,10 +303,6 @@ func (s *organizationService) ExistsByID(ctx context.Context, organizationID str } func (s *organizationService) DeleteOrganization(ctx context.Context, actor *models.Actor, organizationID string) error { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsDeletePermission); err != nil { - return err - } - _, err := s.serviceUtils.authorizeOwner(ctx, actor, organizationID) if err != nil { return err @@ -332,3 +314,23 @@ func (s *organizationService) DeleteOrganization(ctx context.Context, actor *mod return nil } + +func slugify(input string) string { + input = strings.ToLower(input) + var builder strings.Builder + lastDash := false + + for _, r := range input { + if unicode.IsLetter(r) || unicode.IsDigit(r) { + builder.WriteRune(r) + lastDash = false + continue + } + if !lastDash { + builder.WriteByte('-') + lastDash = true + } + } + + return strings.Trim(builder.String(), "-") +} diff --git a/plugins/organizations/services/organization_service_test.go b/plugins/organizations/services/organization_service_test.go index 500da47c..5badc26e 100644 --- a/plugins/organizations/services/organization_service_test.go +++ b/plugins/organizations/services/organization_service_test.go @@ -126,7 +126,7 @@ func TestOrganizationService_CreateOrganization(t *testing.T) { repo := &orgtests.MockOrganizationRepository{} memberRepo := &orgtests.MockOrganizationMemberRepository{} hooks := &orgtests.MockOrganizationHooks{} - serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo} if tt.setup != nil { tt.setup(repo, memberRepo, hooks, serviceUtils) } @@ -156,7 +156,7 @@ func TestOrganizationService_CreateOrganization(t *testing.T) { } } -func TestOrganizationService_GetAllOrganizations(t *testing.T) { +func TestOrganizationService_GetAllOrganizationsByOwner(t *testing.T) { t.Parallel() tests := []struct { @@ -193,9 +193,9 @@ func TestOrganizationService_GetAllOrganizations(t *testing.T) { tt.setup(repo, memberRepo) } - serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo} svc := NewOrganizationService(repo, memberRepo, serviceUtils, nil, nil, nil) - organizations, err := svc.GetAllOrganizations(context.Background(), orgtests.Actor(tt.actorUserID)) + organizations, err := svc.GetAllOrganizationsByOwner(context.Background(), orgtests.Actor(tt.actorUserID)) if tt.expectErr != nil { require.Error(t, err) require.ErrorIs(t, err, tt.expectErr) @@ -258,7 +258,7 @@ func TestOrganizationService_GetOrganizationByID(t *testing.T) { tt.setup(repo, memberRepo) } - serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo} svc := NewOrganizationService(repo, memberRepo, serviceUtils, nil, nil, nil) org, err := svc.GetOrganizationByID(context.Background(), orgtests.Actor(tt.actorUserID), tt.organizationID) if tt.expectErr != nil { @@ -343,7 +343,7 @@ func TestOrganizationService_UpdateOrganization(t *testing.T) { repo := &orgtests.MockOrganizationRepository{} hooks := &orgtests.MockOrganizationHooks{} memberRepo := &orgtests.MockOrganizationMemberRepository{} - serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: repo, orgMemberRepo: memberRepo} if tt.setup != nil { tt.setup(repo, memberRepo, hooks, serviceUtils) } @@ -388,7 +388,7 @@ func TestOrganizationService_DeleteOrganization(t *testing.T) { repo := &orgtests.MockOrganizationRepository{} hooks := &orgtests.MockOrganizationHooks{} - serviceUtils := &ServiceUtils{orgRepo: repo, authorizer: &noopAuthorizer{}} + serviceUtils := &ServiceUtils{orgRepo: repo} if tt.setup != nil { tt.setup(repo, hooks, serviceUtils) } diff --git a/plugins/organizations/services/organization_team_member_service.go b/plugins/organizations/services/organization_team_member_service.go index 3e55aecd..92f95251 100644 --- a/plugins/organizations/services/organization_team_member_service.go +++ b/plugins/organizations/services/organization_team_member_service.go @@ -6,7 +6,6 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/organizations/constants" "github.com/Authula/authula/plugins/organizations/repositories" "github.com/Authula/authula/plugins/organizations/types" ) @@ -35,10 +34,6 @@ func (s *organizationTeamMemberService) AddTeamMember(ctx context.Context, actor return nil, internalerrors.ErrUnprocessableEntity } - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamMembersAddPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -84,10 +79,6 @@ func (s *organizationTeamMemberService) AddTeamMember(ctx context.Context, actor } func (s *organizationTeamMemberService) GetAllTeamMembers(ctx context.Context, actor *models.Actor, organizationID string, teamID string, page int, limit int) ([]types.OrganizationTeamMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamMembersListPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -108,10 +99,6 @@ func (s *organizationTeamMemberService) GetAllTeamMembers(ctx context.Context, a } func (s *organizationTeamMemberService) GetTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) (*types.OrganizationTeamMember, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamMembersReadPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -148,10 +135,6 @@ func (s *organizationTeamMemberService) GetTeamMember(ctx context.Context, actor } func (s *organizationTeamMemberService) RemoveTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) error { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamMembersRemovePermission); err != nil { - return err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return err } diff --git a/plugins/organizations/services/organization_team_member_service_test.go b/plugins/organizations/services/organization_team_member_service_test.go index 32484bd8..e368d218 100644 --- a/plugins/organizations/services/organization_team_member_service_test.go +++ b/plugins/organizations/services/organization_team_member_service_test.go @@ -19,7 +19,6 @@ func newTestOrganizationTeamMemberService(orgRepo *orgtests.MockOrganizationRepo orgMemberRepo: memberRepo, orgTeamRepo: teamRepo, orgTeamMemberRepo: teamMemberRepo, - authorizer: &noopAuthorizer{}, } return NewOrganizationTeamMemberService(orgRepo, memberRepo, teamRepo, teamMemberRepo, serviceUtils) @@ -452,7 +451,6 @@ func TestOrganizationTeamService_AddTeamMember(t *testing.T) { orgMemberRepo: memberRepo, orgTeamRepo: teamRepo, orgTeamMemberRepo: teamMemberRepo, - authorizer: &noopAuthorizer{}, } if tt.setup != nil { diff --git a/plugins/organizations/services/organization_team_service.go b/plugins/organizations/services/organization_team_service.go index 52e8ed09..1b75997e 100644 --- a/plugins/organizations/services/organization_team_service.go +++ b/plugins/organizations/services/organization_team_service.go @@ -9,7 +9,6 @@ import ( internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/internal/util" "github.com/Authula/authula/models" - "github.com/Authula/authula/plugins/organizations/constants" "github.com/Authula/authula/plugins/organizations/repositories" "github.com/Authula/authula/plugins/organizations/types" ) @@ -39,10 +38,6 @@ func NewOrganizationTeamService( } func (s *organizationTeamService) CreateTeam(ctx context.Context, actor *models.Actor, organizationID string, request types.CreateOrganizationTeamRequest) (*types.OrganizationTeam, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamsCreatePermission); err != nil { - return nil, err - } - organization, actorMember, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID) if err != nil { return nil, err @@ -59,7 +54,7 @@ func (s *organizationTeamService) CreateTeam(ctx context.Context, actor *models. slug = *request.Slug } if slug == "" { - slug = s.serviceUtils.slugify(name) + slug = slugify(name) } if slug == "" { return nil, internalerrors.ErrBadRequest @@ -130,10 +125,6 @@ func (s *organizationTeamService) CreateTeam(ctx context.Context, actor *models. } func (s *organizationTeamService) GetAllTeams(ctx context.Context, actor *models.Actor, organizationID string) ([]types.OrganizationTeam, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamsListPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -142,10 +133,6 @@ func (s *organizationTeamService) GetAllTeams(ctx context.Context, actor *models } func (s *organizationTeamService) GetTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) (*types.OrganizationTeam, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamsReadPermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -166,10 +153,6 @@ func (s *organizationTeamService) GetTeam(ctx context.Context, actor *models.Act } func (s *organizationTeamService) UpdateTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string, request types.UpdateOrganizationTeamRequest) (*types.OrganizationTeam, error) { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamsUpdatePermission); err != nil { - return nil, err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return nil, err } @@ -196,7 +179,7 @@ func (s *organizationTeamService) UpdateTeam(ctx context.Context, actor *models. slug = *request.Slug } if slug == "" { - slug = s.serviceUtils.slugify(name) + slug = slugify(name) } if slug == "" { return nil, internalerrors.ErrBadRequest @@ -225,10 +208,6 @@ func (s *organizationTeamService) UpdateTeam(ctx context.Context, actor *models. } func (s *organizationTeamService) DeleteTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) error { - if err := s.serviceUtils.authorizerOrDefault().AuthorizeOrganizationAccess(ctx, actor, organizationID, constants.OrganizationsTeamsDeletePermission); err != nil { - return err - } - if _, _, err := s.serviceUtils.authorizeOrganizationAccess(ctx, actor, organizationID); err != nil { return err } diff --git a/plugins/organizations/services/organization_team_service_test.go b/plugins/organizations/services/organization_team_service_test.go index e8f9d211..93c0de1e 100644 --- a/plugins/organizations/services/organization_team_service_test.go +++ b/plugins/organizations/services/organization_team_service_test.go @@ -19,7 +19,6 @@ func newTestOrganizationTeamService(orgRepo *orgtests.MockOrganizationRepository orgMemberRepo: memberRepo, orgTeamRepo: teamRepo, orgTeamMemberRepo: teamMemberRepo, - authorizer: &noopAuthorizer{}, } return NewOrganizationTeamService(orgRepo, memberRepo, teamRepo, teamMemberRepo, serviceUtils, nil) @@ -204,7 +203,6 @@ func TestOrganizationTeamService_CreateTeam(t *testing.T) { orgMemberRepo: memberRepo, orgTeamRepo: teamRepo, orgTeamMemberRepo: teamMemberRepo, - authorizer: &noopAuthorizer{}, } if tt.setup != nil { diff --git a/plugins/organizations/services/service_utils.go b/plugins/organizations/services/service_utils.go index 253cce65..192937cc 100644 --- a/plugins/organizations/services/service_utils.go +++ b/plugins/organizations/services/service_utils.go @@ -2,15 +2,11 @@ package services import ( "context" - "strings" - "unicode" internalerrors "github.com/Authula/authula/internal/errors" "github.com/Authula/authula/models" - orgconstants "github.com/Authula/authula/plugins/organizations/constants" "github.com/Authula/authula/plugins/organizations/repositories" "github.com/Authula/authula/plugins/organizations/types" - rootservices "github.com/Authula/authula/services" ) type ServiceUtils struct { @@ -18,27 +14,17 @@ type ServiceUtils struct { orgMemberRepo repositories.OrganizationMemberRepository orgTeamRepo repositories.OrganizationTeamRepository orgTeamMemberRepo repositories.OrganizationTeamMemberRepository - authorizer rootservices.Authorizer } -func NewServiceUtils(orgRepo repositories.OrganizationRepository, orgMemberRepo repositories.OrganizationMemberRepository, orgTeamRepo repositories.OrganizationTeamRepository, orgTeamMemberRepo repositories.OrganizationTeamMemberRepository, authorizer rootservices.Authorizer) *ServiceUtils { +func NewServiceUtils(orgRepo repositories.OrganizationRepository, orgMemberRepo repositories.OrganizationMemberRepository, orgTeamRepo repositories.OrganizationTeamRepository, orgTeamMemberRepo repositories.OrganizationTeamMemberRepository) *ServiceUtils { return &ServiceUtils{ orgRepo: orgRepo, orgMemberRepo: orgMemberRepo, orgTeamRepo: orgTeamRepo, orgTeamMemberRepo: orgTeamMemberRepo, - authorizer: authorizer, } } -func (s *ServiceUtils) authorizerOrDefault() rootservices.Authorizer { - if s != nil && s.authorizer != nil { - return s.authorizer - } - - return rootservices.NewDefaultAuthorizer() -} - func (s *ServiceUtils) authorizeOwner(ctx context.Context, actor *models.Actor, organizationID string) (*types.Organization, error) { if actor == nil || actor.ID == "" || organizationID == "" { return nil, internalerrors.ErrUnauthorized @@ -91,77 +77,6 @@ func (s *ServiceUtils) authorizeOrganizationAccess(ctx context.Context, actor *m return organization, member, nil } -func (s *ServiceUtils) ensureOrganizationMembersLimit(ctx context.Context, memberRepo repositories.OrganizationMemberRepository, organizationID string, membersLimit *int) error { - if membersLimit == nil || *membersLimit <= 0 { - return nil - } - - memberCount, err := memberRepo.CountByOrganizationID(ctx, organizationID) - if err != nil { - return err - } - if memberCount >= *membersLimit { - return orgconstants.ErrMembersQuotaExceeded - } - - return nil -} - -func (s *ServiceUtils) ensureOrganizationInvitationsLimit(ctx context.Context, invitationRepo repositories.OrganizationInvitationRepository, organizationID string, email string, invitationsLimit *int) error { - if invitationsLimit == nil || *invitationsLimit <= 0 { - return nil - } - - invitationCount, err := invitationRepo.CountByOrganizationIDAndEmail(ctx, organizationID, email) - if err != nil { - return err - } - if invitationCount >= *invitationsLimit { - return orgconstants.ErrInvitationsQuotaExceeded - } - - return nil -} - -func (s *ServiceUtils) ensureEmailVerifiedForInvitationAcceptance(ctx context.Context, userService rootservices.UserService, userID string, requireEmailVerified bool) (*models.User, error) { - if userID == "" { - return nil, internalerrors.ErrNotFound - } - - user, err := userService.GetByID(ctx, userID) - if err != nil { - return nil, err - } - if user == nil || user.Email == "" { - return nil, internalerrors.ErrNotFound - } - if requireEmailVerified && !user.EmailVerified { - return nil, internalerrors.ErrForbidden - } - - return user, nil -} - -func (s *ServiceUtils) slugify(input string) string { - input = strings.ToLower(input) - var builder strings.Builder - lastDash := false - - for _, r := range input { - if unicode.IsLetter(r) || unicode.IsDigit(r) { - builder.WriteRune(r) - lastDash = false - continue - } - if !lastDash { - builder.WriteByte('-') - lastDash = true - } - } - - return strings.Trim(builder.String(), "-") -} - func (s *ServiceUtils) authorizeTeamAccess(ctx context.Context, actor *models.Actor, orgID string, teamID string) error { team, err := s.orgTeamRepo.GetByID(ctx, teamID) if err != nil { diff --git a/plugins/organizations/services/service_utils_test.go b/plugins/organizations/services/service_utils_test.go index 2232a5e6..a009030f 100644 --- a/plugins/organizations/services/service_utils_test.go +++ b/plugins/organizations/services/service_utils_test.go @@ -16,16 +16,6 @@ import ( "github.com/Authula/authula/plugins/organizations/types" ) -type noopAuthorizer struct{} - -func (a *noopAuthorizer) AuthorizeScope(_ context.Context, _ *models.Actor, _ string) error { - return nil -} - -func (a *noopAuthorizer) AuthorizeOrganizationAccess(_ context.Context, _ *models.Actor, _ string, _ string) error { - return nil -} - func TestServiceUtils_authorizeOwner(t *testing.T) { t.Parallel() @@ -92,7 +82,7 @@ func TestServiceUtils_authorizeOwner(t *testing.T) { tt.setup(orgRepo) } - org, err := (&ServiceUtils{orgRepo: orgRepo, authorizer: &noopAuthorizer{}}).authorizeOwner(context.Background(), orgtests.Actor(tt.actorUserID), tt.organization) + org, err := (&ServiceUtils{orgRepo: orgRepo}).authorizeOwner(context.Background(), orgtests.Actor(tt.actorUserID), tt.organization) if tt.expectErr != nil { require.ErrorIs(t, err, tt.expectErr) require.Nil(t, org) @@ -198,7 +188,7 @@ func TestServiceUtils_authorizeOrganizationAccess(t *testing.T) { tt.setup(orgRepo, memberRepo) } - org, member, err := (&ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo, authorizer: &noopAuthorizer{}}).authorizeOrganizationAccess(context.Background(), orgtests.Actor(tt.actorUserID), tt.organization) + org, member, err := (&ServiceUtils{orgRepo: orgRepo, orgMemberRepo: memberRepo}).authorizeOrganizationAccess(context.Background(), orgtests.Actor(tt.actorUserID), tt.organization) if tt.expectErr != nil { require.ErrorIs(t, err, tt.expectErr) require.Nil(t, org) @@ -278,7 +268,7 @@ func TestServiceUtils_ensureOrganizationMembersLimit(t *testing.T) { tt.setup(memberRepo) } - err := (&ServiceUtils{}).ensureOrganizationMembersLimit(context.Background(), memberRepo, "org-1", tt.limit) + err := ensureOrganizationMembersLimit(context.Background(), memberRepo, "org-1", tt.limit) if tt.expectErr != nil { require.ErrorIs(t, err, tt.expectErr) memberRepo.AssertExpectations(t) @@ -347,7 +337,7 @@ func TestServiceUtils_ensureOrganizationInvitationsLimit(t *testing.T) { tt.setup(invRepo) } - err := (&ServiceUtils{}).ensureOrganizationInvitationsLimit(context.Background(), invRepo, "org-1", "user@example.com", tt.limit) + err := ensureOrganizationInvitationsLimit(context.Background(), invRepo, "org-1", "user@example.com", tt.limit) if tt.expectErr != nil { require.ErrorIs(t, err, tt.expectErr) invRepo.AssertExpectations(t) @@ -444,7 +434,7 @@ func TestServiceUtils_ensureEmailVerifiedForInvitationAcceptance(t *testing.T) { tt.setup(userSvc) } - user, err := (&ServiceUtils{}).ensureEmailVerifiedForInvitationAcceptance(context.Background(), userSvc, tt.userID, tt.requireEmailVerified) + user, err := ensureEmailVerifiedForInvitationAcceptance(context.Background(), userSvc, tt.userID, tt.requireEmailVerified) if tt.expectErr != nil { require.ErrorIs(t, err, tt.expectErr) require.Nil(t, user) @@ -477,11 +467,10 @@ func TestServiceUtils_slugify(t *testing.T) { {name: "returns empty for punctuation only", input: "!!!", expect: ""}, } - utils := &ServiceUtils{} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() - require.Equal(t, tt.expect, utils.slugify(tt.input)) + require.Equal(t, tt.expect, slugify(tt.input)) }) } } diff --git a/plugins/organizations/tests/services.go b/plugins/organizations/tests/services.go index bb2a9909..9944a2c6 100644 --- a/plugins/organizations/tests/services.go +++ b/plugins/organizations/tests/services.go @@ -29,7 +29,7 @@ func (m *MockOrganizationService) CreateOrganization(ctx context.Context, actor return args.Get(0).(*types.Organization), args.Error(1) } -func (m *MockOrganizationService) GetAllOrganizations(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { +func (m *MockOrganizationService) GetAllOrganizationsByOwner(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { args := m.Called(ctx, actorID(actor)) if args.Get(0) == nil { return nil, args.Error(1) diff --git a/plugins/organizations/usecases/usecases.go b/plugins/organizations/usecases/usecases.go new file mode 100644 index 00000000..9ea2cc6d --- /dev/null +++ b/plugins/organizations/usecases/usecases.go @@ -0,0 +1,215 @@ +package usecases + +import ( + "context" + + "github.com/Authula/authula/models" + orgconstants "github.com/Authula/authula/plugins/organizations/constants" + orgservices "github.com/Authula/authula/plugins/organizations/services" + "github.com/Authula/authula/plugins/organizations/types" + rootservices "github.com/Authula/authula/services" +) + +type UseCases struct { + orgService orgservices.OrganizationService + invitationService orgservices.OrganizationInvitationService + memberService orgservices.OrganizationMemberService + teamService orgservices.OrganizationTeamService + teamMemberService orgservices.OrganizationTeamMemberService + authorizer rootservices.Authorizer +} + +func NewUseCases( + orgService orgservices.OrganizationService, + invitationService orgservices.OrganizationInvitationService, + memberService orgservices.OrganizationMemberService, + teamService orgservices.OrganizationTeamService, + teamMemberService orgservices.OrganizationTeamMemberService, + authorizer rootservices.Authorizer, +) *UseCases { + return &UseCases{ + orgService: orgService, + invitationService: invitationService, + memberService: memberService, + teamService: teamService, + teamMemberService: teamMemberService, + authorizer: authorizer, + } +} + +// ------------- OrganizationService ------------- + +func (u *UseCases) CreateOrganization(ctx context.Context, actor *models.Actor, request types.CreateOrganizationRequest) (*types.Organization, error) { + return u.orgService.CreateOrganization(ctx, actor, request) +} + +func (u *UseCases) GetAllOrganizationsByOwner(ctx context.Context, actor *models.Actor) ([]types.Organization, error) { + return u.orgService.GetAllOrganizationsByOwner(ctx, actor) +} + +func (u *UseCases) GetOrganizationByID(ctx context.Context, actor *models.Actor, organizationID string) (*types.Organization, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsReadPermission); err != nil { + return nil, err + } + return u.orgService.GetOrganizationByID(ctx, actor, organizationID) +} + +func (u *UseCases) UpdateOrganization(ctx context.Context, actor *models.Actor, organizationID string, request types.UpdateOrganizationRequest) (*types.Organization, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsUpdatePermission); err != nil { + return nil, err + } + return u.orgService.UpdateOrganization(ctx, actor, organizationID, request) +} + +func (u *UseCases) DeleteOrganization(ctx context.Context, actor *models.Actor, organizationID string) error { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsDeletePermission); err != nil { + return err + } + return u.orgService.DeleteOrganization(ctx, actor, organizationID) +} + +func (u *UseCases) ExistsByID(ctx context.Context, organizationID string) (bool, error) { + return u.orgService.ExistsByID(ctx, organizationID) +} + +// ------------- OrganizationInvitationService ------------- + +func (u *UseCases) CreateOrganizationInvitation(ctx context.Context, actor *models.Actor, organizationID string, request types.CreateOrganizationInvitationRequest) (*types.OrganizationInvitation, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsCreatePermission); err != nil { + return nil, err + } + return u.invitationService.CreateOrganizationInvitation(ctx, actor, organizationID, request) +} + +func (u *UseCases) GetAllOrganizationInvitations(ctx context.Context, actor *models.Actor, organizationID string) ([]types.OrganizationInvitation, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsListPermission); err != nil { + return nil, err + } + return u.invitationService.GetAllOrganizationInvitations(ctx, actor, organizationID) +} + +func (u *UseCases) GetOrganizationInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsReadPermission); err != nil { + return nil, err + } + return u.invitationService.GetOrganizationInvitation(ctx, actor, organizationID, invitationID) +} + +func (u *UseCases) RevokeOrganizationInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsInvitationsRevokePermission); err != nil { + return nil, err + } + return u.invitationService.RevokeOrganizationInvitation(ctx, actor, organizationID, invitationID) +} + +func (u *UseCases) AcceptOrganizationInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { + return u.invitationService.AcceptOrganizationInvitation(ctx, actor, organizationID, invitationID) +} + +func (u *UseCases) RejectOrganizationInvitation(ctx context.Context, actor *models.Actor, organizationID string, invitationID string) (*types.OrganizationInvitation, error) { + return u.invitationService.RejectOrganizationInvitation(ctx, actor, organizationID, invitationID) +} + +// ------------- OrganizationMemberService ------------- + +func (u *UseCases) AddMember(ctx context.Context, actor *models.Actor, organizationID string, request types.AddOrganizationMemberRequest) (*types.OrganizationMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsMembersAddPermission); err != nil { + return nil, err + } + return u.memberService.AddMember(ctx, actor, organizationID, request) +} + +func (u *UseCases) GetAllMembers(ctx context.Context, actor *models.Actor, organizationID string, page int, limit int) ([]types.OrganizationMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsMembersListPermission); err != nil { + return nil, err + } + return u.memberService.GetAllMembers(ctx, actor, organizationID, page, limit) +} + +func (u *UseCases) GetMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) (*types.OrganizationMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsMembersReadPermission); err != nil { + return nil, err + } + return u.memberService.GetMember(ctx, actor, organizationID, memberID) +} + +func (u *UseCases) UpdateMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string, request types.UpdateOrganizationMemberRequest) (*types.OrganizationMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsMembersUpdatePermission); err != nil { + return nil, err + } + return u.memberService.UpdateMember(ctx, actor, organizationID, memberID, request) +} + +func (u *UseCases) RemoveMember(ctx context.Context, actor *models.Actor, organizationID string, memberID string) error { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsMembersRemovePermission); err != nil { + return err + } + return u.memberService.RemoveMember(ctx, actor, organizationID, memberID) +} + +// ------------- OrganizationTeamService ------------- + +func (u *UseCases) CreateTeam(ctx context.Context, actor *models.Actor, organizationID string, request types.CreateOrganizationTeamRequest) (*types.OrganizationTeam, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamsCreatePermission); err != nil { + return nil, err + } + return u.teamService.CreateTeam(ctx, actor, organizationID, request) +} + +func (u *UseCases) GetAllTeams(ctx context.Context, actor *models.Actor, organizationID string) ([]types.OrganizationTeam, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamsListPermission); err != nil { + return nil, err + } + return u.teamService.GetAllTeams(ctx, actor, organizationID) +} + +func (u *UseCases) GetTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) (*types.OrganizationTeam, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamsReadPermission); err != nil { + return nil, err + } + return u.teamService.GetTeam(ctx, actor, organizationID, teamID) +} + +func (u *UseCases) UpdateTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string, request types.UpdateOrganizationTeamRequest) (*types.OrganizationTeam, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamsUpdatePermission); err != nil { + return nil, err + } + return u.teamService.UpdateTeam(ctx, actor, organizationID, teamID, request) +} + +func (u *UseCases) DeleteTeam(ctx context.Context, actor *models.Actor, organizationID string, teamID string) error { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamsDeletePermission); err != nil { + return err + } + return u.teamService.DeleteTeam(ctx, actor, organizationID, teamID) +} + +// ------------- OrganizationTeamMemberService ------------- + +func (u *UseCases) AddTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, request types.AddOrganizationTeamMemberRequest) (*types.OrganizationTeamMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamMembersAddPermission); err != nil { + return nil, err + } + return u.teamMemberService.AddTeamMember(ctx, actor, organizationID, teamID, request) +} + +func (u *UseCases) GetAllTeamMembers(ctx context.Context, actor *models.Actor, organizationID string, teamID string, page int, limit int) ([]types.OrganizationTeamMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamMembersListPermission); err != nil { + return nil, err + } + return u.teamMemberService.GetAllTeamMembers(ctx, actor, organizationID, teamID, page, limit) +} + +func (u *UseCases) GetTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) (*types.OrganizationTeamMember, error) { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamMembersReadPermission); err != nil { + return nil, err + } + return u.teamMemberService.GetTeamMember(ctx, actor, organizationID, teamID, memberID) +} + +func (u *UseCases) RemoveTeamMember(ctx context.Context, actor *models.Actor, organizationID string, teamID string, memberID string) error { + if err := u.authorizer.AuthorizeOrganizationAccess(ctx, actor, organizationID, orgconstants.OrganizationsTeamMembersRemovePermission); err != nil { + return err + } + return u.teamMemberService.RemoveTeamMember(ctx, actor, organizationID, teamID, memberID) +}