Skip to content

Commit eb37f00

Browse files
committed
cleanup some unnecessary logic for expiry formatting.
code refactoring, remove unnecessary code. updated the description of detector. reduce the expiry to 5 seconds.
1 parent 51a25f3 commit eb37f00

File tree

2 files changed

+24
-32
lines changed

2 files changed

+24
-32
lines changed

pkg/detectors/azuredirectmanagementkey/azuredirectmanagementkey.go

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ import (
1717
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
1818
)
1919

20+
const RFC3339WithoutMicroseconds = "2006-01-02T15:04:05"
21+
2022
type Scanner struct {
2123
client *http.Client
2224
detectors.DefaultMultiPartCredentialProvider
@@ -28,7 +30,7 @@ var _ detectors.Detector = (*Scanner)(nil)
2830
var (
2931
defaultClient = common.SaneHttpClient()
3032
urlPat = regexp.MustCompile(`https://([a-z0-9][a-z0-9-]{0,48}[a-z0-9])\.management\.azure-api\.net`) // https://azure.github.io/PSRule.Rules.Azure/en/rules/Azure.APIM.Name/
31-
keyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"azure"}) + `\b([a-zA-Z0-9+\/-]{86,88}\b={0,2})`) // Base64-encoded primary key
33+
primaryKeyPat = regexp.MustCompile(detectors.PrefixRegex([]string{"azure"}) + `\b([a-zA-Z0-9+\/-]{86,88}\b={0,2})`) // Base64-encoded primary key
3234
)
3335

3436
// Keywords are used for efficiently pre-filtering chunks.
@@ -41,30 +43,21 @@ func (s Scanner) Keywords() []string {
4143
func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (results []detectors.Result, err error) {
4244
dataStr := string(data)
4345

44-
urlMatches := urlPat.FindAllStringSubmatch(dataStr, -1)
45-
keyMatches := keyPat.FindAllStringSubmatch(dataStr, -1)
46-
4746
urlMatchesUnique := make(map[string]string)
48-
for _, urlMatch := range urlMatches {
49-
urlMatchesUnique[urlMatch[0]] = urlMatch[1]
47+
for _, urlMatch := range urlPat.FindAllStringSubmatch(dataStr, -1) {
48+
urlMatchesUnique[urlMatch[0]] = urlMatch[1] // urlMatch[0] is the full url, urlMatch[1] is the service name
5049
}
51-
keyMatchesUnique := make(map[string]struct{})
52-
for _, keyMatch := range keyMatches {
53-
keyMatchesUnique[keyMatch[1]] = struct{}{}
50+
primaryKeyMatchesUnique := make(map[string]struct{})
51+
for _, keyMatch := range primaryKeyPat.FindAllStringSubmatch(dataStr, -1) {
52+
primaryKeyMatchesUnique[strings.TrimSpace(keyMatch[1])] = struct{}{}
5453
}
5554

5655
for baseUrl, serviceName := range urlMatchesUnique {
57-
for key, _ := range keyMatchesUnique {
58-
resMatch := strings.TrimSpace(key)
59-
url := fmt.Sprintf(
60-
"%s/subscriptions/default/resourceGroups/default/providers/Microsoft.ApiManagement/service/%s/apis?api-version=2024-05-01",
61-
baseUrl, serviceName,
62-
)
56+
for primaryKey := range primaryKeyMatchesUnique {
6357
s1 := detectors.Result{
6458
DetectorType: detectorspb.DetectorType_AzureDirectManagementKey,
6559
Raw: []byte(baseUrl),
66-
RawV2: []byte(baseUrl + resMatch),
67-
Redacted: baseUrl,
60+
RawV2: []byte(baseUrl + primaryKey),
6861
}
6962

7063
if verify {
@@ -73,9 +66,9 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
7366
client = defaultClient
7467
}
7568

76-
isVerified, verificationErr := s.verifyMatch(ctx, client, url, resMatch)
69+
isVerified, verificationErr := s.verifyMatch(ctx, client, baseUrl, serviceName, primaryKey)
7770
s1.Verified = isVerified
78-
s1.SetVerificationError(verificationErr, resMatch)
71+
s1.SetVerificationError(verificationErr, primaryKey)
7972
}
8073

8174
results = append(results, s1)
@@ -88,19 +81,19 @@ func (s Scanner) FromData(ctx context.Context, verify bool, data []byte) (result
8881
return results, nil
8982
}
9083

91-
func (s Scanner) IsFalsePositive(_ detectors.Result) (bool, string) {
92-
return false, ""
93-
}
94-
9584
func (s Scanner) Type() detectorspb.DetectorType {
9685
return detectorspb.DetectorType_AzureDirectManagementKey
9786
}
9887

9988
func (s Scanner) Description() string {
100-
return "The Azure Management API is a RESTful interface for managing Azure resources programmatically through Azure Resource Manager (ARM), supporting automation with tools like Azure CLI and PowerShell. An Azure Management Direct Access API Key enables secure, non-interactive authentication, allowing direct access to manage resources via Azure Active Directory (AAD)."
89+
return "Azure API Management provides a direct management REST API for performing operations on selected entities, such as users, groups, products, and subscriptions."
10190
}
10291

103-
func (s Scanner) verifyMatch(ctx context.Context, client *http.Client, url, key string) (bool, error) {
92+
func (s Scanner) verifyMatch(ctx context.Context, client *http.Client, baseUrl, serviceName, key string) (bool, error) {
93+
url := fmt.Sprintf(
94+
"%s/subscriptions/default/resourceGroups/default/providers/Microsoft.ApiManagement/service/%s/apis?api-version=2024-05-01",
95+
baseUrl, serviceName,
96+
)
10497
accessToken, err := generateAccessToken(key)
10598
if err != nil {
10699
return false, err
@@ -129,8 +122,8 @@ func (s Scanner) verifyMatch(ctx context.Context, client *http.Client, url, key
129122

130123
// https://learn.microsoft.com/en-us/rest/api/apimanagement/apimanagementrest/azure-api-management-rest-api-authentication
131124
func generateAccessToken(key string) (string, error) {
132-
expiry := time.Now().UTC().Add(time.Minute).Format(time.RFC3339Nano)
133-
expiry = expiry[:27] + "Z" // 7 decimals precision for miliseconds
125+
expiry := time.Now().UTC().Add(5 * time.Second).Format(RFC3339WithoutMicroseconds) // expires in 5 seconds
126+
expiry = expiry + ".0000000Z" // 7 decimals microsecond's precision is must for access token
134127

135128
// Construct the string-to-sign
136129
stringToSign := fmt.Sprintf("integration\n%s", expiry)

pkg/detectors/azuredirectmanagementkey/azuredirectmanagementkey_integration_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ func TestAzureDirectManagementAPIKey_FromChunk(t *testing.T) {
2525
if err != nil {
2626
t.Fatalf("could not get test secrets from GCP: %s", err)
2727
}
28-
url := testSecrets.MustGetField("AZUREMANAGEMENTAPI_URL")
29-
secret := testSecrets.MustGetField("AZUREMANAGEMENTAPI_KEY")
30-
inactiveSecret := testSecrets.MustGetField("AZUREMANAGEMENTAPI_KEY_INACTIVE")
28+
url := testSecrets.MustGetField("AZUREDIRECTMANAGEMENTAPI_URL")
29+
secret := testSecrets.MustGetField("AZUREDIRECTMANAGEMENTAPI_KEY")
30+
inactiveSecret := testSecrets.MustGetField("AZUREDIRECTMANAGEMENTAPI_KEY_INACTIVE")
3131

3232
type args struct {
3333
ctx context.Context
@@ -104,8 +104,7 @@ func TestAzureDirectManagementAPIKey_FromChunk(t *testing.T) {
104104
t.Fatalf("wantVerificationError = %v, verification error = %v", tt.wantVerificationErr, got[i].VerificationError())
105105
}
106106
}
107-
ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "RawV2", "Raw", "Redacted", "verificationError")
108-
107+
ignoreOpts := cmpopts.IgnoreFields(detectors.Result{}, "Raw", "RawV2", "Redacted", "verificationError")
109108
if diff := cmp.Diff(got, tt.want, ignoreOpts); diff != "" {
110109
t.Errorf("AzureDirectManagementAPIKey.FromData() %s diff: (-got +want)\n%s", tt.name, diff)
111110
}

0 commit comments

Comments
 (0)