diff --git a/pkg/internal/pop/msal_confidential.go b/pkg/internal/pop/msal_confidential.go index d31f879b..e14a6f74 100644 --- a/pkg/internal/pop/msal_confidential.go +++ b/pkg/internal/pop/msal_confidential.go @@ -21,11 +21,16 @@ func AcquirePoPTokenConfidential( clientID, tenantID string, options *azcore.ClientOptions, + popKeyFunc func() (*SwKey, error), ) (string, int64, error) { - popKey, err := GetSwPoPKey() + if popKeyFunc == nil { + popKeyFunc = GetSwPoPKey + } + popKey, err := popKeyFunc() if err != nil { - return "", -1, err + return "", -1, fmt.Errorf("unable to get PoP key: %w", err) } + authnScheme := &PoPAuthenticationScheme{ Host: popClaims["u"], PoPKey: popKey, diff --git a/pkg/internal/pop/msal_confidential_test.go b/pkg/internal/pop/msal_confidential_test.go index 039115eb..43cd670a 100644 --- a/pkg/internal/pop/msal_confidential_test.go +++ b/pkg/internal/pop/msal_confidential_test.go @@ -116,6 +116,7 @@ func TestAcquirePoPTokenConfidential(t *testing.T) { tc.p.clientID, tc.p.tenantID, &clientOpts, + GetSwPoPKey, ) defer vcrRecorder.Stop() if tc.expectedError != nil { diff --git a/pkg/internal/pop/poptoken.go b/pkg/internal/pop/poptoken.go index 61447bec..f644efe8 100644 --- a/pkg/internal/pop/poptoken.go +++ b/pkg/internal/pop/poptoken.go @@ -27,7 +27,7 @@ type PoPKey interface { } // software based pop key implementation of PoPKey -type swKey struct { +type SwKey struct { key *rsa.PrivateKey keyID string jwk string @@ -35,38 +35,38 @@ type swKey struct { reqCnf string } -// Alg returns the algorithm used to encrypt/sign the swKey -func (swk *swKey) Alg() string { +// Alg returns the algorithm used to encrypt/sign the SwKey +func (swk *SwKey) Alg() string { return "RS256" } -// KeyID returns the keyID of the swKey, representing the key used to sign the swKey -func (swk *swKey) KeyID() string { +// KeyID returns the keyID of the SwKey, representing the key used to sign the SwKey +func (swk *SwKey) KeyID() string { return swk.keyID } -// JWK returns the JSON Web Key of the given swKey -func (swk *swKey) JWK() string { +// JWK returns the JSON Web Key of the given SwKey +func (swk *SwKey) JWK() string { return swk.jwk } -// JWKThumbprint returns the JWK thumbprint of the given swKey -func (swk *swKey) JWKThumbprint() string { +// JWKThumbprint returns the JWK thumbprint of the given SwKey +func (swk *SwKey) JWKThumbprint() string { return swk.jwkTP } -// ReqCnf returns the req_cnf claim to send to AAD for the given swKey -func (swk *swKey) ReqCnf() string { +// ReqCnf returns the req_cnf claim to send to AAD for the given SwKey +func (swk *SwKey) ReqCnf() string { return swk.reqCnf } -// Sign uses the given swKey to sign the given payload and returns the signed payload -func (swk *swKey) Sign(payload []byte) ([]byte, error) { +// Sign uses the given SwKey to sign the given payload and returns the signed payload +func (swk *SwKey) Sign(payload []byte) ([]byte, error) { return swk.key.Sign(rand.Reader, payload, crypto.SHA256) } -// init initializes the given swKey using the given private key -func (swk *swKey) init(key *rsa.PrivateKey) { +// init initializes the given SwKey using the given private key +func (swk *SwKey) init(key *rsa.PrivateKey) { swk.key = key eB64, nB64 := getRSAKeyExponentAndModulus(key) @@ -81,15 +81,15 @@ func (swk *swKey) init(key *rsa.PrivateKey) { swk.jwk = getJWK(eB64, nB64, swk.keyID) } -// generateSwKey generates a new swkey and initializes it with required fields before returning it -func generateSwKey(key *rsa.PrivateKey) (*swKey, error) { - swk := &swKey{} +// generateSwKey generates a new SwKey and initializes it with required fields before returning it +func generateSwKey(key *rsa.PrivateKey) (*SwKey, error) { + swk := &SwKey{} swk.init(key) return swk, nil } -// GetSwPoPKey generates a new PoP key that rotates every 8 hours and returns it -func GetSwPoPKey() (*swKey, error) { +// GetSwPoPKey generates a new PoP key returns it +func GetSwPoPKey() (*SwKey, error) { key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, fmt.Errorf("error generating RSA private key: %w", err) @@ -97,7 +97,7 @@ func GetSwPoPKey() (*swKey, error) { return GetSwPoPKeyWithRSAKey(key) } -func GetSwPoPKeyWithRSAKey(rsaKey *rsa.PrivateKey) (*swKey, error) { +func GetSwPoPKeyWithRSAKey(rsaKey *rsa.PrivateKey) (*SwKey, error) { key, err := generateSwKey(rsaKey) if err != nil { return nil, fmt.Errorf("unable to generate PoP key. err: %w", err) diff --git a/pkg/internal/token/serviceprincipaltokencertificate.go b/pkg/internal/token/serviceprincipaltokencertificate.go index 6010a595..148e4b30 100644 --- a/pkg/internal/token/serviceprincipaltokencertificate.go +++ b/pkg/internal/token/serviceprincipaltokencertificate.go @@ -91,6 +91,7 @@ func (p *servicePrincipalToken) getPoPTokenWithClientCert( p.clientID, p.tenantID, options, + pop.GetSwPoPKey, ) if err != nil { return "", -1, fmt.Errorf("failed to create service principal PoP token using certificate: %w", err) diff --git a/pkg/internal/token/serviceprincipaltokensecret.go b/pkg/internal/token/serviceprincipaltokensecret.go index 458dccf8..f58c74e0 100644 --- a/pkg/internal/token/serviceprincipaltokensecret.go +++ b/pkg/internal/token/serviceprincipaltokensecret.go @@ -70,6 +70,7 @@ func (p *servicePrincipalToken) getPoPTokenWithClientSecret( p.clientID, p.tenantID, options, + pop.GetSwPoPKey, ) if err != nil { return "", -1, fmt.Errorf("failed to create service principal PoP token using secret: %w", err) diff --git a/pkg/pop/msal_confidential.go b/pkg/pop/msal_confidential.go new file mode 100644 index 00000000..7a3d1431 --- /dev/null +++ b/pkg/pop/msal_confidential.go @@ -0,0 +1,9 @@ +package pop + +import ( + "github.com/Azure/kubelogin/pkg/internal/pop" +) + +// AcquirePoPTokenConfidential retrieves a Proof of Possession (PoP) token using confidential client credentials. +// It utilizes the internal pop.AcquirePoPTokenConfidential function to obtain the token. +var AcquirePoPTokenConfidential = pop.AcquirePoPTokenConfidential diff --git a/pkg/pop/poptoken.go b/pkg/pop/poptoken.go new file mode 100644 index 00000000..9f513a55 --- /dev/null +++ b/pkg/pop/poptoken.go @@ -0,0 +1,7 @@ +package pop + +import "github.com/Azure/kubelogin/pkg/internal/pop" + +// GetSwPoPKey retrieves a software Proof of Possession (PoP) key using RSA encryption. +// It utilizes the internal pop.GetSwPoPKey function to obtain the key. +var GetSwPoPKey = pop.GetSwPoPKey diff --git a/pkg/pop/types.go b/pkg/pop/types.go new file mode 100644 index 00000000..9793ae03 --- /dev/null +++ b/pkg/pop/types.go @@ -0,0 +1,12 @@ +package pop + +import ( + "github.com/Azure/kubelogin/pkg/internal/pop" +) + +// This is the MSAL implementation of AuthenticationScheme. +// For more details, see the MSAL repo interface: +// https://github.com/AzureAD/microsoft-authentication-library-for-go/blob/4a4dafcbcbd7d57a69ed3bc59760381232c2be9c/apps/internal/oauth/ops/authority/authority.go#L146 +type PoPAuthenticationScheme = pop.PoPAuthenticationScheme + +type SwKey = pop.SwKey