@@ -3,26 +3,26 @@ package okta
3
3
import (
4
4
"context"
5
5
"fmt"
6
- "io"
7
6
"net/http"
8
- "strings"
9
7
10
8
regexp "github.com/wasilibs/go-re2"
11
9
12
10
"github.com/trufflesecurity/trufflehog/v3/pkg/detectors"
13
11
"github.com/trufflesecurity/trufflehog/v3/pkg/pb/detectorspb"
14
12
)
15
13
16
- type Scanner struct {
14
+ type Scanner struct {
15
+ client * http.Client
17
16
detectors.DefaultMultiPartCredentialProvider
18
17
}
19
18
20
19
// Ensure the Scanner satisfies the interface at compile time.
21
20
var _ detectors.Detector = (* Scanner )(nil )
22
21
23
22
var (
24
- domainPat = regexp .MustCompile (`\b[a-z0-9-]{1,40}\.okta(?:preview|-emea){0,1}\.com\b` )
25
- tokenPat = regexp .MustCompile (`\b00[a-zA-Z0-9_-]{40}\b` )
23
+ defaultClient = detectors .DetectorHttpClientWithNoLocalAddresses
24
+ domainPat = regexp .MustCompile (`\b[a-z0-9-]{1,40}\.okta(?:preview|-emea){0,1}\.com\b` )
25
+ tokenPat = regexp .MustCompile (`\b00[a-zA-Z0-9_-]{40}\b` )
26
26
// TODO: Oauth client secrets
27
27
)
28
28
@@ -34,55 +34,76 @@ func (s Scanner) Keywords() []string {
34
34
35
35
// FromData will find and optionally verify Okta secrets in a given set of bytes.
36
36
func (s Scanner ) FromData (ctx context.Context , verify bool , data []byte ) (results []detectors.Result , err error ) {
37
- for _ , tokenMatch := range tokenPat .FindAll (data , - 1 ) {
38
- token := string (tokenMatch )
37
+ dataStr := string (data )
39
38
40
- for _ , domainMatch := range domainPat .FindAll (data , - 1 ) {
41
- domain := string (domainMatch )
39
+ var uniqueTokens , uniqueDomains = make (map [string ]struct {}), make (map [string ]struct {})
42
40
43
- result := detectors.Result {
41
+ for _ , matches := range tokenPat .FindAllStringSubmatch (dataStr , - 1 ) {
42
+ uniqueTokens [matches [0 ]] = struct {}{}
43
+ }
44
+
45
+ for _ , matches := range domainPat .FindAllStringSubmatch (dataStr , - 1 ) {
46
+ uniqueDomains [matches [0 ]] = struct {}{}
47
+ }
48
+
49
+ for token := range uniqueTokens {
50
+ for domain := range uniqueDomains {
51
+ s1 := detectors.Result {
44
52
DetectorType : detectorspb .DetectorType_Okta ,
45
53
Raw : []byte (token ),
46
54
RawV2 : []byte (fmt .Sprintf ("%s:%s" , domain , token )),
47
55
}
48
56
49
57
if verify {
50
- // curl -v -X GET \
51
- // -H "Accept: application/json" \
52
- // -H "Content-Type: application/json" \
53
- // -H "Authorization: Bearer token" \
54
- // "https://subdomain.okta.com/api/v1/users/me"
55
- //
56
-
57
- url := fmt .Sprintf ("https://%s/api/v1/users/me" , domain )
58
- req , err := http .NewRequestWithContext (ctx , "GET" , url , nil )
59
- if err != nil {
60
- return results , err
58
+ client := s .client
59
+ if client == nil {
60
+ client = defaultClient
61
61
}
62
- req .Header .Set ("Accept" , "application/json" )
63
- req .Header .Set ("Content-Type" , "application/json" )
64
- req .Header .Set ("Authorization" , fmt .Sprintf ("SSWS %s" , token ))
65
62
66
- resp , err := detectors .DetectorHttpClientWithNoLocalAddresses .Do (req )
67
- if err != nil {
68
- continue
69
- }
70
- defer resp .Body .Close ()
71
- if resp .StatusCode >= 200 && resp .StatusCode < 300 {
72
- body , _ := io .ReadAll (resp .Body )
73
- if strings .Contains (string (body ), "activated" ) {
74
- result .Verified = true
75
- }
76
- }
63
+ isVerified , verificationErr := verifyOktaToken (ctx , client , domain , token )
64
+ s1 .Verified = isVerified
65
+ s1 .SetVerificationError (verificationErr )
77
66
}
78
67
79
- results = append (results , result )
68
+ results = append (results , s1 )
80
69
}
81
70
}
82
71
83
72
return
84
73
}
85
74
75
+ func verifyOktaToken (ctx context.Context , client * http.Client , domain string , token string ) (bool , error ) {
76
+ // curl -v -X GET \
77
+ // -H "Accept: application/json" \
78
+ // -H "Content-Type: application/json" \
79
+ // -H "Authorization: SSWS token" \
80
+ // "https://subdomain.okta.com/api/v1/users/me"
81
+
82
+ url := fmt .Sprintf ("https://%s/api/v1/users/me" , domain )
83
+ req , err := http .NewRequestWithContext (ctx , http .MethodGet , url , nil )
84
+ if err != nil {
85
+ return false , err
86
+ }
87
+ req .Header .Set ("Accept" , "application/json" )
88
+ req .Header .Set ("Content-Type" , "application/json" )
89
+ req .Header .Set ("Authorization" , fmt .Sprintf ("SSWS %s" , token ))
90
+
91
+ resp , err := client .Do (req )
92
+ if err != nil {
93
+ return false , err
94
+ }
95
+ defer resp .Body .Close ()
96
+
97
+ switch resp .StatusCode {
98
+ case http .StatusOK :
99
+ return true , nil
100
+ case http .StatusUnauthorized , http .StatusForbidden :
101
+ return false , nil
102
+ default :
103
+ return false , fmt .Errorf ("unexpected status code: %d" , resp .StatusCode )
104
+ }
105
+ }
106
+
86
107
func (s Scanner ) Type () detectorspb.DetectorType {
87
108
return detectorspb .DetectorType_Okta
88
109
}
0 commit comments