Skip to content

Commit 437e6d3

Browse files
committed
feat(detectors): create azure_entra base package
feat(azure): finish pending items for review
1 parent d408849 commit 437e6d3

17 files changed

+1285
-402
lines changed

go.mod

-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ replace github.com/STARRY-S/zip => github.com/STARRY-S/zip v0.1.0
1818
require (
1919
cloud.google.com/go/secretmanager v1.14.2
2020
cloud.google.com/go/storage v1.47.0
21-
github.com/Azure/go-autorest/autorest/azure/auth v0.5.13
2221
github.com/AzureAD/microsoft-authentication-library-for-go v1.3.1
2322
github.com/BobuSumisu/aho-corasick v1.0.3
2423
github.com/TheZeroSlave/zapsentry v1.23.0
@@ -136,13 +135,6 @@ require (
136135
github.com/99designs/go-keychain v0.0.0-20191008050251-8e49817e8af4 // indirect
137136
github.com/99designs/keyring v1.2.2 // indirect
138137
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
139-
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
140-
github.com/Azure/go-autorest/autorest v0.11.28 // indirect
141-
github.com/Azure/go-autorest/autorest/adal v0.9.22 // indirect
142-
github.com/Azure/go-autorest/autorest/azure/cli v0.4.6 // indirect
143-
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
144-
github.com/Azure/go-autorest/logger v0.2.1 // indirect
145-
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
146138
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
147139
github.com/DataDog/zstd v1.5.5 // indirect
148140
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.24.1 // indirect
@@ -186,7 +178,6 @@ require (
186178
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
187179
github.com/danieljoos/wincred v1.1.2 // indirect
188180
github.com/davecgh/go-spew v1.1.1 // indirect
189-
github.com/dimchansky/utfbom v1.1.1 // indirect
190181
github.com/distribution/reference v0.6.0 // indirect
191182
github.com/dlclark/regexp2 v1.4.0 // indirect
192183
github.com/docker/cli v27.1.1+incompatible // indirect
@@ -221,7 +212,6 @@ require (
221212
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
222213
github.com/golang/snappy v0.0.4 // indirect
223214
github.com/google/flatbuffers v23.5.26+incompatible // indirect
224-
github.com/google/go-github/v62 v62.0.0 // indirect
225215
github.com/google/go-querystring v1.1.0 // indirect
226216
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7 // indirect
227217
github.com/google/s2a-go v0.1.8 // indirect

go.sum

+6-206
Large diffs are not rendered by default.

pkg/detectors/azure/azure.go

-92
This file was deleted.

pkg/detectors/azure/azure_test.go

-90
This file was deleted.

pkg/detectors/azure_entra/common.go

+127
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
package azure_entra
2+
3+
import (
4+
"fmt"
5+
"io"
6+
"net/http"
7+
"strings"
8+
9+
regexp "github.com/wasilibs/go-re2"
10+
"golang.org/x/sync/singleflight"
11+
12+
"github.com/trufflesecurity/trufflehog/v3/pkg/cache/simple"
13+
"github.com/trufflesecurity/trufflehog/v3/pkg/context"
14+
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
15+
)
16+
17+
const uuidStr = `[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}`
18+
19+
var (
20+
// Tenants can be identified with a UUID or an `*.onmicrosoft.com` domain.
21+
//
22+
// See:
23+
// https://learn.microsoft.com/en-us/partner-center/account-settings/find-ids-and-domain-names#find-the-microsoft-azure-ad-tenant-id-and-primary-domain-name
24+
// https://learn.microsoft.com/en-us/microsoft-365/admin/setup/domains-faq?view=o365-worldwide#why-do-i-have-an--onmicrosoft-com--domain
25+
tenantIdPat = regexp.MustCompile(fmt.Sprintf(
26+
//language=regexp
27+
`(?i)(?:(?:login\.microsoftonline\.com/|(?:login|sts)\.windows\.net/|(?:t[ae]n[ae]nt(?:[ ._-]?id)?|\btid)(?:.|\s){0,60}?)(%s)|https?://(%s)|X-AnchorMailbox(?:.|\s){0,60}?@(%s))`,
28+
uuidStr,
29+
uuidStr,
30+
uuidStr,
31+
))
32+
tenantOnMicrosoftPat = regexp.MustCompile(`([\w-]+\.onmicrosoft\.com)`)
33+
34+
clientIdPat = regexp.MustCompile(fmt.Sprintf(
35+
`(?i)(?:(?:app(?:lication)?|client)(?:[ ._-]?id)?|username| -u)(?:.|\s){0,45}?(%s)`, uuidStr))
36+
)
37+
38+
// FindTenantIdMatches returns a list of potential tenant IDs in the provided |data|.
39+
func FindTenantIdMatches(data string) map[string]struct{} {
40+
uniqueMatches := make(map[string]struct{})
41+
42+
for _, match := range tenantIdPat.FindAllStringSubmatch(data, -1) {
43+
var m string
44+
if match[1] != "" {
45+
m = strings.ToLower(match[1])
46+
} else if match[2] != "" {
47+
m = strings.ToLower(match[2])
48+
} else if match[3] != "" {
49+
m = strings.ToLower(match[3])
50+
}
51+
if _, ok := detectors.UuidFalsePositives[detectors.FalsePositive(m)]; ok {
52+
continue
53+
}
54+
uniqueMatches[m] = struct{}{}
55+
}
56+
for _, match := range tenantOnMicrosoftPat.FindAllStringSubmatch(data, -1) {
57+
uniqueMatches[match[1]] = struct{}{}
58+
}
59+
return uniqueMatches
60+
}
61+
62+
// FindClientIdMatches returns a list of potential client UUIDs in the provided |data|.
63+
func FindClientIdMatches(data string) map[string]struct{} {
64+
uniqueMatches := make(map[string]struct{})
65+
for _, match := range clientIdPat.FindAllStringSubmatch(data, -1) {
66+
m := strings.ToLower(match[1])
67+
if _, ok := detectors.UuidFalsePositives[detectors.FalsePositive(m)]; ok {
68+
continue
69+
}
70+
uniqueMatches[m] = struct{}{}
71+
}
72+
return uniqueMatches
73+
}
74+
75+
var (
76+
tenantCache = simple.NewCache[bool]()
77+
tenantGroup singleflight.Group
78+
)
79+
80+
// TenantExists returns whether the tenant exists according to Microsoft's well-known OpenID endpoint.
81+
func TenantExists(ctx context.Context, client *http.Client, tenant string) bool {
82+
// Use cached value where possible.
83+
if tenantExists, isCached := tenantCache.Get(tenant); isCached {
84+
return tenantExists
85+
}
86+
87+
// https://www.codingexplorations.com/blog/understanding-singleflight-in-golang-a-solution-for-eliminating-redundant-work
88+
tenantExists, _, _ := tenantGroup.Do(tenant, func() (interface{}, error) {
89+
result := queryTenant(ctx, client, tenant)
90+
tenantCache.Set(tenant, result)
91+
return result, nil
92+
})
93+
94+
return tenantExists.(bool)
95+
}
96+
97+
func queryTenant(ctx context.Context, client *http.Client, tenant string) bool {
98+
logger := ctx.Logger().WithName("azure").WithValues("tenant", tenant)
99+
100+
tenantUrl := fmt.Sprintf("https://login.microsoftonline.com/%s/.well-known/openid-configuration", tenant)
101+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, tenantUrl, nil)
102+
if err != nil {
103+
return false
104+
}
105+
106+
res, err := client.Do(req)
107+
if err != nil {
108+
logger.Error(err, "Failed to check if tenant exists")
109+
return false
110+
}
111+
defer func() {
112+
_, _ = io.Copy(io.Discard, res.Body)
113+
_ = res.Body.Close()
114+
}()
115+
116+
switch res.StatusCode {
117+
case http.StatusOK:
118+
return true
119+
case http.StatusBadRequest:
120+
logger.V(4).Info("Tenant does not exist.")
121+
return false
122+
default:
123+
bodyBytes, _ := io.ReadAll(res.Body)
124+
logger.Error(nil, "WARNING: Unexpected response when checking if tenant exists", "status_code", res.StatusCode, "body", string(bodyBytes))
125+
return false
126+
}
127+
}

0 commit comments

Comments
 (0)