feat(users): Classify resources for audit events

This commit is contained in:
Timothy Messier authored and Johan Brandhorst-Satzkorn committed 2022-04-20 13:32:32 -04:00
1 parent 006fa3a85a
commit 2ade7f34a8
6 files changed
+183 -62

No files matched your search

+2
View File
@@ -179,6 +179,8 @@ protobuild:
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/role_service.pb.go
@protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/sessions/session.pb.go
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/session_service.pb.go
@protoc-go-inject-tag -input=./sdk/pbs/controller/api/resources/users/user.pb.go
@protoc-go-inject-tag -input=./internal/gen/controller/api/services/user_service.pb.go
# these protos, services and openapi artifacts are purely for testing purposes
@protoc-go-inject-tag -input=./internal/gen/testing/event/event.pb.go
@@ -29,7 +29,7 @@ type GetUserRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *GetUserRequest) Reset() {
@@ -123,9 +123,9 @@ type ListUsersRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty"`
Recursive bool `protobuf:"varint,20,opt,name=recursive,proto3" json:"recursive,omitempty"`
Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty"`
ScopeId string `protobuf:"bytes,1,opt,name=scope_id,json=scopeId,proto3" json:"scope_id,omitempty" class:"public"` // @gotags: `class:"public"`
Recursive bool `protobuf:"varint,20,opt,name=recursive,proto3" json:"recursive,omitempty" class:"public"` // @gotags: `class:"public"`
Filter string `protobuf:"bytes,30,opt,name=filter,proto3" json:"filter,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
}
func (x *ListUsersRequest) Reset() {
@@ -280,7 +280,7 @@ type CreateUserResponse struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty"`
Uri string `protobuf:"bytes,1,opt,name=uri,proto3" json:"uri,omitempty" class:"public"` // @gotags: `class:"public"`
Item *users.User `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"`
}
@@ -335,7 +335,7 @@ type UpdateUserRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
Item *users.User `protobuf:"bytes,2,opt,name=item,proto3" json:"item,omitempty"`
UpdateMask *fieldmaskpb.FieldMask `protobuf:"bytes,3,opt,name=update_mask,proto3" json:"update_mask,omitempty"`
}
@@ -445,7 +445,7 @@ type DeleteUserRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *DeleteUserRequest) Reset() {
@@ -530,10 +530,10 @@ type AddUserAccountsRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *AddUserAccountsRequest) Reset() {
@@ -641,10 +641,10 @@ type SetUserAccountsRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *SetUserAccountsRequest) Reset() {
@@ -752,10 +752,10 @@ type RemoveUserAccountsRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty"`
Version uint32 `protobuf:"varint,2,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"`
AccountIds []string `protobuf:"bytes,3,rep,name=account_ids,proto3" json:"account_ids,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *RemoveUserAccountsRequest) Reset() {
@@ -11,61 +11,61 @@ import "controller/custom_options/v1/options.proto";
message Account {
// Output only. The ID of the Account.
string id = 10;
string id = 10; // @gotags: `class:"public"`
// Output only. The Scope containing the Account.
string scope_id = 20 [json_name = "scope_id"];
string scope_id = 20 [json_name = "scope_id"]; // @gotags: `class:"public"`
}
// User contains all fields related to a User resource
message User {
// Output only. The ID of the User.
string id = 10;
string id = 10; // @gotags: `class:"public"`
// The ID of the Scope this resource is in.
string scope_id = 20 [json_name = "scope_id"];
string scope_id = 20 [json_name = "scope_id"]; // @gotags: `class:"public"`
// Output only. Scope information for this resource.
resources.scopes.v1.ScopeInfo scope = 30;
// Optional name for identification purposes.
google.protobuf.StringValue name = 40 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "name" that: "name" }];
google.protobuf.StringValue name = 40 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "name" that: "name" }]; // @gotags: `class:"sensitive"`
// Optional user-set description for identification purposes.
google.protobuf.StringValue description = 50 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "description" that: "description" }];
google.protobuf.StringValue description = 50 [(custom_options.v1.generate_sdk_option) = true, (custom_options.v1.mask_mapping) = { this: "description" that: "description" }]; // @gotags: `class:"sensitive"`
// Output only. The time this resource was created.
google.protobuf.Timestamp created_time = 60 [json_name = "created_time"];
google.protobuf.Timestamp created_time = 60 [json_name = "created_time"]; // @gotags: `class:"public"`
// Output only. The time this resource was last updated.
google.protobuf.Timestamp updated_time = 70 [json_name = "updated_time"];
google.protobuf.Timestamp updated_time = 70 [json_name = "updated_time"]; // @gotags: `class:"public"`
// Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.
// The mutation will fail if the version does not match the latest known good version.
uint32 version = 80;
uint32 version = 80; // @gotags: `class:"public"`
// Output only. Contains the list of Account IDs linked to this User.
repeated string account_ids = 90 [json_name = "account_ids"];
repeated string account_ids = 90 [json_name = "account_ids"]; // @gotags: `class:"public"`
// Output only. The Accounts linked to this User.
repeated Account accounts = 100;
// Output only. The available actions on this resource for this user.
repeated string authorized_actions = 300 [json_name = "authorized_actions"];
repeated string authorized_actions = 300 [json_name = "authorized_actions"]; // @gotags: `class:"public"`
// Output only. login_name is a string that maps to the user's account "login
// name" from the scope's primary auth method
string login_name = 110 [json_name = "login_name"];
string login_name = 110 [json_name = "login_name"]; // @gotags: `class:"sensitive"`
// Output only. full_name is a string that maps to the user's account name
// from the scope's primary auth method
string full_name = 120 [json_name = "full_name"];
string full_name = 120 [json_name = "full_name"]; // @gotags: `class:"sensitive"`
// Output only. email is a string that maps to the user's account email from
// the scope's primary auth method
string email = 130 [json_name = "email"];
string email = 130 [json_name = "email"]; // @gotags: `class:"sensitive"`
// Output only. primary_account_id is a string that maps to the user's account
// public_id from the scope's primary auth method
string primary_account_id = 140 [json_name = "primary_account_id"];
string primary_account_id = 140 [json_name = "primary_account_id"]; // @gotags: `class:"public"`
}
@@ -136,7 +136,7 @@ service UserService {
}
message GetUserRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
}
message GetUserResponse {
@@ -144,9 +144,9 @@ message GetUserResponse {
}
message ListUsersRequest {
string scope_id = 1;
bool recursive = 20 [json_name="recursive"];
string filter = 30 [json_name="filter"];
string scope_id = 1; // @gotags: `class:"public"`
bool recursive = 20 [json_name="recursive"]; // @gotags: `class:"public"`
string filter = 30 [json_name="filter"]; // @gotags: `class:"sensitive"`
}
message ListUsersResponse {
@@ -158,12 +158,12 @@ message CreateUserRequest {
}
message CreateUserResponse {
string uri = 1;
string uri = 1; // @gotags: `class:"public"`
resources.users.v1.User item = 2;
}
message UpdateUserRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
resources.users.v1.User item = 2;
google.protobuf.FieldMask update_mask = 3 [json_name="update_mask"];
}
@@ -173,16 +173,16 @@ message UpdateUserResponse {
}
message DeleteUserRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
}
message DeleteUserResponse {}
message AddUserAccountsRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
uint32 version = 2;
repeated string account_ids = 3 [json_name="account_ids"];
uint32 version = 2; // @gotags: `class:"public"`
repeated string account_ids = 3 [json_name="account_ids"]; // @gotags: `class:"public"`
}
message AddUserAccountsResponse {
@@ -190,10 +190,10 @@ message AddUserAccountsResponse {
}
message SetUserAccountsRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
uint32 version = 2;
repeated string account_ids = 3 [json_name="account_ids"];
uint32 version = 2; // @gotags: `class:"public"`
repeated string account_ids = 3 [json_name="account_ids"]; // @gotags: `class:"public"`
}
message SetUserAccountsResponse {
@@ -201,10 +201,10 @@ message SetUserAccountsResponse {
}
message RemoveUserAccountsRequest {
string id = 1;
string id = 1; // @gotags: `class:"public"`
// The version ensures the User hasn't changed since it was last retrieved and if it has the request will fail.
uint32 version = 2;
repeated string account_ids = 3 [json_name="account_ids"];
uint32 version = 2; // @gotags: `class:"public"`
repeated string account_ids = 3 [json_name="account_ids"]; // @gotags: `class:"public"`
}
message RemoveUserAccountsResponse {
@@ -0,0 +1,119 @@
package users_test
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/hashicorp/boundary/sdk/pbs/controller/api"
"github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/scopes"
pb "github.com/hashicorp/boundary/sdk/pbs/controller/api/resources/users"
"github.com/hashicorp/boundary/sdk/wrapper"
"github.com/hashicorp/eventlogger"
"github.com/hashicorp/eventlogger/filters/encrypt"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/types/known/timestamppb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func TestUsers(t *testing.T) {
ctx := context.Background()
now := time.Now()
pbNow := timestamppb.Now()
wrapper := wrapper.TestWrapper(t)
testEncryptingFilter := api.NewEncryptFilter(t, wrapper)
testEncryptingFilter.FilterOperationOverrides = map[encrypt.DataClassification]encrypt.FilterOperation{
// Use HMAC for sensitive fields for easy test comparisons
encrypt.SensitiveClassification: encrypt.HmacSha256Operation,
}
tests := []struct {
name string
in *eventlogger.Event
want *eventlogger.Event
}{
{
name: "role",
in: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &pb.User{
Id: "id",
ScopeId: "scope-id",
Scope: &scopes.ScopeInfo{
Id: "scope-id",
Type: "scope-type",
Name: "scope-name",
Description: "scope-description",
ParentScopeId: "scope-parent-scope-id",
},
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "description"},
CreatedTime: pbNow,
UpdatedTime: pbNow,
Version: 0,
AccountIds: []string{"account-id"},
Accounts: []*pb.Account{
{
Id: "account-id",
ScopeId: "scope-id",
},
},
AuthorizedActions: []string{"action-1"},
LoginName: "login-name",
FullName: "full-name",
Email: "email@test.test",
PrimaryAccountId: "primary-account-id",
},
},
want: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &pb.User{
Id: "id",
ScopeId: "scope-id",
Scope: &scopes.ScopeInfo{
Id: "scope-id",
Type: "scope-type",
Name: "scope-name",
Description: "scope-description",
ParentScopeId: "scope-parent-scope-id",
},
Name: &wrapperspb.StringValue{Value: encrypt.TestHmacSha256(t, []byte("name"), wrapper, nil, nil)},
Description: &wrapperspb.StringValue{Value: encrypt.TestHmacSha256(t, []byte("description"), wrapper, nil, nil)},
CreatedTime: pbNow,
UpdatedTime: pbNow,
Version: 0,
AccountIds: []string{"account-id"},
Accounts: []*pb.Account{
{
Id: "account-id",
ScopeId: "scope-id",
},
},
AuthorizedActions: []string{"action-1"},
LoginName: encrypt.TestHmacSha256(t, []byte("login-name"), wrapper, nil, nil),
FullName: encrypt.TestHmacSha256(t, []byte("full-name"), wrapper, nil, nil),
Email: encrypt.TestHmacSha256(t, []byte("email@test.test"), wrapper, nil, nil),
PrimaryAccountId: "primary-account-id",
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert, require := assert.New(t), require.New(t)
got, err := testEncryptingFilter.Process(ctx, tt.in)
require.NoError(err)
require.NotNil(got)
gotJSON, err := json.Marshal(got)
require.NoError(err)
wantJSON, err := json.Marshal(tt.want)
require.NoError(err)
assert.JSONEq(string(wantJSON), string(gotJSON))
})
}
}
@@ -30,9 +30,9 @@ type Account struct {
unknownFields protoimpl.UnknownFields
// Output only. The ID of the Account.
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. The Scope containing the Account.
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,proto3" json:"scope_id,omitempty"`
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,proto3" json:"scope_id,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *Account) Reset() {
@@ -88,40 +88,40 @@ type User struct {
unknownFields protoimpl.UnknownFields
// Output only. The ID of the User.
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty"`
Id string `protobuf:"bytes,10,opt,name=id,proto3" json:"id,omitempty" class:"public"` // @gotags: `class:"public"`
// The ID of the Scope this resource is in.
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,proto3" json:"scope_id,omitempty"`
ScopeId string `protobuf:"bytes,20,opt,name=scope_id,proto3" json:"scope_id,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. Scope information for this resource.
Scope *scopes.ScopeInfo `protobuf:"bytes,30,opt,name=scope,proto3" json:"scope,omitempty"`
// Optional name for identification purposes.
Name *wrapperspb.StringValue `protobuf:"bytes,40,opt,name=name,proto3" json:"name,omitempty"`
Name *wrapperspb.StringValue `protobuf:"bytes,40,opt,name=name,proto3" json:"name,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
// Optional user-set description for identification purposes.
Description *wrapperspb.StringValue `protobuf:"bytes,50,opt,name=description,proto3" json:"description,omitempty"`
Description *wrapperspb.StringValue `protobuf:"bytes,50,opt,name=description,proto3" json:"description,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
// Output only. The time this resource was created.
CreatedTime *timestamppb.Timestamp `protobuf:"bytes,60,opt,name=created_time,proto3" json:"created_time,omitempty"`
CreatedTime *timestamppb.Timestamp `protobuf:"bytes,60,opt,name=created_time,proto3" json:"created_time,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. The time this resource was last updated.
UpdatedTime *timestamppb.Timestamp `protobuf:"bytes,70,opt,name=updated_time,proto3" json:"updated_time,omitempty"`
UpdatedTime *timestamppb.Timestamp `protobuf:"bytes,70,opt,name=updated_time,proto3" json:"updated_time,omitempty" class:"public"` // @gotags: `class:"public"`
// Version is used in mutation requests, after the initial creation, to ensure this resource has not changed.
// The mutation will fail if the version does not match the latest known good version.
Version uint32 `protobuf:"varint,80,opt,name=version,proto3" json:"version,omitempty"`
Version uint32 `protobuf:"varint,80,opt,name=version,proto3" json:"version,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. Contains the list of Account IDs linked to this User.
AccountIds []string `protobuf:"bytes,90,rep,name=account_ids,proto3" json:"account_ids,omitempty"`
AccountIds []string `protobuf:"bytes,90,rep,name=account_ids,proto3" json:"account_ids,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. The Accounts linked to this User.
Accounts []*Account `protobuf:"bytes,100,rep,name=accounts,proto3" json:"accounts,omitempty"`
// Output only. The available actions on this resource for this user.
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty"`
AuthorizedActions []string `protobuf:"bytes,300,rep,name=authorized_actions,proto3" json:"authorized_actions,omitempty" class:"public"` // @gotags: `class:"public"`
// Output only. login_name is a string that maps to the user's account "login
// name" from the scope's primary auth method
LoginName string `protobuf:"bytes,110,opt,name=login_name,proto3" json:"login_name,omitempty"`
LoginName string `protobuf:"bytes,110,opt,name=login_name,proto3" json:"login_name,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
// Output only. full_name is a string that maps to the user's account name
// from the scope's primary auth method
FullName string `protobuf:"bytes,120,opt,name=full_name,proto3" json:"full_name,omitempty"`
FullName string `protobuf:"bytes,120,opt,name=full_name,proto3" json:"full_name,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
// Output only. email is a string that maps to the user's account email from
// the scope's primary auth method
Email string `protobuf:"bytes,130,opt,name=email,proto3" json:"email,omitempty"`
Email string `protobuf:"bytes,130,opt,name=email,proto3" json:"email,omitempty" class:"sensitive"` // @gotags: `class:"sensitive"`
// Output only. primary_account_id is a string that maps to the user's account
// public_id from the scope's primary auth method
PrimaryAccountId string `protobuf:"bytes,140,opt,name=primary_account_id,proto3" json:"primary_account_id,omitempty"`
PrimaryAccountId string `protobuf:"bytes,140,opt,name=primary_account_id,proto3" json:"primary_account_id,omitempty" class:"public"` // @gotags: `class:"public"`
}
func (x *User) Reset() {