diff --git a/internal/auth/auth.go b/internal/auth/auth.go index 899a61fd54..63855bf94d 100644 --- a/internal/auth/auth.go +++ b/internal/auth/auth.go @@ -43,11 +43,12 @@ type RequestInfo struct { Token string TokenFormat TokenFormat + // This is used for operations on the scopes collection + scopeIdOverride string + // The following are useful for tests - DisableAuthzFailures bool - DisableAuthEntirely bool - scopeIdOverride string - parentScopeIdOverride string + DisableAuthzFailures bool + DisableAuthEntirely bool } type VerifyResults struct { @@ -88,7 +89,7 @@ func NewVerifierContext(ctx context.Context, // may come from the URL and may come from the token) and whether or not to // proceed, e.g. whether the authn/authz check resulted in failure. If an error // occurs it's logged to the system log. -func Verify(ctx context.Context) (ret VerifyResults) { +func Verify(ctx context.Context, opt ...Option) (ret VerifyResults) { v, ok := ctx.Value(verifierKey).(*verifier) if !ok { // We don't have a logger yet and this should never happen in any @@ -106,11 +107,12 @@ func Verify(ctx context.Context) (ret VerifyResults) { case strings.HasPrefix(ret.Scope.Id, scope.Project.Prefix()): ret.Scope.Type = scope.Project.String() } - ret.Scope.ParentScopeId = v.requestInfo.parentScopeIdOverride ret.Valid = true return } v.ctx = ctx + opts := getOpts(opt...) + v.requestInfo.scopeIdOverride = opts.withScopeId if err := v.parseAuthParams(); err != nil { v.logger.Trace("error reading auth parameters from URL", "url", v.requestInfo.Path, "method", v.requestInfo.Method, "error", err) return @@ -204,25 +206,50 @@ func (v *verifier) parseAuthParams() error { } // Get scope information and handle it in a special case; that is, for - // operating on scopes, we use the token scope, not the path scope + // operating on scopes, scope from the request ID, not the path scope switch splitLen { case 1: // We've already validated that this is "scopes" if v.act == action.Read { v.act = action.List } - // We're operating on the scopes collection. Set the scope ID to - // "token", which will be a signal to read it from the token. - v.res.ScopeId = "token" - // TODO: check for an override + if v.requestInfo.scopeIdOverride == "" { + return errors.New("parse auth params: missing scope ID information for scopes collection operation") + } + v.res.ScopeId = v.requestInfo.scopeIdOverride return nil case 2: - // The next segment should be the scope ID, and we still need to look up - // the actual request scopefrom the token like in the case above. - v.res.ScopeId = "token" - // TODO: check for an override - v.res.Id = splitPath[1] + id := splitPath[1] + // The next segment should be the scope ID, but it takes place not in + // its own scope but in the parent scope. Rather than require the user + // to provide it, look up the parent. + switch { + case id == "global", strings.HasPrefix(id, scope.Org.Prefix()): + // Org scope parent is always global. Set scope for global + // operations to global as well (it's basically acting as its own + // parent scope). We want this so that users can e.g. modify the + // name or description of the global scope if they have permissions + // in the scope. + v.res.ScopeId = "global" + + default: + // Project case + iamRepo, err := v.iamRepoFn() + if err != nil { + return fmt.Errorf("perform auth check: failed to get iam repo: %w", err) + } + + scp, err := iamRepo.LookupScope(v.ctx, id) + if err != nil { + return fmt.Errorf("perform auth check: failed to lookup scope: %w", err) + } + if scp == nil { + return fmt.Errorf("perform auth check: non-existent scope %q", id) + } + v.res.ScopeId = scp.GetParentId() + } + v.res.Id = id return nil case 3: @@ -353,16 +380,6 @@ func (v verifier) performAuthCheck() (aclResults *perms.ACLResults, userId strin } if at != nil { userId = at.GetIamUserId() - if v.res.ScopeId == "token" { - v.res.ScopeId = at.ScopeId - } - } - - // If no token was found, put at global scope. In the future we can allow an - // override as part of the request parameter. Then check that we actually - // have a valid scope. - if v.res.ScopeId == "token" { - v.res.ScopeId = "global" } // Fetch and parse grants for this user ID (which may include grants for @@ -418,7 +435,7 @@ func (v verifier) performAuthCheck() (aclResults *perms.ACLResults, userId strin return } -// getTokenFromRequest pulls the token from either the Authorization header or +// GetTokenFromRequest pulls the token from either the Authorization header or // split cookies and parses it. If it cannot be parsed successfully, the issue // is logged and we return blank, so logic will continue as the anonymous user. // The public ID and token are returned along with the token format. diff --git a/internal/auth/auth_test.go b/internal/auth/auth_test.go index 0f5d6d5ce5..a90bea6ac8 100644 --- a/internal/auth/auth_test.go +++ b/internal/auth/auth_test.go @@ -18,6 +18,15 @@ import ( ) func TestHandler_AuthDecoration(t *testing.T) { + conn, _ := db.TestSetup(t, "postgres") + rw := db.New(conn) + wrapper := db.TestWrapper(t) + iamRepo, err := iam.NewRepository(rw, rw, wrapper) + require.NoError(t, err) + iamRepoFn := func() (*iam.Repository, error) { + return iamRepo, nil + } + org, proj := iam.TestScopes(t, conn) cases := []struct { name string path string @@ -48,14 +57,23 @@ func TestHandler_AuthDecoration(t *testing.T) { id: "am_1234", }, { - name: "global scope, delete, token scope", + name: "global scope, delete org", path: "/v1/scopes/o_1234", method: "DELETE", action: action.Delete, - scope: "token", + scope: "global", resource: resource.Scope, id: "o_1234", }, + { + name: "org scope, delete project", + path: fmt.Sprintf("/v1/scopes/%s", proj.GetPublicId()), + method: "DELETE", + action: action.Delete, + scope: org.GetPublicId(), + resource: resource.Scope, + id: proj.GetPublicId(), + }, { name: "empty segments", path: "/v1/scopes/o_abc1234/auth-methods//am_1234", @@ -114,6 +132,15 @@ func TestHandler_AuthDecoration(t *testing.T) { path: "/v1/scopes/o_abc/:auth:enticate", wantErrContains: "unexpected number of colons", }, + { + name: "root, action on global", + path: "/v1/scopes/global", + method: "GET", + action: action.Read, + scope: "global", + resource: resource.Scope, + id: "global", + }, { name: "org scope, valid", path: "/v1/scopes/o_abc123/auth-methods", @@ -144,7 +171,7 @@ func TestHandler_AuthDecoration(t *testing.T) { path: "/v1/scopes/o_1234:set-principals", method: "POST", action: action.SetPrincipals, - scope: "token", + scope: "global", resource: resource.Scope, id: "o_1234", }, @@ -222,6 +249,7 @@ func TestHandler_AuthDecoration(t *testing.T) { Path: req.URL.Path, Method: tc.method, }, + iamRepoFn: iamRepoFn, } err = v.parseAuthParams() diff --git a/internal/auth/option.go b/internal/auth/option.go new file mode 100644 index 0000000000..7ba2bb5097 --- /dev/null +++ b/internal/auth/option.go @@ -0,0 +1,29 @@ +package auth + +func getOpts(opt ...Option) options { + opts := getDefaultOptions() + for _, o := range opt { + o(&opts) + } + return opts +} + +// Option - how Options are passed as arguments +type Option func(*options) + +// options = how options are represented +type options struct { + withScopeId string +} + +func getDefaultOptions() options { + return options{ + withScopeId: "", + } +} + +func WithScopeId(id string) Option { + return func(o *options) { + o.withScopeId = id + } +} diff --git a/internal/auth/testing.go b/internal/auth/testing.go index 8bbc006bfd..ed31702f4f 100644 --- a/internal/auth/testing.go +++ b/internal/auth/testing.go @@ -3,46 +3,9 @@ package auth import "context" // DisabledAuthTestContext is meant for testing, and uses a context that has auth checking entirely disabled -func DisabledAuthTestContext(opt ...TestOption) context.Context { +func DisabledAuthTestContext(opt ...Option) context.Context { reqInfo := RequestInfo{DisableAuthEntirely: true} opts := getOpts(opt...) - reqInfo.scopeIdOverride = opts.withTestScopeId - reqInfo.parentScopeIdOverride = opts.withTestParentScopeId + reqInfo.scopeIdOverride = opts.withScopeId return NewVerifierContext(context.Background(), nil, nil, nil, reqInfo) } - -func getOpts(opt ...TestOption) options { - opts := getDefaultOptions() - for _, o := range opt { - o(&opts) - } - return opts -} - -// Option - how Options are passed as arguments -type TestOption func(*options) - -// options = how options are represented -type options struct { - withTestScopeId string - withTestParentScopeId string -} - -func getDefaultOptions() options { - return options{ - withTestScopeId: "", - withTestParentScopeId: "", - } -} - -func WithTestScopeId(id string) TestOption { - return func(o *options) { - o.withTestScopeId = id - } -} - -func withTestParentScopeId(id string) TestOption { - return func(o *options) { - o.withTestParentScopeId = id - } -} diff --git a/internal/gen/controller.swagger.json b/internal/gen/controller.swagger.json index 498c93eb94..aac2f10f68 100644 --- a/internal/gen/controller.swagger.json +++ b/internal/gen/controller.swagger.json @@ -29,6 +29,12 @@ } }, "parameters": [ + { + "name": "scope_id", + "in": "query", + "required": false, + "type": "string" + }, { "name": "view", "in": "query", diff --git a/internal/gen/controller/api/services/scope_service.pb.go b/internal/gen/controller/api/services/scope_service.pb.go index 3849bd8ee1..3bc4520cbc 100644 --- a/internal/gen/controller/api/services/scope_service.pb.go +++ b/internal/gen/controller/api/services/scope_service.pb.go @@ -140,7 +140,8 @@ type ListScopesRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - View string `protobuf:"bytes,1,opt,name=view,proto3" json:"view,omitempty"` + ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty"` + View string `protobuf:"bytes,2,opt,name=view,proto3" json:"view,omitempty"` } func (x *ListScopesRequest) Reset() { @@ -175,6 +176,13 @@ func (*ListScopesRequest) Descriptor() ([]byte, []int) { return file_controller_api_services_v1_scope_service_proto_rawDescGZIP(), []int{2} } +func (x *ListScopesRequest) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + func (x *ListScopesRequest) GetView() string { if x != nil { return x.View @@ -234,7 +242,8 @@ type CreateScopeRequest struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Item *scopes.Scope `protobuf:"bytes,1,opt,name=item,proto3" json:"item,omitempty"` + ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty"` + Item *scopes.Scope `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"` } func (x *CreateScopeRequest) Reset() { @@ -269,6 +278,13 @@ func (*CreateScopeRequest) Descriptor() ([]byte, []int) { return file_controller_api_services_v1_scope_service_proto_rawDescGZIP(), []int{4} } +func (x *CreateScopeRequest) GetScopeId() string { + if x != nil { + return x.ScopeId + } + return "" +} + func (x *CreateScopeRequest) GetItem() *scopes.Scope { if x != nil { return x.Item @@ -561,108 +577,111 @@ var file_controller_api_services_v1_scope_service_proto_rawDesc = []byte{ 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x22, 0x27, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, - 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x69, 0x65, - 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x22, 0x55, 0x0a, - 0x12, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x3f, 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, - 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x05, 0x69, - 0x74, 0x65, 0x6d, 0x73, 0x22, 0x53, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, - 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, - 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, - 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, - 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x66, 0x0a, 0x13, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, - 0x72, 0x69, 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, - 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, - 0x6d, 0x22, 0xa0, 0x01, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, - 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x69, 0x74, 0x65, 0x6d, 0x22, 0x42, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, + 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, + 0x70, 0x65, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x76, 0x69, 0x65, 0x77, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x76, 0x69, 0x65, 0x77, 0x22, 0x55, 0x0a, 0x12, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3f, + 0x0a, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, + 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x05, 0x69, 0x74, 0x65, 0x6d, 0x73, 0x22, + 0x6e, 0x0a, 0x12, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x49, 0x64, + 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, + 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, + 0x66, 0x0a, 0x13, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, - 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3b, 0x0a, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, - 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x54, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, - 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x69, - 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, - 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0x24, 0x0a, 0x12, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, - 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, - 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, - 0x64, 0x32, 0xe9, 0x06, 0x0a, 0x0c, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x12, 0x9c, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, - 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, - 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, - 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x6f, - 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x17, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x7b, - 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x15, 0x12, 0x13, 0x47, 0x65, - 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x53, 0x63, 0x6f, 0x70, - 0x65, 0x12, 0xc5, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, - 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, - 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, - 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x22, 0xa0, 0x01, 0x0a, 0x12, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x3d, + 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x63, + 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2e, 0x76, + 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x12, 0x3b, 0x0a, + 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4d, 0x61, 0x73, 0x6b, 0x52, 0x0a, + 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x61, 0x73, 0x6b, 0x22, 0x54, 0x0a, 0x13, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, + 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x63, 0x6f, 0x70, 0x65, + 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x22, 0x24, 0x0a, 0x12, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, 0x2f, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, + 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x64, 0x32, 0xe9, 0x06, 0x0a, 0x0c, 0x53, 0x63, 0x6f, 0x70, + 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x9c, 0x01, 0x0a, 0x08, 0x47, 0x65, 0x74, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2b, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, + 0x47, 0x65, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17, 0x12, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, + 0x41, 0x15, 0x12, 0x13, 0x47, 0x65, 0x74, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, + 0x65, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0xc5, 0x01, 0x0a, 0x0a, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x12, 0x2d, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, + 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, + 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, + 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, + 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x92, 0x41, 0x43, 0x12, 0x41, 0x4c, 0x69, + 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, 0x6c, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x77, + 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, + 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x6d, 0x61, 0x6b, + 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0xa9, 0x01, 0x0a, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, - 0x58, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, - 0x70, 0x65, 0x73, 0x92, 0x41, 0x43, 0x12, 0x41, 0x4c, 0x69, 0x73, 0x74, 0x73, 0x20, 0x61, 0x6c, - 0x6c, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x20, - 0x74, 0x68, 0x65, 0x20, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, - 0x20, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x20, 0x6d, 0x61, 0x6b, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, - 0x65, 0x20, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0xa9, 0x01, 0x0a, 0x0b, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, - 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, - 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x18, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x04, - 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x18, 0x12, 0x16, 0x43, - 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, - 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0xa7, 0x01, 0x0a, 0x0b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x72, 0x65, + 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, + 0x6f, 0x70, 0x65, 0x73, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, + 0x92, 0x41, 0x18, 0x12, 0x16, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x73, + 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0xa7, 0x01, 0x0a, 0x0b, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, + 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x1d, 0x32, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, + 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, + 0x6d, 0x92, 0x41, 0x11, 0x12, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, + 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x9b, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, - 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x37, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1d, 0x32, 0x0f, - 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x3a, - 0x04, 0x69, 0x74, 0x65, 0x6d, 0x62, 0x04, 0x69, 0x74, 0x65, 0x6d, 0x92, 0x41, 0x11, 0x12, 0x0f, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, - 0x9b, 0x01, 0x0a, 0x0b, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, - 0x2e, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x2f, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2e, 0x61, 0x70, 0x69, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x2a, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, - 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, 0x41, 0x11, 0x12, 0x0f, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x42, 0x4f, 0x5a, - 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, - 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, - 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x76, 0x31, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x2a, 0x0f, + 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x73, 0x2f, 0x7b, 0x69, 0x64, 0x7d, 0x92, + 0x41, 0x11, 0x12, 0x0f, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x73, 0x20, 0x61, 0x20, 0x53, 0x63, + 0x6f, 0x70, 0x65, 0x42, 0x4f, 0x5a, 0x4d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x77, 0x61, 0x74, 0x63, + 0x68, 0x74, 0x6f, 0x77, 0x65, 0x72, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, + 0x67, 0x65, 0x6e, 0x2f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x6c, 0x65, 0x72, 0x2f, 0x61, + 0x70, 0x69, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x3b, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/gen/controller/api/services/scope_service.pb.gw.go b/internal/gen/controller/api/services/scope_service.pb.gw.go index c3cea29efa..3ae78446a7 100644 --- a/internal/gen/controller/api/services/scope_service.pb.gw.go +++ b/internal/gen/controller/api/services/scope_service.pb.gw.go @@ -139,6 +139,10 @@ func local_request_ScopeService_ListScopes_0(ctx context.Context, marshaler runt } +var ( + filter_ScopeService_CreateScope_0 = &utilities.DoubleArray{Encoding: map[string]int{"item": 0}, Base: []int{1, 1, 0}, Check: []int{0, 1, 2}} +) + func request_ScopeService_CreateScope_0(ctx context.Context, marshaler runtime.Marshaler, client ScopeServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq CreateScopeRequest var metadata runtime.ServerMetadata @@ -151,6 +155,13 @@ func request_ScopeService_CreateScope_0(ctx context.Context, marshaler runtime.M return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ScopeService_CreateScope_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := client.CreateScope(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err @@ -168,6 +179,13 @@ func local_request_ScopeService_CreateScope_0(ctx context.Context, marshaler run return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_ScopeService_CreateScope_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + msg, err := server.CreateScope(ctx, &protoReq) return msg, metadata, err diff --git a/internal/proto/local/controller/api/services/v1/scope_service.proto b/internal/proto/local/controller/api/services/v1/scope_service.proto index 5adffcee3d..295952212b 100644 --- a/internal/proto/local/controller/api/services/v1/scope_service.proto +++ b/internal/proto/local/controller/api/services/v1/scope_service.proto @@ -96,7 +96,8 @@ message GetScopeResponse { } message ListScopesRequest { - string view = 1; + string scope_id = 1; + string view = 2; } message ListScopesResponse { @@ -104,7 +105,8 @@ message ListScopesResponse { } message CreateScopeRequest { - resources.scopes.v1.Scope item = 1; + string scope_id = 1; + resources.scopes.v1.Scope item = 2; } message CreateScopeResponse { diff --git a/internal/servers/controller/cors_test.go b/internal/servers/controller/cors_test.go index d6464328e8..12f8fc327f 100644 --- a/internal/servers/controller/cors_test.go +++ b/internal/servers/controller/cors_test.go @@ -3,11 +3,14 @@ package controller import ( "fmt" "net/http" + "net/url" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/hashicorp/go-retryablehttp" + "github.com/hashicorp/watchtower/api/scopes" "github.com/hashicorp/watchtower/internal/cmd/config" ) @@ -73,13 +76,14 @@ func TestHandler_CORS(t *testing.T) { defer tc.Shutdown() cases := []struct { - name string - method string - origin string - code int - acrmHeader string - allowedHeader string - listenerNum int + name string + method string + origin string + code int + acrmHeader string + allowedHeader string + listenerNum int + provideScopeId bool }{ { name: "disabled no origin", @@ -140,6 +144,21 @@ func TestHandler_CORS(t *testing.T) { code: http.StatusOK, listenerNum: 4, }, + { + name: "enabled with wildcard origins and no origin defined, scope id checking", + method: http.MethodGet, + code: http.StatusOK, + listenerNum: 4, + provideScopeId: true, + }, + { + name: "enabled with wildcard origins and origin defined, scope id checking", + method: http.MethodPost, + origin: "flubber.com", + code: http.StatusOK, + listenerNum: 4, + provideScopeId: true, + }, { name: "wildcard origins with method list and good method", method: http.MethodOptions, @@ -169,8 +188,22 @@ func TestHandler_CORS(t *testing.T) { client.SetToken("fo_o_bar") // Create the request - req, err := client.NewRequest(tc.Context(), c.method, "scopes", nil) + var req *retryablehttp.Request + + // This tests out scope_id handling from body or query + var body interface{} + scopeId := "global" + if c.provideScopeId { + scopeId = "o_1234567890" + if c.method == http.MethodPost { + body = &scopes.Scope{} + } + } + req, err = client.NewRequest(tc.Context(), c.method, "scopes", body) require.NoError(t, err) + q := url.Values{} + q.Add("scope_id", scopeId) + req.URL.RawQuery = q.Encode() // Append headers if c.origin != "" { diff --git a/internal/servers/controller/handler.go b/internal/servers/controller/handler.go index af92163ba7..5049a8238c 100644 --- a/internal/servers/controller/handler.go +++ b/internal/servers/controller/handler.go @@ -125,7 +125,7 @@ func wrapHandlerWithCommonFuncs(h http.Handler, c *Controller, props HandlerProp return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if logUrls { - c.logger.Trace("request received", "url", r.URL.String()) + c.logger.Trace("request received", "url", r.URL.RequestURI()) } // Set the Cache-Control header for all responses returned diff --git a/internal/servers/controller/handlers/authenticate/authenticate_service_test.go b/internal/servers/controller/handlers/authenticate/authenticate_service_test.go index 3899b478fa..d11c263c34 100644 --- a/internal/servers/controller/handlers/authenticate/authenticate_service_test.go +++ b/internal/servers/controller/handlers/authenticate/authenticate_service_test.go @@ -65,7 +65,6 @@ func TestAuthenticate(t *testing.T) { { name: "basic", request: &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), AuthMethodId: amId, TokenType: "token", Credentials: func() *structpb.Struct { @@ -83,7 +82,6 @@ func TestAuthenticate(t *testing.T) { { name: "no-token-type", request: &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), AuthMethodId: amId, Credentials: func() *structpb.Struct { creds := map[string]*structpb.Value{ @@ -100,7 +98,6 @@ func TestAuthenticate(t *testing.T) { { name: "bad-token-type", request: &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), AuthMethodId: amId, TokenType: "email", Credentials: func() *structpb.Struct { @@ -116,7 +113,6 @@ func TestAuthenticate(t *testing.T) { { name: "no-authmethod", request: &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), Credentials: func() *structpb.Struct { creds := map[string]*structpb.Value{ "name": {Kind: &structpb.Value_StringValue{StringValue: "admin"}}, @@ -130,7 +126,6 @@ func TestAuthenticate(t *testing.T) { { name: "wrong-username-password", request: &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), AuthMethodId: amId, TokenType: "token", Credentials: func() *structpb.Struct { @@ -214,7 +209,6 @@ func TestAuthenticate_AuthAccountConnectedToIamUser(t *testing.T) { s, err := NewService(iamRepoFn, authTokenRepoFn) require.NoError(err) resp, err := s.Authenticate(context.Background(), &pbs.AuthenticateRequest{ - ScopeId: o.GetPublicId(), AuthMethodId: amId, Credentials: func() *structpb.Struct { creds := map[string]*structpb.Value{ diff --git a/internal/servers/controller/handlers/groups/group_service_test.go b/internal/servers/controller/handlers/groups/group_service_test.go index ca3f4be585..693b522139 100644 --- a/internal/servers/controller/handlers/groups/group_service_test.go +++ b/internal/servers/controller/handlers/groups/group_service_test.go @@ -136,7 +136,7 @@ func TestGet(t *testing.T) { s, err := groups.NewService(repo) require.NoError(err, "Couldn't create new group service.") - got, gErr := s.GetGroup(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.GetGroup(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "GetGroup(%+v) got error %v, wanted %v", req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "GetGroup(%q) got response\n%q, wanted\n%q", req, got, tc.res) }) @@ -208,7 +208,7 @@ func TestList(t *testing.T) { s, err := groups.NewService(repoFn) require.NoError(err, "Couldn't create new group service.") - got, gErr := s.ListGroups(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), &pbs.ListGroupsRequest{}) + got, gErr := s.ListGroups(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), &pbs.ListGroupsRequest{}) assert.Equal(tc.errCode, status.Code(gErr), "ListGroups(%q) got error %v, wanted %v", tc.scopeId, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "ListGroups(%q) got response %q, wanted %q", tc.scopeId, got, tc.res) }) @@ -308,7 +308,7 @@ func TestDelete(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - got, gErr := s.DeleteGroup(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.DeleteGroup(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "DeleteGroup(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.EqualValuesf(tc.res, got, "DeleteGroup(%+v) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -326,7 +326,7 @@ func TestDelete_twice(t *testing.T) { req := &pbs.DeleteGroupRequest{ Id: og.GetPublicId(), } - ctx := auth.DisabledAuthTestContext(auth.WithTestScopeId(scopeId)) + ctx := auth.DisabledAuthTestContext(auth.WithScopeId(scopeId)) got, gErr := s.DeleteGroup(ctx, req) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -338,7 +338,7 @@ func TestDelete_twice(t *testing.T) { projReq := &pbs.DeleteGroupRequest{ Id: pg.GetPublicId(), } - ctx = auth.DisabledAuthTestContext(auth.WithTestScopeId(scopeId)) + ctx = auth.DisabledAuthTestContext(auth.WithScopeId(scopeId)) got, gErr = s.DeleteGroup(ctx, projReq) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -431,7 +431,7 @@ func TestCreate(t *testing.T) { s, err := groups.NewService(repo) require.NoError(err, "Error when getting new group service.") - got, gErr := s.CreateGroup(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.CreateGroup(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "CreateGroup(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { assert.True(strings.HasPrefix(got.GetUri(), tc.res.Uri), got.GetUri()) @@ -742,7 +742,7 @@ func TestUpdate(t *testing.T) { req := proto.Clone(toMerge).(*pbs.UpdateGroupRequest) proto.Merge(req, tc.req) - got, gErr := tested.UpdateGroup(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := tested.UpdateGroup(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "UpdateGroup(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { diff --git a/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go b/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go index 237600c265..265e72d9b3 100644 --- a/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go +++ b/internal/servers/controller/handlers/host_catalogs/host_catalog_service_test.go @@ -105,7 +105,7 @@ func TestGet(t *testing.T) { s, err := host_catalogs.NewService(repo) require.NoError(t, err, "Couldn't create a new host catalog service.") - got, gErr := s.GetHostCatalog(auth.DisabledAuthTestContext(auth.WithTestScopeId(proj.GetPublicId())), req) + got, gErr := s.GetHostCatalog(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req) assert.Equal(tc.errCode, status.Code(gErr), "GetHostCatalog(%+v) got error %v, wanted %v", req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "GetHostCatalog(%q) got response %q, wanted %q", req, got, tc.res) }) @@ -184,7 +184,7 @@ func TestDelete(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - got, gErr := s.DeleteHostCatalog(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.DeleteHostCatalog(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "DeleteHostCatalog(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.EqualValuesf(tc.res, got, "DeleteHostCatalog(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -201,7 +201,7 @@ func TestDelete_twice(t *testing.T) { req := &pbs.DeleteHostCatalogRequest{ Id: hc.GetPublicId(), } - ctx := auth.DisabledAuthTestContext(auth.WithTestScopeId(proj.GetPublicId())) + ctx := auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())) got, gErr := s.DeleteHostCatalog(ctx, req) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -293,7 +293,7 @@ func TestCreate(t *testing.T) { s, err := host_catalogs.NewService(repo) require.NoError(err, "Failed to create a new host catalog service.") - got, gErr := s.CreateHostCatalog(auth.DisabledAuthTestContext(auth.WithTestScopeId(proj.GetPublicId())), req) + got, gErr := s.CreateHostCatalog(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req) assert.Equal(tc.errCode, status.Code(gErr), "CreateHostCatalog(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { assert.True(strings.HasPrefix(got.GetUri(), tc.res.GetUri())) @@ -588,7 +588,7 @@ func TestUpdate(t *testing.T) { req := proto.Clone(toMerge).(*pbs.UpdateHostCatalogRequest) proto.Merge(req, tc.req) - got, gErr := tested.UpdateHostCatalog(auth.DisabledAuthTestContext(auth.WithTestScopeId(proj.GetPublicId())), req) + got, gErr := tested.UpdateHostCatalog(auth.DisabledAuthTestContext(auth.WithScopeId(proj.GetPublicId())), req) assert.Equal(tc.errCode, status.Code(gErr), "UpdateHostCatalog(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { diff --git a/internal/servers/controller/handlers/roles/role_service_test.go b/internal/servers/controller/handlers/roles/role_service_test.go index 9cc5016e7c..8dea4de8fe 100644 --- a/internal/servers/controller/handlers/roles/role_service_test.go +++ b/internal/servers/controller/handlers/roles/role_service_test.go @@ -166,7 +166,7 @@ func TestGet(t *testing.T) { s, err := roles.NewService(repo) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.GetRole(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.GetRole(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "GetRole(%+v) got error %v, wanted %v", req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "GetRole(%q) got response\n%q, wanted\n%q", req, got, tc.res) }) @@ -247,7 +247,7 @@ func TestList(t *testing.T) { s, err := roles.NewService(repoFn) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.ListRoles(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.ListRoles(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "ListRoles(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "ListRoles(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -326,7 +326,7 @@ func TestDelete(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - got, gErr := s.DeleteRole(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.DeleteRole(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "DeleteRole(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.EqualValuesf(tc.res, got, "DeleteRole(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -343,7 +343,7 @@ func TestDelete_twice(t *testing.T) { req := &pbs.DeleteRoleRequest{ Id: or.GetPublicId(), } - ctx := auth.DisabledAuthTestContext(auth.WithTestScopeId(or.GetPublicId())) + ctx := auth.DisabledAuthTestContext(auth.WithScopeId(or.GetPublicId())) got, gErr := s.DeleteRole(ctx, req) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -354,7 +354,7 @@ func TestDelete_twice(t *testing.T) { projReq := &pbs.DeleteRoleRequest{ Id: pr.GetPublicId(), } - ctx = auth.DisabledAuthTestContext(auth.WithTestScopeId(pr.GetPublicId())) + ctx = auth.DisabledAuthTestContext(auth.WithScopeId(pr.GetPublicId())) got, gErr = s.DeleteRole(ctx, projReq) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -469,7 +469,7 @@ func TestCreate(t *testing.T) { s, err := roles.NewService(repo) require.NoError(err, "Error when getting new role service.") - got, gErr := s.CreateRole(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.CreateRole(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "CreateRole(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { assert.True(strings.HasPrefix(got.GetUri(), tc.res.Uri), "Expected %q to have the prefix %q", got.GetUri(), tc.res.GetUri()) @@ -877,7 +877,7 @@ func TestUpdate(t *testing.T) { req := proto.Clone(toMerge).(*pbs.UpdateRoleRequest) proto.Merge(req, tc.req) - got, gErr := tested.UpdateRole(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := tested.UpdateRole(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "UpdateRole(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { @@ -978,7 +978,7 @@ func TestAddPrincipal(t *testing.T) { PrincipalIds: append(tc.addUsers, tc.addGroups...), } - got, err := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(o.GetPublicId())), req) + got, err := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), req) if tc.wantErr { assert.Error(t, err) return @@ -1011,7 +1011,7 @@ func TestAddPrincipal(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "AddRolePrincipals(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } @@ -1098,7 +1098,7 @@ func TestSetPrincipal(t *testing.T) { PrincipalIds: append(tc.setUsers, tc.setGroups...), } - got, err := s.SetRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(o.GetPublicId())), req) + got, err := s.SetRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), req) if tc.wantErr { assert.Error(t, err) return @@ -1131,7 +1131,7 @@ func TestSetPrincipal(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.SetRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.SetRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "SetRolePrincipals(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } @@ -1236,7 +1236,7 @@ func TestRemovePrincipal(t *testing.T) { PrincipalIds: append(tc.removeUsers, tc.removeGroups...), } - got, err := s.RemoveRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(o.GetPublicId())), req) + got, err := s.RemoveRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(o.GetPublicId())), req) if tc.wantErr { assert.Error(t, err) return @@ -1269,7 +1269,7 @@ func TestRemovePrincipal(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.AddRolePrincipals(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "AddRolePrincipals(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } @@ -1348,7 +1348,7 @@ func TestAddGrants(t *testing.T) { scopeId = p.GetPublicId() } req.GrantStrings = append(req.GrantStrings, tc.add...) - got, err := s.AddRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(scopeId)), req) + got, err := s.AddRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(scopeId)), req) if tc.wantErr { assert.Error(err) return @@ -1379,7 +1379,7 @@ func TestAddGrants(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.AddRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.AddRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "AddRoleGrants(%+v) got error %#v, wanted %#v", tc.req, gErr, tc.errCode) }) } @@ -1446,7 +1446,7 @@ func TestSetGrants(t *testing.T) { scopeId = p.GetPublicId() } req.GrantStrings = append(req.GrantStrings, tc.set...) - got, err := s.SetRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(scopeId)), req) + got, err := s.SetRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(scopeId)), req) if tc.wantErr { assert.Error(err) return @@ -1479,7 +1479,7 @@ func TestSetGrants(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.SetRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.SetRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "SetRoleGrants(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } @@ -1545,7 +1545,7 @@ func TestRemoveGrants(t *testing.T) { scopeId = p.GetPublicId() } req.GrantStrings = append(req.GrantStrings, tc.remove...) - got, err := s.RemoveRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(scopeId)), req) + got, err := s.RemoveRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(scopeId)), req) if tc.wantErr { assert.Error(err) return @@ -1579,7 +1579,7 @@ func TestRemoveGrants(t *testing.T) { for _, tc := range failCases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - _, gErr := s.RemoveRoleGrants(auth.DisabledAuthTestContext(auth.WithTestScopeId(p.GetPublicId())), tc.req) + _, gErr := s.RemoveRoleGrants(auth.DisabledAuthTestContext(auth.WithScopeId(p.GetPublicId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "RemoveRoleGrants(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) }) } diff --git a/internal/servers/controller/handlers/scopes/scope_service.go b/internal/servers/controller/handlers/scopes/scope_service.go index b2688a1095..0e2223947d 100644 --- a/internal/servers/controller/handlers/scopes/scope_service.go +++ b/internal/servers/controller/handlers/scopes/scope_service.go @@ -50,10 +50,17 @@ var _ pbs.ScopeServiceServer = Service{} // ListScopes implements the interface pbs.ScopeServiceServer. func (s Service) ListScopes(ctx context.Context, req *pbs.ListScopesRequest) (*pbs.ListScopesResponse, error) { - authResults := auth.Verify(ctx) + if req.GetScopeId() == "" { + return nil, handlers.InvalidArgumentErrorf( + "Argument errors found in the request.", + map[string]string{"scope_id": "Missing value for scope_id"}, + ) + } + authResults := auth.Verify(ctx, auth.WithScopeId(req.GetScopeId())) if !authResults.Valid { return nil, handlers.ForbiddenError() } + if err := validateListRequest(req); err != nil { return nil, err } @@ -88,10 +95,17 @@ func (s Service) GetScope(ctx context.Context, req *pbs.GetScopeRequest) (*pbs.G // CreateScope implements the interface pbs.ScopeServiceServer. func (s Service) CreateScope(ctx context.Context, req *pbs.CreateScopeRequest) (*pbs.CreateScopeResponse, error) { - authResults := auth.Verify(ctx) + if req.GetScopeId() == "" { + return nil, handlers.InvalidArgumentErrorf( + "Argument errors found in the request.", + map[string]string{"scope_id": "Missing value for scope_id"}, + ) + } + authResults := auth.Verify(ctx, auth.WithScopeId(req.GetScopeId())) if !authResults.Valid { return nil, handlers.ForbiddenError() } + if err := validateCreateRequest(req); err != nil { return nil, err } diff --git a/internal/servers/controller/handlers/scopes/scope_service_test.go b/internal/servers/controller/handlers/scopes/scope_service_test.go index 881daaac5b..afceae88a8 100644 --- a/internal/servers/controller/handlers/scopes/scope_service_test.go +++ b/internal/servers/controller/handlers/scopes/scope_service_test.go @@ -136,7 +136,7 @@ func TestGet(t *testing.T) { s, err := scopes.NewService(repo) require.NoError(err, "Couldn't create new project service.") - got, gErr := s.GetScope(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.GetScope(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "GetProject(%+v) got error\n%v, wanted\n%v", req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "GetProject(%q) got response\n%q, wanted\n%q", req, got, tc.res) }) @@ -177,16 +177,16 @@ func TestList(t *testing.T) { errCode codes.Code }{ { - name: "List Only initial Orgs", + name: "List initial orgs", scopeId: scope.Global.String(), - req: &pbs.ListScopesRequest{}, + req: &pbs.ListScopesRequest{ScopeId: "global"}, res: &pbs.ListScopesResponse{Items: initialOrgs}, errCode: codes.OK, }, { name: "List No Projects", scopeId: oNoProjects.GetPublicId(), - req: &pbs.ListScopesRequest{}, + req: &pbs.ListScopesRequest{ScopeId: oNoProjects.GetPublicId()}, res: &pbs.ListScopesResponse{}, errCode: codes.OK, }, @@ -197,9 +197,9 @@ func TestList(t *testing.T) { s, err := scopes.NewService(repoFn) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.ListScopes(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.ListScopes(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "ListScopes(%+v) got error\n%v, wanted\n%v", tc.req, gErr, tc.errCode) - assert.True(proto.Equal(got, tc.res), "ListScopes(%q) got response\n%q, wanted\n%q", tc.req, got, tc.res) + assert.True(proto.Equal(got, tc.res), "ListScopes(%q) got response\n%q\nwanted\n%q", tc.req, got, tc.res) }) } @@ -244,14 +244,14 @@ func TestList(t *testing.T) { { name: "List Many Orgs", scopeId: scope.Global.String(), - req: &pbs.ListScopesRequest{}, + req: &pbs.ListScopesRequest{ScopeId: "global"}, res: &pbs.ListScopesResponse{Items: wantOrgs}, errCode: codes.OK, }, { name: "List Many Projects", scopeId: oWithProjects.GetPublicId(), - req: &pbs.ListScopesRequest{}, + req: &pbs.ListScopesRequest{ScopeId: oWithProjects.GetPublicId()}, res: &pbs.ListScopesResponse{Items: wantProjects}, errCode: codes.OK, }, @@ -262,7 +262,7 @@ func TestList(t *testing.T) { s, err := scopes.NewService(repoFn) require.NoError(err, "Couldn't create new role service.") - got, gErr := s.ListScopes(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.ListScopes(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "ListScopes(%+v) got error\n%v, wanted\n%v", tc.req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "ListScopes(%q) got response\n%q, wanted\n%q", tc.req, got, tc.res) }) @@ -349,7 +349,7 @@ func TestDelete(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - got, gErr := s.DeleteScope(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.DeleteScope(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "DeleteProject(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.EqualValuesf(tc.res, got, "DeleteProject(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -363,7 +363,7 @@ func TestDelete_twice(t *testing.T) { s, err := scopes.NewService(repo) require.NoError(err, "Error when getting new scopes service") - ctx := auth.DisabledAuthTestContext(auth.WithTestScopeId(org.GetPublicId())) + ctx := auth.DisabledAuthTestContext(auth.WithScopeId(org.GetPublicId())) req := &pbs.DeleteScopeRequest{ Id: proj.GetPublicId(), } @@ -374,7 +374,7 @@ func TestDelete_twice(t *testing.T) { assert.NoError(gErr, "Second attempt") assert.False(got.GetExisted(), "Expected existed to be false for the second delete.") - ctx = auth.DisabledAuthTestContext(auth.WithTestScopeId(scope.Global.String())) + ctx = auth.DisabledAuthTestContext(auth.WithScopeId(scope.Global.String())) req = &pbs.DeleteScopeRequest{ Id: org.GetPublicId(), } @@ -403,10 +403,13 @@ func TestCreate(t *testing.T) { { name: "Create a valid Project", scopeId: defaultOrg.GetPublicId(), - req: &pbs.CreateScopeRequest{Item: &pb.Scope{ - Name: &wrapperspb.StringValue{Value: "name"}, - Description: &wrapperspb.StringValue{Value: "desc"}, - }}, + req: &pbs.CreateScopeRequest{ + ScopeId: defaultOrg.GetPublicId(), + Item: &pb.Scope{ + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, res: &pbs.CreateScopeResponse{ Uri: "scopes/p_", Item: &pb.Scope{ @@ -420,10 +423,13 @@ func TestCreate(t *testing.T) { { name: "Create a valid Org", scopeId: scope.Global.String(), - req: &pbs.CreateScopeRequest{Item: &pb.Scope{ - Name: &wrapperspb.StringValue{Value: "name"}, - Description: &wrapperspb.StringValue{Value: "desc"}, - }}, + req: &pbs.CreateScopeRequest{ + ScopeId: scope.Global.String(), + Item: &pb.Scope{ + Name: &wrapperspb.StringValue{Value: "name"}, + Description: &wrapperspb.StringValue{Value: "desc"}, + }, + }, res: &pbs.CreateScopeResponse{ Uri: "scopes/o_", Item: &pb.Scope{ @@ -471,7 +477,7 @@ func TestCreate(t *testing.T) { s, err := scopes.NewService(repo) require.NoError(err, "Error when getting new project service.") - got, gErr := s.CreateScope(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := s.CreateScope(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "CreateProject(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { assert.True(strings.HasPrefix(got.GetUri(), tc.res.Uri)) @@ -805,7 +811,7 @@ func TestUpdate(t *testing.T) { } proto.Merge(req, tc.req) - got, gErr := tested.UpdateScope(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), req) + got, gErr := tested.UpdateScope(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), req) assert.Equal(tc.errCode, status.Code(gErr), "UpdateScope(%+v) got error\n%v, wanted\n%v", req, gErr, tc.errCode) if got != nil { diff --git a/internal/servers/controller/handlers/users/user_service_test.go b/internal/servers/controller/handlers/users/user_service_test.go index ff97b55373..616a528b95 100644 --- a/internal/servers/controller/handlers/users/user_service_test.go +++ b/internal/servers/controller/handlers/users/user_service_test.go @@ -95,7 +95,7 @@ func TestGet(t *testing.T) { s, err := users.NewService(repo) require.NoError(err, "Couldn't create new user service.") - got, gErr := s.GetUser(auth.DisabledAuthTestContext(auth.WithTestScopeId(u.GetScopeId())), req) + got, gErr := s.GetUser(auth.DisabledAuthTestContext(auth.WithScopeId(u.GetScopeId())), req) assert.Equal(tc.errCode, status.Code(gErr), "GetUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "GetUser(%q) got response %q, wanted %q", req, got, tc.res) }) @@ -157,7 +157,7 @@ func TestList(t *testing.T) { s, err := users.NewService(repoFn) require.NoError(err, "Couldn't create new user service.") - got, gErr := s.ListUsers(auth.DisabledAuthTestContext(auth.WithTestScopeId(tc.scopeId)), tc.req) + got, gErr := s.ListUsers(auth.DisabledAuthTestContext(auth.WithScopeId(tc.scopeId)), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "ListUsers(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.True(proto.Equal(got, tc.res), "ListUsers(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -209,7 +209,7 @@ func TestDelete(t *testing.T) { for _, tc := range cases { t.Run(tc.name, func(t *testing.T) { assert := assert.New(t) - got, gErr := s.DeleteUser(auth.DisabledAuthTestContext(auth.WithTestScopeId(u.GetScopeId())), tc.req) + got, gErr := s.DeleteUser(auth.DisabledAuthTestContext(auth.WithScopeId(u.GetScopeId())), tc.req) assert.Equal(tc.errCode, status.Code(gErr), "DeleteUser(%+v) got error %v, wanted %v", tc.req, gErr, tc.errCode) assert.EqualValuesf(tc.res, got, "DeleteUser(%q) got response %q, wanted %q", tc.req, got, tc.res) }) @@ -226,7 +226,7 @@ func TestDelete_twice(t *testing.T) { req := &pbs.DeleteUserRequest{ Id: u.GetPublicId(), } - ctx := auth.DisabledAuthTestContext(auth.WithTestScopeId(u.GetScopeId())) + ctx := auth.DisabledAuthTestContext(auth.WithScopeId(u.GetScopeId())) got, gErr := s.DeleteUser(ctx, req) assert.NoError(gErr, "First attempt") assert.True(got.GetExisted(), "Expected existed to be true for the first delete.") @@ -298,7 +298,7 @@ func TestCreate(t *testing.T) { s, err := users.NewService(repo) require.NoError(err, "Error when getting new user service.") - got, gErr := s.CreateUser(auth.DisabledAuthTestContext(auth.WithTestScopeId(defaultUser.GetScopeId())), req) + got, gErr := s.CreateUser(auth.DisabledAuthTestContext(auth.WithScopeId(defaultUser.GetScopeId())), req) assert.Equal(tc.errCode, status.Code(gErr), "CreateUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil { assert.True(strings.HasPrefix(got.GetUri(), tc.res.Uri)) @@ -551,7 +551,7 @@ func TestUpdate(t *testing.T) { req := proto.Clone(toMerge).(*pbs.UpdateUserRequest) proto.Merge(req, tc.req) - got, gErr := tested.UpdateUser(auth.DisabledAuthTestContext(auth.WithTestScopeId(u.GetScopeId())), req) + got, gErr := tested.UpdateUser(auth.DisabledAuthTestContext(auth.WithScopeId(u.GetScopeId())), req) assert.Equal(tc.errCode, status.Code(gErr), "UpdateUser(%+v) got error %v, wanted %v", req, gErr, tc.errCode) if got != nil {