feat(handlers): Implement Policy Service

This also includes adding new grant and type primitives, as well as
package domain names.
pull/4239/head
Hugo 2 years ago committed by Louis Ruch
parent 1c3b1b42f7
commit edbb33de5b

@ -315,6 +315,11 @@ var prefixToResourceType = map[string]ResourceInfo{
Type: resource.SessionRecording,
Subtype: UnknownSubtype,
},
StoragePolicyPrefix: {
Type: resource.Policy,
Subtype: UnknownSubtype,
},
}
var resourceTypeToPrefixes map[resource.Type][]string = func() map[resource.Type][]string {

@ -33,6 +33,7 @@ import (
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_sets"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/hosts"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/managed_groups"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/policies"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/scopes"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/session_recordings"
@ -222,6 +223,17 @@ func (c *Controller) registerGrpcServices(s *grpc.Server) error {
}
services.RegisterStorageBucketServiceServer(s, sbs)
}
if _, ok := currentServices[services.PolicyService_ServiceDesc.ServiceName]; !ok {
ps, err := policies.NewServiceFn(
c.baseContext,
c.IamRepoFn,
c.ControllerExtension,
)
if err != nil {
return fmt.Errorf("failed to create policy handler service: %w", err)
}
services.RegisterPolicyServiceServer(s, ps)
}
if _, ok := currentServices[services.SessionRecordingService_ServiceDesc.ServiceName]; !ok {
srs, err := session_recordings.NewServiceFn(
c.baseContext,
@ -403,6 +415,9 @@ func registerGrpcGatewayEndpoints(ctx context.Context, gwMux *runtime.ServeMux,
if err := services.RegisterSessionRecordingServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
return fmt.Errorf("failed to register session recording handler: %w", err)
}
if err := services.RegisterPolicyServiceHandlerFromEndpoint(ctx, gwMux, gatewayTarget, dialOptions); err != nil {
return fmt.Errorf("failed to register policy handler: %w", err)
}
return nil
}

@ -0,0 +1,75 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package policies
import (
"context"
"github.com/hashicorp/boundary/internal/daemon/controller/common"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
internalglobals "github.com/hashicorp/boundary/internal/globals"
"github.com/hashicorp/boundary/internal/types/action"
"github.com/hashicorp/boundary/internal/types/resource"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
var (
_ pbs.PolicyServiceServer = (*Service)(nil)
// idActions contains the set of actions that can be performed on individual
// resources.
idActions = action.NewActionSet(
action.NoOp,
action.Read,
action.Update,
action.Delete,
)
// CollectionActions contains the set of actions that can be performed on
// this collection.
CollectionActions = action.NewActionSet(
action.Create,
action.List,
)
)
// NewServiceFn returns a policy service which is not implemented in OSS
var NewServiceFn = func(ctx context.Context,
iamRepoFn common.IamRepoFactory,
controllerExt internalglobals.ControllerExtension,
) (pbs.PolicyServiceServer, error) {
return &Service{}, nil
}
func init() {
action.RegisterResource(resource.Policy, idActions, CollectionActions)
}
type Service struct {
pbs.UnimplementedPolicyServiceServer
}
// GetPolicy implements the interface pbs.PolicyServiceServer.
func (s *Service) GetPolicy(ctx context.Context, req *pbs.GetPolicyRequest) (*pbs.GetPolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Policies are an Enterprise-only feature")
}
// ListPolicies implements the interface pbs.PolicyServiceServer.
func (s *Service) ListPolicies(ctx context.Context, req *pbs.ListPoliciesRequest) (*pbs.ListPoliciesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Policies are an Enterprise-only feature")
}
// CreatePolicy implements the interface pbs.PolicyServiceServer.
func (s *Service) CreatePolicy(ctx context.Context, req *pbs.CreatePolicyRequest) (*pbs.CreatePolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Policies are an Enterprise-only feature")
}
// UpdatePolicy implements the interface pbs.PolicyServiceServer.
func (s *Service) UpdatePolicy(ctx context.Context, req *pbs.UpdatePolicyRequest) (*pbs.UpdatePolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Policies are an Enterprise-only feature")
}
func (s *Service) DeletePolicy(ctx context.Context, req *pbs.DeletePolicyRequest) (*pbs.DeletePolicyResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "Policies are an Enterprise-only feature")
}

@ -0,0 +1,62 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package policies
import (
"context"
"testing"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
func TestPolicyService(t *testing.T) {
t.Parallel()
ctx := context.Background()
assert, require := assert.New(t), require.New(t)
s := Service{}
gotCreate, err := s.CreatePolicy(ctx, &pbs.CreatePolicyRequest{})
require.Nil(gotCreate)
require.Error(err)
gotStatus, ok := status.FromError(err)
require.True(ok)
assert.Equal(gotStatus.Code(), codes.Unimplemented)
assert.Equal(gotStatus.Message(), "Policies are an Enterprise-only feature")
gotUpdate, err := s.UpdatePolicy(ctx, &pbs.UpdatePolicyRequest{})
require.Nil(gotUpdate)
require.Error(err)
gotStatus, ok = status.FromError(err)
require.True(ok)
assert.Equal(gotStatus.Code(), codes.Unimplemented)
assert.Equal(gotStatus.Message(), "Policies are an Enterprise-only feature")
gotGet, err := s.GetPolicy(ctx, &pbs.GetPolicyRequest{})
require.Nil(gotGet)
require.Error(err)
gotStatus, ok = status.FromError(err)
require.True(ok)
assert.Equal(gotStatus.Code(), codes.Unimplemented)
assert.Equal(gotStatus.Message(), "Policies are an Enterprise-only feature")
gotDelete, err := s.DeletePolicy(ctx, &pbs.DeletePolicyRequest{})
require.Nil(gotDelete)
require.Error(err)
gotStatus, ok = status.FromError(err)
require.True(ok)
assert.Equal(gotStatus.Code(), codes.Unimplemented)
assert.Equal(gotStatus.Message(), "Policies are an Enterprise-only feature")
gotList, err := s.ListPolicies(ctx, &pbs.ListPoliciesRequest{})
require.Nil(gotList)
require.Error(err)
gotStatus, ok = status.FromError(err)
require.True(ok)
assert.Equal(gotStatus.Code(), codes.Unimplemented)
assert.Equal(gotStatus.Message(), "Policies are an Enterprise-only feature")
}

@ -19,6 +19,7 @@ import (
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/credentialstores"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/groups"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_catalogs"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/policies"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/session_recordings"
"github.com/hashicorp/boundary/internal/daemon/controller/handlers/sessions"
@ -81,6 +82,7 @@ var (
resource.User: users.CollectionActions,
resource.Worker: workers.CollectionActions,
resource.SessionRecording: session_recordings.CollectionActions,
resource.Policy: policies.CollectionActions,
},
scope.Org.String(): {
@ -92,6 +94,7 @@ var (
resource.Scope: CollectionActions,
resource.User: users.CollectionActions,
resource.SessionRecording: session_recordings.CollectionActions,
resource.Policy: policies.CollectionActions,
},
scope.Project.String(): {

@ -93,6 +93,12 @@ var globalAuthorizedCollectionActions = map[string]*structpb.ListValue{
structpb.NewStringValue("list"),
},
},
"policies": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
"roles": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
@ -155,6 +161,12 @@ var orgAuthorizedCollectionActions = map[string]*structpb.ListValue{
structpb.NewStringValue("list"),
},
},
"policies": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
"roles": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),

@ -63,7 +63,7 @@ func Test_newRateLimiterConfig(t *testing.T) {
ratelimit.DefaultLimiterMaxQuotas(),
false,
&rateLimiterConfig{
maxSize: 296148,
maxSize: 308154,
configs: nil,
disabled: false,
limits: defaultLimits,

@ -3893,7 +3893,7 @@
]
}
},
"max_size": 296148,
"max_size": 308154,
"msg": "controller api rate limiter"
},
"op": "controller.(rateLimiterConfig).writeSysEvent",

@ -3893,7 +3893,7 @@
]
}
},
"max_size": 296148,
"max_size": 308154,
"msg": "controller api rate limiter"
},
"op": "controller.(rateLimiterConfig).writeSysEvent",

@ -928,7 +928,7 @@ func Test_AnonRestrictions(t *testing.T) {
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require, assert := require.New(t), assert.New(t)
for i := resource.Type(1); i <= resource.StorageBucket; i++ {
for i := resource.Type(1); i <= resource.Policy; i++ {
if i == resource.Controller || i == resource.Worker {
continue
}

@ -119,7 +119,7 @@ func Test_ValidateType(t *testing.T) {
t.Parallel()
ctx := context.Background()
var g Grant
for i := resource.Unknown; i <= resource.StorageBucket; i++ {
for i := resource.Unknown; i <= resource.Policy; i++ {
g.typ = i
if i == resource.Controller {
assert.Error(t, g.validateType(ctx))

@ -5,6 +5,9 @@ package policy
import "github.com/hashicorp/boundary/internal/boundary"
// Domain defines the domain for this package.
const Domain = "policy"
// Policy contains the common methods across all the different types of policies.
type Policy interface {
boundary.Resource

@ -28,6 +28,7 @@ import (
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/host_sets"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/hosts"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/managed_groups"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/policies"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/roles"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/scopes"
_ "github.com/hashicorp/boundary/internal/daemon/controller/handlers/session_recordings"

@ -34,6 +34,7 @@ const (
CredentialLibrary
Credential
StorageBucket
Policy
// NOTE: When adding a new type, be sure to update:
//
// * The Grant.validateType function and test
@ -72,6 +73,7 @@ func (r Type) String() string {
"credential-library",
"credential",
"storage-bucket",
"policy",
}[r]
}
@ -79,6 +81,8 @@ func (r Type) PluralString() string {
switch r {
case CredentialLibrary:
return "credential-libraries"
case Policy:
return "policies"
default:
return r.String() + "s"
}
@ -88,6 +92,8 @@ func FromPlural(s string) (Type, bool) {
switch s {
case "credential-libraries":
return CredentialLibrary, true
case "policies":
return Policy, true
default:
t, ok := Map[strings.TrimSuffix(s, "s")]
return t, ok
@ -117,6 +123,7 @@ var Map = map[string]Type{
CredentialLibrary.String(): CredentialLibrary,
Credential.String(): Credential,
StorageBucket.String(): StorageBucket,
Policy.String(): Policy,
}
// Parent returns the parent type for a given type; if there is no parent, it
@ -159,6 +166,7 @@ func TopLevelType(typ Type) bool {
Target,
User,
StorageBucket,
Policy,
Worker:
return true
}

@ -122,6 +122,11 @@ func Test_Resource(t *testing.T) {
want: Credential,
parent: CredentialStore,
},
{
typeString: "policy",
want: Policy,
topLevelType: true,
},
}
for _, tt := range tests {
t.Run(tt.typeString, func(t *testing.T) {

Loading…
Cancel
Save