-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add more validations to trust-policy parsing #43
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,8 @@ | ||
github.com/go-ldap/ldap v3.0.3+incompatible h1:HTeSZO8hWMS1Rgb2Ziku6b8a7qRIZZMHjsvuZyatzwk= | ||
github.com/go-ldap/ldap v3.0.3+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp40uXYvFoEVrNEPqRc= | ||
github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= | ||
github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= | ||
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= | ||
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= | ||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d h1:TxyelI5cVkbREznMhfzycHdkp5cLA7DpE+GKjSslYhM= | ||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw= |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,74 @@ | ||||||||||||||||||||||||||
package verification | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
import ( | ||||||||||||||||||||||||||
"fmt" | ||||||||||||||||||||||||||
"regexp" | ||||||||||||||||||||||||||
"strings" | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
"github.com/go-ldap/ldap" | ||||||||||||||||||||||||||
) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// isPresent is a utility function to check if a string exists in an array | ||||||||||||||||||||||||||
func isPresent(val string, values []string) bool { | ||||||||||||||||||||||||||
for _, v := range values { | ||||||||||||||||||||||||||
if v == val { | ||||||||||||||||||||||||||
return true | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
return false | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// validateRegistryScopeFormat validates if a scope is following the format defined in distribution spec | ||||||||||||||||||||||||||
func validateRegistryScopeFormat(scope string) error { | ||||||||||||||||||||||||||
// Domain and Repository regexes are adapted from distribution implementation | ||||||||||||||||||||||||||
// https://github.com/distribution/distribution/blob/main/reference/regexp.go#L31 | ||||||||||||||||||||||||||
domainRegexp := regexp.MustCompile(`^(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])(?:(?:\.(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9]))+)?(?::[0-9]+)?$`) | ||||||||||||||||||||||||||
repositoryRegexp := regexp.MustCompile(`^[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?(?:(?:/[a-z0-9]+(?:(?:(?:[._]|__|[-]*)[a-z0-9]+)+)?)+)?$`) | ||||||||||||||||||||||||||
errorMessage := "registry scope %q is not valid, make sure it is the fully qualified registry URL without the scheme/protocol. e.g domain.com/my/repository" | ||||||||||||||||||||||||||
firstSlash := strings.Index(scope, "/") | ||||||||||||||||||||||||||
if firstSlash < 0 { | ||||||||||||||||||||||||||
return fmt.Errorf(errorMessage, scope) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
domain := scope[:firstSlash] | ||||||||||||||||||||||||||
repository := scope[firstSlash+1:] | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if domain == "" || repository == "" || !domainRegexp.MatchString(domain) || !repositoryRegexp.MatchString(repository) { | ||||||||||||||||||||||||||
return fmt.Errorf(errorMessage, scope) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// No errors | ||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// validateDistinguishedName validates if a DN name parsable and follows Notary V2 rules | ||||||||||||||||||||||||||
func validateDistinguishedName(name string) error { | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, this method should move into On second thought, this is Notary V2 specific DN validation based on what we allow in trust policy, so seems appropriate here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this method and There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These helpers are for policy validation but I wanted to move them to a helper file so that policy.go is cleaner and deals with higher level functionality like policy verification. There is no side effect of having these methods in a helper class as Go package is a closure of everything under the package directory. |
||||||||||||||||||||||||||
mandatoryFields := []string{"C", "ST", "O"} | ||||||||||||||||||||||||||
rDnCount := make(map[string]int) | ||||||||||||||||||||||||||
dn, err := ldap.ParseDN(name) | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
if err != nil { | ||||||||||||||||||||||||||
return fmt.Errorf("distinguished name (DN) %q is not valid, make sure it is following rfc4514 standard", name) | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
for _, rdn := range dn.RDNs { | ||||||||||||||||||||||||||
for _, attribute := range rdn.Attributes { | ||||||||||||||||||||||||||
rDnCount[attribute.Type]++ | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Verify there are no duplicate RDNs (multi-valdued RDNs are not supported) | ||||||||||||||||||||||||||
for key := range rDnCount { | ||||||||||||||||||||||||||
if rDnCount[key] > 1 { | ||||||||||||||||||||||||||
return fmt.Errorf("distinguished name (DN) %q has duplicate RDNs, DN can only have unique RDNs", name) | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Duplicate is different from multi valued RDN, correct? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. End customers may not be familiar with terminology RDN
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We want notation-go lib to not support multi-valued RDNs as they are not commonly used, and confusing for end customers. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed |
||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
// Verify mandatory fields are present | ||||||||||||||||||||||||||
for _, field := range mandatoryFields { | ||||||||||||||||||||||||||
if rDnCount[field] != 1 { | ||||||||||||||||||||||||||
return fmt.Errorf("distinguished name (DN) %q has no mandatory RDN for %q", name, field) | ||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||
// No errors | ||||||||||||||||||||||||||
return nil | ||||||||||||||||||||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How is that
ldap
is marked as indirect when it is directly referenced in our code?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I should have run
go mod tidy
. Also, I realized that I should use go-ldap v3 as mentioned here. Thanks for pointing this out. Will raise a new revision for this PR.