Skip to content

Commit 9dceed1

Browse files
tkAcharya007Harness
authored andcommitted
feat: [STO-9557]: add auth support for STO using ng-manager secret (#124)
* feat: add global exemption management APIs and CLI commands * refactor: simplify STO authentication by using NG manager secret instead of STO token
1 parent cb3da05 commit 9dceed1

File tree

2 files changed

+13
-71
lines changed

2 files changed

+13
-71
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ Toolset Name: `scs`
191191
Toolset Name: `sto`
192192

193193
- `frontend_all_issues_list`: List and filter security issues in Harness STO by target, pipeline, tool, severity, exemption status, and type.
194-
194+
- `global_exemptions`: List all global exemptions in Harness STO.
195+
- `promote_exemption`: Promote a specific exemption to a global exemption.
196+
- `approve_exemption`: Approve a specific exemption.
195197

196198
#### Logs Toolset
197199

pkg/modules/sto.go

Lines changed: 10 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@ package modules
22

33
import (
44
"context"
5-
"encoding/json"
6-
"fmt"
7-
"io"
85
"log/slog"
96
"net/http"
107
"time"
@@ -74,13 +71,14 @@ func (m *STOModule) IsDefault() bool {
7471
// RegisterSTO registers the Security Test Orchestration toolset
7572
func RegisterSTO(config *config.Config, tsg *toolsets.ToolsetGroup) error {
7673
baseURL := utils.BuildServiceURL(config, config.STOSvcBaseURL, config.BaseURL, "sto")
77-
secret := config.STOSvcSecret
78-
c := &http.Client{
79-
Timeout: 30 * time.Second,
74+
// Do not use STO API key, use NG Manager secret as STO calls ACL & ng-manager APIs with the token
75+
principalSecret := config.NgManagerSecret
76+
c, err := utils.CreateClient(baseURL, config, principalSecret, 30*time.Second)
77+
if err != nil {
78+
return err
8079
}
8180

8281
baseURLPrincipal := utils.BuildServiceURL(config, config.NgManagerBaseURL, config.BaseURL, "ng/api")
83-
principalSecret := config.NgManagerSecret
8482

8583
cPrincipal, err := utils.CreateClient(baseURLPrincipal, config, principalSecret)
8684
if err != nil {
@@ -89,17 +87,14 @@ func RegisterSTO(config *config.Config, tsg *toolsets.ToolsetGroup) error {
8987
}
9088
principalClient := &client.PrincipalService{Client: cPrincipal}
9189

92-
stoAPIKey := ""
93-
tokenURL := fmt.Sprintf("%s/api/v2/token?accountId=%s&audience=sto-plugin", baseURL, config.AccountID)
94-
if config.Internal {
95-
stoAPIKey, err = retrieveSTOToken(tokenURL, secret)
90+
requestEditorFn := func(ctx context.Context, req *http.Request) error {
91+
k, v, err := c.AuthProvider.GetHeader(ctx)
9692
if err != nil {
97-
slog.Warn("Failed to retrieve STO token. STO toolset will be partially operational", "error", err)
98-
// Continue without the token
93+
return err
9994
}
95+
req.Header.Set(k, v)
96+
return nil
10097
}
101-
102-
requestEditorFn := createSTORequestEditor(config, stoAPIKey)
10398
stoClient, err := sto.NewClientWithResponses(baseURL, sto.WithHTTPClient(c),
10499
sto.WithRequestEditorFn(requestEditorFn))
105100
if err != nil {
@@ -116,58 +111,3 @@ func RegisterSTO(config *config.Config, tsg *toolsets.ToolsetGroup) error {
116111
tsg.AddToolset(sto)
117112
return nil
118113
}
119-
120-
// createSTORequestEditor creates a request editor function for STO API requests
121-
func createSTORequestEditor(config *config.Config, stoAPIKey string) func(context.Context, *http.Request) error {
122-
return func(ctx context.Context, req *http.Request) error {
123-
//Add STO plugin token as Authorization header if internal mode
124-
if config.Internal && stoAPIKey != "" {
125-
req.Header.Set("Authorization", "ApiKey "+stoAPIKey)
126-
} else {
127-
req.Header.Set("x-api-key", config.APIKey)
128-
}
129-
return nil
130-
}
131-
}
132-
133-
// retrieveSTOToken retrieves the STO plugin token from the token endpoint
134-
func retrieveSTOToken(tokenURL, secret string) (string, error) {
135-
stoTokenReq, err := http.NewRequestWithContext(context.Background(), http.MethodGet, tokenURL, nil)
136-
if err != nil {
137-
return "", fmt.Errorf("failed to create STO token request: %w", err)
138-
}
139-
140-
stoTokenReq.Header.Set("X-Harness-Token", secret)
141-
142-
// Try with a fresh HTTP client to avoid any client configuration issues
143-
httpClient := &http.Client{
144-
Timeout: 30 * time.Second,
145-
}
146-
147-
stoTokenResp, err := httpClient.Do(stoTokenReq)
148-
if err != nil {
149-
return "", fmt.Errorf("failed to call STO token endpoint: %w", err)
150-
}
151-
152-
defer stoTokenResp.Body.Close()
153-
154-
if stoTokenResp.StatusCode >= 300 {
155-
return "", fmt.Errorf("failed to retrieve STO token, status: %s", stoTokenResp.Status)
156-
}
157-
158-
bodyBytes, err := io.ReadAll(stoTokenResp.Body)
159-
if err != nil {
160-
return "", fmt.Errorf("failed to read STO token response: %w", err)
161-
}
162-
163-
var tokenJSON map[string]interface{}
164-
if err := json.Unmarshal(bodyBytes, &tokenJSON); err == nil {
165-
if v, ok := tokenJSON["token"].(string); ok && v != "" {
166-
return v, nil
167-
} else if v, ok := tokenJSON["apiKey"].(string); ok && v != "" {
168-
return v, nil
169-
}
170-
}
171-
172-
return "", nil
173-
}

0 commit comments

Comments
 (0)