Skip to content

Commit 9041f37

Browse files
authored
Migrate terraform handler to OIDCRegistry (#83)
1 parent 9ee1a78 commit 9041f37

2 files changed

Lines changed: 64 additions & 18 deletions

File tree

internal/handlers/oidc_handling_test.go

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1225,7 +1225,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
12251225
},
12261226
urlMocks: []mockHttpRequest{},
12271227
expectedLogLines: []string{
1228-
"registered aws OIDC credentials for terraform registry: terraform.example.com",
1228+
"registered aws OIDC credentials for terraform registry: https://terraform.example.com",
12291229
},
12301230
urlsToAuthenticate: []string{
12311231
"https://terraform.example.com/some-package",
@@ -1268,7 +1268,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
12681268
},
12691269
urlMocks: []mockHttpRequest{},
12701270
expectedLogLines: []string{
1271-
"registered jfrog OIDC credentials for terraform registry: jfrog.example.com",
1271+
"registered jfrog OIDC credentials for terraform registry: https://jfrog.example.com",
12721272
},
12731273
urlsToAuthenticate: []string{
12741274
"https://jfrog.example.com/some-package",
@@ -1291,7 +1291,7 @@ func TestOIDCURLsAreAuthenticated(t *testing.T) {
12911291
},
12921292
urlMocks: []mockHttpRequest{},
12931293
expectedLogLines: []string{
1294-
"registered cloudsmith OIDC credentials for terraform registry: cloudsmith.example.com",
1294+
"registered cloudsmith OIDC credentials for terraform registry: https://cloudsmith.example.com",
12951295
},
12961296
urlsToAuthenticate: []string{
12971297
"https://cloudsmith.example.com/some-package",
@@ -1492,3 +1492,56 @@ func TestNPMOIDCSameHostDifferentPaths(t *testing.T) {
14921492
reqB = handleRequestAndClose(handler, reqB, nil)
14931493
assertHasTokenAuth(t, reqB, "Bearer", "__token_B__", "feed-B should use token B")
14941494
}
1495+
1496+
// TestTerraformOIDCSameHostDifferentPaths verifies that two terraform OIDC
1497+
// credentials on the same host with different URL paths do not collide — each
1498+
// request is authenticated with the credential whose path is the longest
1499+
// prefix match.
1500+
func TestTerraformOIDCSameHostDifferentPaths(t *testing.T) {
1501+
httpmock.Activate()
1502+
defer httpmock.DeactivateAndReset()
1503+
1504+
tenantA := "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
1505+
tenantB := "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"
1506+
clientId := "87654321-4321-4321-4321-210987654321"
1507+
1508+
tokenUrl := "https://token.actions.example.com" //nolint:gosec // test URL
1509+
httpmock.RegisterResponder("GET", tokenUrl,
1510+
httpmock.NewStringResponder(200, `{"count":1,"value":"sometoken"}`))
1511+
1512+
// Two different Azure tenants → two different tokens
1513+
httpmock.RegisterResponder("POST", fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantA),
1514+
httpmock.NewStringResponder(200, `{"access_token":"__token_A__","expires_in":3600,"token_type":"Bearer"}`))
1515+
httpmock.RegisterResponder("POST", fmt.Sprintf("https://login.microsoftonline.com/%s/oauth2/v2.0/token", tenantB),
1516+
httpmock.NewStringResponder(200, `{"access_token":"__token_B__","expires_in":3600,"token_type":"Bearer"}`))
1517+
1518+
t.Setenv("ACTIONS_ID_TOKEN_REQUEST_URL", tokenUrl)
1519+
t.Setenv("ACTIONS_ID_TOKEN_REQUEST_TOKEN", "sometoken")
1520+
1521+
creds := config.Credentials{
1522+
config.Credential{
1523+
"type": "terraform_registry",
1524+
"url": "https://terraform.example.com/org/feed-A",
1525+
"tenant-id": tenantA,
1526+
"client-id": clientId,
1527+
},
1528+
config.Credential{
1529+
"type": "terraform_registry",
1530+
"url": "https://terraform.example.com/org/feed-B",
1531+
"tenant-id": tenantB,
1532+
"client-id": clientId,
1533+
},
1534+
}
1535+
1536+
handler := NewTerraformRegistryHandler(creds)
1537+
1538+
// Request to feed-A path should get token A
1539+
reqA := httptest.NewRequest("GET", "https://terraform.example.com/org/feed-A/v1/providers/org/name", nil)
1540+
reqA = handleRequestAndClose(handler, reqA, nil)
1541+
assertHasTokenAuth(t, reqA, "Bearer", "__token_A__", "feed-A should use token A")
1542+
1543+
// Request to feed-B path should get token B
1544+
reqB := httptest.NewRequest("GET", "https://terraform.example.com/org/feed-B/v1/providers/org/name", nil)
1545+
reqB = handleRequestAndClose(handler, reqB, nil)
1546+
assertHasTokenAuth(t, reqB, "Bearer", "__token_B__", "feed-B should use token B")
1547+
}

internal/handlers/terraform_registry.go

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"net/http"
55
"sort"
66
"strings"
7-
"sync"
87

98
"github.com/elazarl/goproxy"
109

@@ -15,9 +14,8 @@ import (
1514
)
1615

1716
type TerraformRegistryHandler struct {
18-
credentials []terraformRegistryCredentials
19-
oidcCredentials map[string]*oidc.OIDCCredential
20-
mutex sync.RWMutex
17+
credentials []terraformRegistryCredentials
18+
oidcRegistry *oidc.OIDCRegistry
2119
}
2220

2321
type terraformRegistryCredentials struct {
@@ -28,26 +26,21 @@ type terraformRegistryCredentials struct {
2826

2927
func NewTerraformRegistryHandler(credentials config.Credentials) *TerraformRegistryHandler {
3028
handler := TerraformRegistryHandler{
31-
credentials: []terraformRegistryCredentials{},
32-
oidcCredentials: make(map[string]*oidc.OIDCCredential),
29+
credentials: []terraformRegistryCredentials{},
30+
oidcRegistry: oidc.NewOIDCRegistry(),
3331
}
3432

3533
for _, credential := range credentials {
3634
if credential["type"] != "terraform_registry" {
3735
continue
3836
}
3937

40-
host := credential.Host()
41-
42-
oidcCredential, _ := oidc.CreateOIDCCredential(credential)
43-
if oidcCredential != nil {
44-
if host != "" {
45-
handler.oidcCredentials[host] = oidcCredential
46-
logging.RequestLogf(nil, "registered %s OIDC credentials for terraform registry: %s", oidcCredential.Provider(), host)
47-
}
38+
// OIDC credentials are not used as static credentials.
39+
if oidcCred, _, _ := handler.oidcRegistry.Register(credential, []string{"url"}, "terraform registry"); oidcCred != nil {
4840
continue
4941
}
5042

43+
host := credential.Host()
5144
token := credential.GetString("token")
5245
url := credential.GetString("url")
5346

@@ -84,7 +77,7 @@ func (h *TerraformRegistryHandler) HandleRequest(request *http.Request, context
8477
}
8578

8679
// Try OIDC credentials first
87-
if oidc.TryAuthOIDCRequestWithPrefix(&h.mutex, h.oidcCredentials, request, context) {
80+
if h.oidcRegistry.TryAuth(request, context) {
8881
return request, nil
8982
}
9083

0 commit comments

Comments
 (0)