Events: Add outbound detail protobufs, request status code, and update event encrypt filter. (#1569)

* feat (events): Add status code to audit events

* feat (events): Add the resp proto msg to every audit event

* chore (events): Update eventlogger dep

This latest version will redact any map and/or map field which isn't
explicitly classified via a Taggable interface

* feat (events): Begin to add tagging to response proto msgs
This commit is contained in:
Jim authored and GitHub committed 2021-09-30 12:55:47 -04:00
1 parent 8d6dee09a9
commit c8b29ded1c
23 files changed
+914 -129

No files matched your search

@@ -32,31 +32,31 @@ type AuthMethod struct {
unknownFields protoimpl.UnknownFields
// Output only. The ID of the Auth Method.
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 of which this Auth Method is a part.
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 Auth method.
Scope *scopes.ScopeInfo `protobuf:"bytes,30,opt,name=scope,proto3" json:"scope,omitempty"`
Scope *scopes.ScopeInfo `protobuf:"bytes,30,opt,name=scope,proto3" json:"scope,omitempty" class:"public"` // @gotags: `class:"public"`
// 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:"public"` // @gotags: `class:"public"`
// 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:"public"` // @gotags: `class:"public"`
// 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"`
// The Auth Method type.
Type string `protobuf:"bytes,90,opt,name=type,proto3" json:"type,omitempty"`
Type string `protobuf:"bytes,90,opt,name=type,proto3" json:"type,omitempty" class:"public"` // @gotags: `class:"public"`
// The attributes that are applicable for the specific Auth Method type.
Attributes *structpb.Struct `protobuf:"bytes,100,opt,name=attributes,proto3" json:"attributes,omitempty"`
// Output only. Whether this auth method is the primary auth method for it's scope.
// To change this value update the primary_auth_method_id field on the scope.
IsPrimary bool `protobuf:"varint,110,opt,name=is_primary,proto3" json:"is_primary,omitempty"`
IsPrimary bool `protobuf:"varint,110,opt,name=is_primary,proto3" json:"is_primary,omitempty" class:"public"` // @gotags: `class:"public"`
// 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. The authorized actions for the scope's collections.
AuthorizedCollectionActions map[string]*structpb.ListValue `protobuf:"bytes,310,rep,name=authorized_collection_actions,proto3" json:"authorized_collection_actions,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
}
@@ -0,0 +1,98 @@
package authmethods
import (
"fmt"
"github.com/hashicorp/eventlogger/filters/encrypt"
)
// Tags implements the encrypt.Taggable interface which allows
// AuthMethod map fields to be classified for the encrypt filter.
func (req *AuthMethod) Tags() ([]encrypt.PointerTag, error) {
tags := make([]encrypt.PointerTag, 0, len(req.AuthorizedCollectionActions))
for k := range req.AuthorizedCollectionActions {
tags = append(tags, encrypt.PointerTag{
Pointer: fmt.Sprintf("/AuthorizedCollectionActions/%s", k),
Classification: encrypt.PublicClassification,
})
}
if req.Attributes != nil {
switch req.Type {
case "oidc":
oidcTags := []encrypt.PointerTag{
// public fields
{
Pointer: "/Attributes/Fields/state",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/issuer",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/client_id",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/client_secret_hmac",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/max_age",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/signing_algorithms",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/api_url_prefix",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/callback_url",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/allowed_audiences",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/claims_scopes",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/account_claim_maps",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/disable_discovered_config_validation",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/dry_run",
Classification: encrypt.PublicClassification,
},
// secrets
{
Pointer: "/Attributes/Fields/client_secret",
Classification: encrypt.SecretClassification,
},
}
tags = append(tags, oidcTags...)
case "password":
pwTags := []encrypt.PointerTag{
{
Pointer: "/Attributes/Fields/min_login_name_length",
Classification: encrypt.PublicClassification,
},
{
Pointer: "/Attributes/Fields/min_password_length",
Classification: encrypt.PublicClassification,
},
}
tags = append(tags, pwTags...)
}
}
return tags, nil
}
@@ -0,0 +1,183 @@
package authmethods
import (
"context"
"encoding/json"
"testing"
"time"
"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/structpb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
func TestAuthMethod_Tags(t *testing.T) {
ctx := context.Background()
now := time.Now()
wrapper := wrapper.TestWrapper(t)
testEncryptingFilter := &encrypt.Filter{
Wrapper: wrapper,
HmacSalt: []byte("salt"),
HmacInfo: []byte("info"),
}
tests := []struct {
name string
testEvent *eventlogger.Event
wantEvent *eventlogger.Event
}{
{
name: "validate-oidc-filtering",
testEvent: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &AuthMethod{
Id: "id",
ScopeId: "scope-id",
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "description"},
Type: "oidc",
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
"state": structpb.NewStringValue("public-state"),
"issuer": structpb.NewStringValue("public-issuer"),
"client_id": structpb.NewStringValue("public-client_id"),
"client_secret_hmac": structpb.NewStringValue("public-client_secret_hmac"),
"max_age": structpb.NewStringValue("public-max_age"),
"signing_algorithms": structpb.NewStringValue("public-signing_algorithms"),
"api_url_prefix": structpb.NewStringValue("public-api_url_prefix"),
"callback_url": structpb.NewStringValue("public-callback_url"),
"allowed_audiences": structpb.NewStringValue("public-allowed_audiences"),
"claims_scopes": structpb.NewStringValue("public-claims_scopes"),
"account_claim_maps": structpb.NewStringValue("public-account_claim_maps"),
"disable_discovered_config_validation": structpb.NewStringValue("public-disable_discovered_config_validation"),
"dry_run": structpb.NewStringValue("public-dry_run"),
"client_secret": structpb.NewStringValue("secret-client_secret"),
},
},
AuthorizedActions: []string{"action-1", "action-2"},
AuthorizedCollectionActions: map[string]*structpb.ListValue{
"auth-methods": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
},
},
},
wantEvent: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &AuthMethod{
Id: "id",
ScopeId: "scope-id",
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "description"},
Type: "oidc",
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
"state": structpb.NewStringValue("public-state"),
"issuer": structpb.NewStringValue("public-issuer"),
"client_id": structpb.NewStringValue("public-client_id"),
"client_secret_hmac": structpb.NewStringValue("public-client_secret_hmac"),
"max_age": structpb.NewStringValue("public-max_age"),
"signing_algorithms": structpb.NewStringValue("public-signing_algorithms"),
"api_url_prefix": structpb.NewStringValue("public-api_url_prefix"),
"callback_url": structpb.NewStringValue("public-callback_url"),
"allowed_audiences": structpb.NewStringValue("public-allowed_audiences"),
"claims_scopes": structpb.NewStringValue("public-claims_scopes"),
"account_claim_maps": structpb.NewStringValue("public-account_claim_maps"),
"disable_discovered_config_validation": structpb.NewStringValue("public-disable_discovered_config_validation"),
"dry_run": structpb.NewStringValue("public-dry_run"),
"client_secret": structpb.NewStringValue("<REDACTED>"),
},
},
AuthorizedActions: []string{"action-1", "action-2"},
AuthorizedCollectionActions: map[string]*structpb.ListValue{
"auth-methods": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
},
},
},
},
{
name: "validate-password-filtering",
testEvent: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &AuthMethod{
Id: "id",
ScopeId: "scope-id",
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "description"},
Type: "oidc",
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
"min_login_name_length": structpb.NewStringValue("public-min_login_name_length"),
"min_password_length": structpb.NewStringValue("public-min_password_length"),
},
},
AuthorizedActions: []string{"action-1", "action-2"},
AuthorizedCollectionActions: map[string]*structpb.ListValue{
"auth-methods": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
},
},
},
wantEvent: &eventlogger.Event{
Type: "test",
CreatedAt: now,
Payload: &AuthMethod{
Id: "id",
ScopeId: "scope-id",
Name: &wrapperspb.StringValue{Value: "name"},
Description: &wrapperspb.StringValue{Value: "description"},
Type: "oidc",
Attributes: &structpb.Struct{
Fields: map[string]*structpb.Value{
"min_login_name_length": structpb.NewStringValue("public-min_login_name_length"),
"min_password_length": structpb.NewStringValue("public-min_password_length"),
},
},
AuthorizedActions: []string{"action-1", "action-2"},
AuthorizedCollectionActions: map[string]*structpb.ListValue{
"auth-methods": {
Values: []*structpb.Value{
structpb.NewStringValue("create"),
structpb.NewStringValue("list"),
},
},
},
},
},
},
}
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.testEvent)
require.NoError(err)
require.NotNil(got)
actualJson, err := json.Marshal(got)
require.NoError(err)
t.Log(string(actualJson))
wantJson, err := json.Marshal(tt.wantEvent)
require.NoError(err)
assert.JSONEq(string(wantJson), string(actualJson))
})
}
}