feat(AzureDNS): add a test for federated SPT

Signed-off-by: Igor Beliakov <demtis.register@gmail.com>
This commit is contained in:
Igor Beliakov 2022-11-17 17:42:05 +01:00
parent efae037cec
commit 964f4bbd8d

View File

@ -9,10 +9,16 @@ this directory.
package azuredns
import (
"encoding/json"
"io"
"net/http"
"net/http/httptest"
"os"
"testing"
"time"
"github.com/Azure/go-autorest/autorest/adal"
"github.com/Azure/go-autorest/autorest/azure"
v1 "github.com/cert-manager/cert-manager/pkg/apis/acme/v1"
"github.com/cert-manager/cert-manager/pkg/issuer/acme/dns/util"
"github.com/stretchr/testify/assert"
@ -77,3 +83,119 @@ func TestInvalidAzureDns(t *testing.T) {
_, err := NewDNSProviderCredentials("invalid env", "cid", "secret", "", "", "", "", util.RecursiveNameservers, false, &v1.AzureManagedIdentity{})
assert.Error(t, err)
}
func populateFederatedToken(t *testing.T, filename string, content string) {
t.Helper()
f, err := os.Create(filename)
if err != nil {
assert.FailNow(t, err.Error())
}
if _, err := io.WriteString(f, content); err != nil {
assert.FailNow(t, err.Error())
}
if err := f.Close(); err != nil {
assert.FailNow(t, err.Error())
}
}
func TestGetAuthorizationFederatedSPT(t *testing.T) {
// Create a file that will be used to store a federated token
f, err := os.CreateTemp("", "")
if err != nil {
assert.FailNow(t, err.Error())
}
defer os.Remove(f.Name())
// Close the file to simplify logic within populateFederatedToken helper
if err := f.Close(); err != nil {
assert.FailNow(t, err.Error())
}
// The initial federated token is never used, so we don't care about the value yet
// Though, it's a requirement from adal to have a non-empty value set
populateFederatedToken(t, f.Name(), "random-jwt")
// Prepare environment variables adal will rely on. Skip changes for some envs if they are already defined (=live environment)
// Envs themselves are described here: https://azure.github.io/azure-workload-identity/docs/installation/mutating-admission-webhook.html
if os.Getenv("AZURE_TENANT_ID") == "" {
t.Setenv("AZURE_TENANT_ID", "fakeTenantID")
}
if os.Getenv("AZURE_CLIENT_ID") == "" {
t.Setenv("AZURE_CLIENT_ID", "fakeClientID")
}
t.Setenv("AZURE_FEDERATED_TOKEN_FILE", f.Name())
t.Run("token refresh", func(t *testing.T) {
// Basically, we want one token to be exchanged for the other (key and value respectively)
tokens := map[string]string{
"initialFederatedToken": "initialAccessToken",
"refreshedFederatedToken": "refreshedAccessToken",
}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
assert.FailNow(t, err.Error())
}
w.Header().Set("Content-Type", "application/json")
receivedFederatedToken := r.FormValue("client_assertion")
accessToken := adal.Token{AccessToken: tokens[receivedFederatedToken]}
if err := json.NewEncoder(w).Encode(accessToken); err != nil {
assert.FailNow(t, err.Error())
}
// Expected format: http://<server>/<tenant-ID>/oauth2/token?api-version=1.0
assert.Contains(t, r.RequestURI, os.Getenv("AZURE_TENANT_ID"), "URI should contain the tenant ID exposed through env variable")
assert.Equal(t, os.Getenv("AZURE_CLIENT_ID"), r.FormValue("client_id"), "client_id should match the value exposed through env variable")
}))
defer ts.Close()
ambient := true
env := azure.Environment{ActiveDirectoryEndpoint: ts.URL, ResourceManagerEndpoint: ts.URL}
managedIdentity := &v1.AzureManagedIdentity{ClientID: ""}
spt, err := getAuthorization(env, "", "", "", "", ambient, managedIdentity)
assert.NoError(t, err)
for federatedToken, accessToken := range tokens {
populateFederatedToken(t, f.Name(), federatedToken)
assert.NoError(t, spt.Refresh(), "Token refresh failed")
assert.Equal(t, accessToken, spt.Token().AccessToken, "Access token should have been set to a value returned by the webserver")
}
})
t.Run("clientID overrides through managedIdentity section", func(t *testing.T) {
managedIdentity := &v1.AzureManagedIdentity{ClientID: "anotherClientID"}
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseForm(); err != nil {
assert.FailNow(t, err.Error())
}
w.Header().Set("Content-Type", "application/json")
accessToken := adal.Token{AccessToken: "abc"}
if err := json.NewEncoder(w).Encode(accessToken); err != nil {
assert.FailNow(t, err.Error())
}
assert.Equal(t, managedIdentity.ClientID, r.FormValue("client_id"), "client_id should match the value passed through managedIdentity section")
}))
defer ts.Close()
ambient := true
env := azure.Environment{ActiveDirectoryEndpoint: ts.URL, ResourceManagerEndpoint: ts.URL}
spt, err := getAuthorization(env, "", "", "", "", ambient, managedIdentity)
assert.NoError(t, err)
assert.NoError(t, spt.Refresh(), "Token refresh failed")
})
}