Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/auth0_network-acl_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ auth0 network-acl create [flags]
auth0 network-acl create --description "Complex Rule" --priority 5 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}'
auth0 network-acl create --description "Deny All" --priority 7 --active true --rule '{"action":{"block":true},"scope":"tenant","match_all":true}'

# Early Access (auth0_managed match/not_match value):
# Early Access (auth0_managed and http_message_signature match/not_match value):
auth0 network-acl create -d "Curated Blocklist" -p 6 --active true --rule '{"action":{"log":true},"scope":"tenant","not_match":{"auth0_managed":["auth0.vpn","auth0.proxy"]}}'
auth0 network-acl create -d "Only Signed" -p 8 --active true --rule '{"action":{"allow":true},"scope":"authentication","match":{"http_message_signature":{"keys":[{"id": "key_123"}]}}}'

```

Expand Down
3 changes: 2 additions & 1 deletion docs/auth0_network-acl_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ auth0 network-acl update [flags]
auth0 network-acl update <id> --description "Complex Rule updated" --priority 1 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}'
auth0 network-acl update <id> --rule '{"action":{"block":true},"scope":"tenant","match_all":true}'

# Early Access (auth0_managed match/not_match value):
# Early Access (auth0_managed and http_message_signature match/not_match value):
auth0 network-acl update <id> --rule '{"action":{"allow":true},"scope":"tenant","match":{"auth0_managed":["auth0.low_reputation"]}}'
auth0 network-acl update <id> --rule '{"action":{"allow":true},"scope":"authentication","match":{"http_message_signature":{"keys":[{"id": "key_123"},{"id": "key_456"}]}}}'

```

Expand Down
2 changes: 2 additions & 0 deletions internal/auth0/auth0.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ type APIV3 struct {
UserRefreshToken UserRefreshTokenAPIV3
ActionModule ActionModuleAPIV3
ActionModuleVersion ActionModuleVersionAPIV3
NetworkACLKey NetworkACLKeyAPIV3
}

func NewAPIV3(m *managementv3.Management) *APIV3 {
Expand All @@ -108,6 +109,7 @@ func NewAPIV3(m *managementv3.Management) *APIV3 {
UserRefreshToken: m.Users.RefreshToken,
ActionModule: m.Actions.Modules,
ActionModuleVersion: m.Actions.Modules.Versions,
NetworkACLKey: m.Keys.NetworkACLs,
}
}

Expand Down
57 changes: 57 additions & 0 deletions internal/auth0/mock/network_acl_key_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions internal/auth0/network_acl_key.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//go:generate mockgen -source=network_acl_key.go -destination=mock/network_acl_key_mock.go -package=mock

package auth0

import (
"context"

managementv3 "github.com/auth0/go-auth0/v3/management"
"github.com/auth0/go-auth0/v3/management/option"
)

// NetworkACLKeyAPIV3 is the V3 SDK interface for the /keys/network-acls endpoint.
//
// Only List is exposed today: the network-acl command uses it to let a user pick
// existing signing keys by name when adding the http_message_signature signal to a
// rule. Key create/delete is intentionally not wired yet (DXCDT-2269).
type NetworkACLKeyAPIV3 interface {
// List retrieves all Network ACL keys for the tenant.
//
// Required scope: `read:network_acl_keys`. The response is not paginated.
List(ctx context.Context, opts ...option.RequestOption) (*managementv3.GetAllKeysNetworkACLsResponseContent, error)
}
168 changes: 131 additions & 37 deletions internal/cli/network_acl.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ func selectNetworkACLParams() (map[string]bool, error) {
"JA4Fingerprints",
"User Agents",
"Auth0 Managed",
"Signature Keys",
}

var selected []string
Expand Down Expand Up @@ -228,22 +229,23 @@ func selectNetworkACLParams() (map[string]bool, error) {

// ruleDefaults holds default values extracted from current ACL rule.
type ruleDefaults struct {
Scope string
Action string
RedirectURI string
ASNs []int
CountryCodes []string
SubdivCodes []string
IPv4CIDRs []string
IPv6CIDRs []string
JA3 []string
JA4 []string
UserAgents []string
Auth0Managed []string
IsMatchRule bool
HasMatchRule bool
HasNotMatch bool
MatchAll bool
Scope string
Action string
RedirectURI string
ASNs []int
CountryCodes []string
SubdivCodes []string
IPv4CIDRs []string
IPv6CIDRs []string
JA3 []string
JA4 []string
UserAgents []string
Auth0Managed []string
SignatureKeyIDs []string
IsMatchRule bool
HasMatchRule bool
HasNotMatch bool
MatchAll bool
}

// extractCurrentRuleDefaults extracts default values from current ACL rule for interactive prompts.
Expand Down Expand Up @@ -322,29 +324,46 @@ func extractCurrentRuleDefaults(currentACL *management.NetworkACL) *ruleDefaults
if match.Auth0Managed != nil {
defaults.Auth0Managed = *match.Auth0Managed
}
defaults.SignatureKeyIDs = signatureKeyIDs(match)
}

return defaults
}

// signatureKeyIDs flattens the referenced key ids of a match's
// http_message_signature signal, or nil when the signal is not set.
func signatureKeyIDs(match *management.NetworkACLRuleMatch) []string {
if match == nil || match.HTTPMessageSignature == nil {
return nil
}
ids := make([]string, 0, len(match.HTTPMessageSignature.Keys))
for _, k := range match.HTTPMessageSignature.Keys {
if k.ID != nil {
ids = append(ids, *k.ID)
}
}
return ids
}

// ruleInputs holds user inputs for rule configuration.
type ruleInputs struct {
Scope string
Action string
RedirectURI string
ASNs []int
CountryCodes []string
SubdivCodes []string
IPv4CIDRs []string
IPv6CIDRs []string
JA3 []string
JA4 []string
UserAgents []string
Auth0Managed []string
IsMatchRule bool
MatchRule bool
NoMatchRule bool
MatchAll bool
Scope string
Action string
RedirectURI string
ASNs []int
CountryCodes []string
SubdivCodes []string
IPv4CIDRs []string
IPv6CIDRs []string
JA3 []string
JA4 []string
UserAgents []string
Auth0Managed []string
SignatureKeyIDs []string
IsMatchRule bool
MatchRule bool
NoMatchRule bool
MatchAll bool
}

// promptForRuleDetails handles interactive prompting for rule configuration.
Expand Down Expand Up @@ -415,7 +434,7 @@ func promptForRuleDetails(cmd *cobra.Command, cli *cli, defaults *ruleDefaults,
var selectedMatchOption string
if err := (&Flag{
Name: "What kind of rule do you want to create?",
Help: "Match or Not Match rule (ASNs, Country Codes, Subdivision Codes, IPv4 CIDRs, IPv6 CIDRs, JA3/JA4 Fingerprints, User Agents, Auth0 Managed)",
Help: "Match or Not Match rule (ASNs, Country Codes, Subdivision Codes, IPv4 CIDRs, IPv6 CIDRs, JA3/JA4 Fingerprints, User Agents, Auth0 Managed, Signature Keys)",
}).Select(cmd, &selectedMatchOption, matchOptions, nil); err != nil {
return nil, err
}
Expand All @@ -429,15 +448,15 @@ func promptForRuleDetails(cmd *cobra.Command, cli *cli, defaults *ruleDefaults,
}

// Ask for values only for selected parameters.
if err := promptForMatchCriteria(cmd, selectedParams, inputs, defaults); err != nil {
if err := promptForMatchCriteria(cmd, cli, selectedParams, inputs, defaults); err != nil {
return nil, err
}

return inputs, nil
}

// promptForMatchCriteria handles prompting for all match criteria based on selected parameters.
func promptForMatchCriteria(cmd *cobra.Command, selectedParams map[string]bool, inputs *ruleInputs, defaults *ruleDefaults) error {
func promptForMatchCriteria(cmd *cobra.Command, cli *cli, selectedParams map[string]bool, inputs *ruleInputs, defaults *ruleDefaults) error {
if selectedParams["ASNs"] {
if err := (&Flag{
Name: "ASNs",
Expand Down Expand Up @@ -527,9 +546,74 @@ func promptForMatchCriteria(cmd *cobra.Command, selectedParams map[string]bool,
}
}

if selectedParams["Signature Keys"] {
ids, err := cli.pickNetworkACLSignatureKeys(cmd, defaults.SignatureKeyIDs)
if err != nil {
return err
}
inputs.SignatureKeyIDs = ids
}

return nil
}

// pickNetworkACLSignatureKeys resolves the http_message_signature key ids for a rule.
//
// It lists the tenant's Network ACL keys (v3 /keys/network-acls) and shows a multi-select
// of them, with the ids already referenced by the rule (current) pre-selected. Setting the
// signal non-interactively is done through the full rule JSON passed to --rule.
func (c *cli) pickNetworkACLSignatureKeys(cmd *cobra.Command, current []string) ([]string, error) {
var options []string
labelToID := make(map[string]string)
idToLabel := make(map[string]string)
if err := ansi.Waiting(func() error {
resp, err := c.apiv3.NetworkACLKey.List(cmd.Context())
if err != nil {
return err
}
if resp != nil {
for _, k := range resp.Keys {
id := k.GetID()
label := fmt.Sprintf("%s (%s)", k.GetName(), id)
options = append(options, label)
idToLabel[id] = label
labelToID[label] = id
}
}
return nil
}); err != nil {
return nil, err
}

if len(options) == 0 {
return nil, errors.New("no Network ACL keys exist for this tenant; create a key first, then reference it here")
}

// Pre-select the keys already referenced by the rule.
defaults := make([]string, 0, len(current))
for _, id := range current {
if label, ok := idToLabel[id]; ok {
defaults = append(defaults, label)
}
}

var selected []string
if err := prompt.AskMultiSelectWithDefault(
"Select the signing keys whose HTTP message signature satisfies the rule using the spacebar and press Enter to confirm:",
&selected,
defaults,
options...,
); err != nil {
return nil, err
}

ids := make([]string, 0, len(selected))
for _, label := range selected {
ids = append(ids, labelToID[label])
}
return ids, nil
}

// buildNetworkACLRule creates a NetworkACLRule from the provided inputs.
func buildNetworkACLRule(inputs *ruleInputs) (*management.NetworkACLRule, error) {
rule := &management.NetworkACLRule{
Expand Down Expand Up @@ -595,6 +679,14 @@ func buildNetworkACLRule(inputs *ruleInputs) (*management.NetworkACLRule, error)
match.Auth0Managed = &inputs.Auth0Managed
matchProvided = true
}
if len(inputs.SignatureKeyIDs) > 0 {
keys := make([]*management.NetworkACLHTTPMessageSignatureKey, len(inputs.SignatureKeyIDs))
for i := range inputs.SignatureKeyIDs {
keys[i] = &management.NetworkACLHTTPMessageSignatureKey{ID: &inputs.SignatureKeyIDs[i]}
}
match.HTTPMessageSignature = &management.NetworkACLHTTPMessageSignature{Keys: keys}
matchProvided = true
}

if !matchProvided {
return nil, fmt.Errorf("at least one match criteria must be provided")
Expand Down Expand Up @@ -715,8 +807,9 @@ The --rule parameter is required and must contain a valid JSON object with actio
auth0 network-acl create --description "Complex Rule" --priority 5 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}'
auth0 network-acl create --description "Deny All" --priority 7 --active true --rule '{"action":{"block":true},"scope":"tenant","match_all":true}'

# Early Access (auth0_managed match/not_match value):
# Early Access (auth0_managed and http_message_signature match/not_match value):
auth0 network-acl create -d "Curated Blocklist" -p 6 --active true --rule '{"action":{"log":true},"scope":"tenant","not_match":{"auth0_managed":["auth0.vpn","auth0.proxy"]}}'
auth0 network-acl create -d "Only Signed" -p 8 --active true --rule '{"action":{"allow":true},"scope":"authentication","match":{"http_message_signature":{"keys":[{"id": "key_123"}]}}}'
`,
RunE: func(cmd *cobra.Command, args []string) error {
// Validate --rule JSON up front, before prompting for other fields, so
Expand Down Expand Up @@ -818,8 +911,9 @@ To update non-interactively, supply the description, active, priority, and rule
auth0 network-acl update <id> --description "Complex Rule updated" --priority 1 --active true --rule '{"action":{"block":true},"scope":"tenant","match":{"ipv4_cidrs":["192.168.1.0/24"],"geo_country_codes":["US"]}}'
auth0 network-acl update <id> --rule '{"action":{"block":true},"scope":"tenant","match_all":true}'

# Early Access (auth0_managed match/not_match value):
# Early Access (auth0_managed and http_message_signature match/not_match value):
auth0 network-acl update <id> --rule '{"action":{"allow":true},"scope":"tenant","match":{"auth0_managed":["auth0.low_reputation"]}}'
auth0 network-acl update <id> --rule '{"action":{"allow":true},"scope":"authentication","match":{"http_message_signature":{"keys":[{"id": "key_123"},{"id": "key_456"}]}}}'
`,
RunE: func(cmd *cobra.Command, args []string) error {
// Get the network ACL ID.
Expand Down
Loading
Loading