* Add Type() to detector interface The goal here is to allow the detector type information to be used without the need for reflection. This could possibly allow us to more easily inject information into detectors or filter them out if necessary. Co-authored-by: ahmed <[email protected]> * remove test detector --------- Co-authored-by: ahmed <[email protected]>
92 lines
2.6 KiB
Go
92 lines
2.6 KiB
Go
package azure
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/Azure/go-autorest/autorest/azure/auth"
|
|
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
|
|
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
|
|
)
|
|
|
|
type Scanner struct{}
|
|
|
|
// Ensure the Scanner satisfies the interface at compile time.
|
|
var _ detectors.Detector = (*Scanner)(nil)
|
|
|
|
func mustFmtPat(id, pat string) *regexp.Regexp {
|
|
combinedID := strings.ReplaceAll(id, "_", "") + "|" + id
|
|
return regexp.MustCompile(fmt.Sprintf(pat, combinedID))
|
|
}
|
|
|
|
var (
|
|
// TODO: Azure storage access keys and investigate other types of creds.
|
|
|
|
// Azure App Oauth
|
|
idPatFmt = `(?i)(%s).{0,20}([a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})`
|
|
clientIDPat = mustFmtPat("client_id", idPatFmt)
|
|
tenantIDPat = mustFmtPat("tenant_id", idPatFmt)
|
|
|
|
// TODO: support old patterns
|
|
secretPatFmt = `(?i)(%s).{0,20}([a-z0-9_\.\-~]{34})`
|
|
clientSecretPat = mustFmtPat("client_secret", secretPatFmt)
|
|
)
|
|
|
|
// Keywords are used for efficiently pre-filtering chunks.
|
|
// Use identifiers in the secret preferably, or the provider name.
|
|
func (s Scanner) Keywords() []string {
|
|
return []string{"azure"}
|
|
}
|
|
|
|
// FromData will find and optionally verify Azure secrets in a given set of bytes.
|
|
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
|
|
dataStr := string(data)
|
|
|
|
clientSecretMatches := clientSecretPat.FindAllStringSubmatch(dataStr, -1)
|
|
for _, clientSecret := range clientSecretMatches {
|
|
tenantIDMatches := tenantIDPat.FindAllStringSubmatch(dataStr, -1)
|
|
for _, tenantID := range tenantIDMatches {
|
|
clientIDMatches := clientIDPat.FindAllStringSubmatch(dataStr, -1)
|
|
for _, clientID := range clientIDMatches {
|
|
s := detectors.Result{
|
|
DetectorType: detectorspb.DetectorType_Azure,
|
|
Raw: []byte(clientSecret[2]),
|
|
Redacted: clientID[2],
|
|
}
|
|
|
|
if verify {
|
|
cred := auth.NewClientCredentialsConfig(clientID[2], clientSecret[2], tenantID[2])
|
|
token, err := cred.ServicePrincipalToken()
|
|
if err != nil {
|
|
continue
|
|
}
|
|
err = token.Refresh()
|
|
if err == nil {
|
|
s.Verified = true
|
|
}
|
|
}
|
|
|
|
if !s.Verified {
|
|
if detectors.IsKnownFalsePositive(s.Redacted, detectors.DefaultFalsePositives, true) {
|
|
continue
|
|
}
|
|
if detectors.IsKnownFalsePositive(string(s.Raw), detectors.DefaultFalsePositives, true) {
|
|
continue
|
|
}
|
|
}
|
|
|
|
results = append(results, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
return results, nil
|
|
}
|
|
|
|
func (s Scanner) Type() detectorspb.DetectorType {
|
|
return detectorspb.DetectorType_Azure
|
|
}
|