Skip to content

Commit

Permalink
Add tests to validate login using the authmethods issues the desired …
Browse files Browse the repository at this point in the history
…token.
  • Loading branch information
Ashwin Venkatesh committed Mar 5, 2022
1 parent 4d22fcb commit 6f384d3
Showing 1 changed file with 199 additions and 0 deletions.
199 changes: 199 additions & 0 deletions control-plane/subcommand/server-acl-init/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2405,6 +2405,160 @@ func TestRun_PoliciesAndBindingRulesACLLoginInSecondaryDatacenterDuringFederatio
}
}

// Test that server-acl-init used the local auth method to create the desired token.
// The test works by running the login command and then ensuring that:
// * The token returned has the correct policy for the component.
// * The token returned has the correct role for the component.
func TestRun_ValidateLoginToken_TokensCreatedByLocalAuthMethod(t *testing.T) {
t.Parallel()

cases := []struct {
ComponentName string
TokenFlags []string
Roles []string
}{
{
ComponentName: "controller",
TokenFlags: []string{"-create-controller-token"},
Roles: []string{resourcePrefix + "-controller-acl-role"},
},
}
for _, c := range cases {
t.Run(c.ComponentName, func(t *testing.T) {
k8s, testSvr := completeSetup(t)
defer testSvr.Stop()
_, jwtToken := setUpK8sServiceAccount(t, k8s, ns)
k8sMockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/json")
if r != nil && r.URL.Path == "/apis/authentication.k8s.io/v1/tokenreviews" && r.Method == "POST" {
w.Write([]byte(tokenReviewsResponse(fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName), ns)))
}
if r != nil && r.URL.Path == fmt.Sprintf("/api/v1/namespaces/%s/serviceaccounts/%s", ns, fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName)) &&
r.Method == "GET" {
w.Write([]byte(serviceAccountGetResponse(fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName), ns)))
}
}))
t.Cleanup(k8sMockServer.Close)

// Run the command.
ui := cli.NewMockUi()
cmd := Command{
UI: ui,
clientset: k8s,
}
cmdArgs := append([]string{
"-timeout=500ms",
"-resource-prefix=" + resourcePrefix,
"-k8s-namespace=" + ns,
"-auth-method-host=" + k8sMockServer.URL,
"-server-address", strings.Split(testSvr.HTTPAddr, ":")[0],
"-server-port", strings.Split(testSvr.HTTPAddr, ":")[1],
}, c.TokenFlags...)
cmd.init()
responseCode := cmd.Run(cmdArgs)
require.Equal(t, 0, responseCode, ui.ErrorWriter.String())

// Do the login.
req := &api.ACLLoginParams{
AuthMethod: "release-name-" + componentAuthMethod,
BearerToken: jwtToken,
Meta: map[string]string{},
}
tokenlessConfig := &api.Config{
Address: testSvr.HTTPAddr,
}
client, err := api.NewClient(tokenlessConfig)
require.NoError(t, err)
tok, _, err := client.ACL().Login(req, &api.WriteOptions{})
require.NoError(t, err)
require.Equal(t, len(tok.Roles), len(c.Roles))
for _, role := range tok.Roles {
require.Contains(t, c.Roles, role.Name)
}
})
}
}

// Test that server-acl-init used the global auth method to create the desired token.
// The test works by running the login command and then ensuring that:
// * The token returned has the correct policy for the component.
// * The token returned has the correct role for the component.
func TestRun_ValidateLoginToken_TokensCreatedByGlobalAuthMethod(t *testing.T) {
t.Parallel()

cases := []struct {
ComponentName string
TokenFlags []string
Roles []string
}{
{
ComponentName: "controller",
TokenFlags: []string{"-create-controller-token"},
Roles: []string{resourcePrefix + "-controller-acl-role-dc2"},
},
}
for _, c := range cases {
t.Run(c.ComponentName, func(t *testing.T) {
bootToken := "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
tokenFile := common.WriteTempFile(t, bootToken)
k8s, _, consulHTTPAddr, cleanup := mockReplicatedSetup(t, bootToken)
defer cleanup()

_, jwtToken := setUpK8sServiceAccount(t, k8s, ns)
k8sMockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("content-type", "application/json")
if r != nil && r.URL.Path == "/apis/authentication.k8s.io/v1/tokenreviews" && r.Method == "POST" {
w.Write([]byte(tokenReviewsResponse(fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName), ns)))
}
if r != nil && r.URL.Path == fmt.Sprintf("/api/v1/namespaces/%s/serviceaccounts/%s", ns, fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName)) &&
r.Method == "GET" {
w.Write([]byte(serviceAccountGetResponse(fmt.Sprintf("%s-%s", resourcePrefix, c.ComponentName), ns)))
}
}))
t.Cleanup(k8sMockServer.Close)

// Run the command.
ui := cli.NewMockUi()
cmd := Command{
UI: ui,
clientset: k8s,
}
cmdArgs := append([]string{
"-federation",
"-timeout=1m",
"-resource-prefix=" + resourcePrefix,
"-k8s-namespace=" + ns,
"-acl-replication-token-file", tokenFile,
"-auth-method-host=" + k8sMockServer.URL,
"-server-address", strings.Split(consulHTTPAddr, ":")[0],
"-server-port", strings.Split(consulHTTPAddr, ":")[1],
}, c.TokenFlags...)
cmd.init()
responseCode := cmd.Run(cmdArgs)
require.Equal(t, 0, responseCode, ui.ErrorWriter.String())

// Do the login.
req := &api.ACLLoginParams{
AuthMethod: "release-name-" + componentAuthMethod + "-dc2",
BearerToken: jwtToken,
Meta: map[string]string{},
}
tokenlessConfig := &api.Config{
Address: consulHTTPAddr,
Datacenter: "dc1",
}
client, err := api.NewClient(tokenlessConfig)
require.NoError(t, err)
tok, _, err := client.ACL().Login(req, &api.WriteOptions{})
require.NoError(t, err)
require.Equal(t, len(tok.Roles), len(c.Roles))
for _, role := range tok.Roles {
require.Contains(t, c.Roles, role.Name)
}
})
}
}

// Test that the component auth method gets created.
func TestRun_ComponentAuthMethod(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -2749,5 +2903,50 @@ func policyExists(t require.TestingT, name string, client *api.Client) *api.ACLP
return policy
}

func tokenReviewsResponse(name, ns string) string {
return fmt.Sprintf(`{
"kind": "TokenReview",
"apiVersion": "authentication.k8s.io/v1",
"metadata": {
"creationTimestamp": null
},
"spec": {
"token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IiJ9.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImtoYWtpLWFyYWNobmlkLWNvbnN1bC1jb25uZWN0LWluamVjdG9yLWF1dGhtZXRob2Qtc3ZjLWFjY29obmRidiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJraGFraS1hcmFjaG5pZC1jb25zdWwtY29ubmVjdC1pbmplY3Rvci1hdXRobWV0aG9kLXN2Yy1hY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQudWlkIjoiN2U5NWUxMjktZTQ3My0xMWU5LThmYWEtNDIwMTBhODAwMTIyIiwic3ViIjoic3lzdGVtOnNlcnZpY2VhY2NvdW50OmRlZmF1bHQ6a2hha2ktYXJhY2huaWQtY29uc3VsLWNvbm5lY3QtaW5qZWN0b3ItYXV0aG1ldGhvZC1zdmMtYWNjb3VudCJ9.Yi63MMtzh5MBWKKd3a7dzCJjTITE15ikFy_Tnpdk_AwdwA9J4AMSGEeHN5vWtCuuFjo_lMJqBBPHkK2AqbnoFUj9m5CopWyqICJQlvEOP4fUQ-Rc0W1P_JjU1rZERHG39b5TMLgKPQguyhaiZEJ6CjVtm9wUTagrgiuqYV2iUqLuF6SYNm6SrKtkPS-lqIO-u7C06wVk5m5uqwIVQNpZSIC_5Ls5aLmyZU3nHvH-V7E3HmBhVyZAB76jgKB0TyVX1IOskt9PDFarNtU3suZyCjvqC-UJA6sYeySe4dBNKsKlSZ6YuxUUmn1Rgv32YMdImnsWg8khf-zJvqgWk7B5EA"
},
"status": {
"authenticated": true,
"user": {
"username": "system:serviceaccount:%s:%s",
"uid": "9ff51ff4-557e-11e9-9687-48e6c8b8ecb5",
"groups": [
"system:serviceaccounts",
"system:serviceaccounts:%s",
"system:authenticated"
]
}
}
}`, ns, name, ns)
}

func serviceAccountGetResponse(name, ns string) string {
return fmt.Sprintf(`{
"kind": "ServiceAccount",
"apiVersion": "v1",
"metadata": {
"name": "%s",
"namespace": "%s",
"selfLink": "/api/v1/namespaces/%s/serviceaccounts/%s",
"uid": "9ff51ff4-557e-11e9-9687-48e6c8b8ecb5",
"resourceVersion": "2101",
"creationTimestamp": "2019-04-02T19:36:34Z"
},
"secrets": [
{
"name": "%s-token-m9cvn"
}
]
}`, name, ns, ns, name, name)
}

var serviceAccountCACert = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURDekNDQWZPZ0F3SUJBZ0lRS3pzN05qbDlIczZYYzhFWG91MjVoekFOQmdrcWhraUc5dzBCQVFzRkFEQXYKTVMwd0t3WURWUVFERXlRMU9XVTJaR00wTVMweU1EaG1MVFF3T1RVdFlUSTRPUzB4Wm1NM01EQmhZekZqWXpndwpIaGNOTVRrd05qQTNNVEF4TnpNeFdoY05NalF3TmpBMU1URXhOek14V2pBdk1TMHdLd1lEVlFRREV5UTFPV1UyClpHTTBNUzB5TURobUxUUXdPVFV0WVRJNE9TMHhabU0zTURCaFl6RmpZemd3Z2dFaU1BMEdDU3FHU0liM0RRRUIKQVFVQUE0SUJEd0F3Z2dFS0FvSUJBUURaakh6d3FvZnpUcEdwYzBNZElDUzdldXZmdWpVS0UzUEMvYXBmREFnQgo0anpFRktBNzgvOStLVUd3L2MvMFNIZVNRaE4rYThnd2xIUm5BejFOSmNmT0lYeTRkd2VVdU9rQWlGeEg4cGh0CkVDd2tlTk83ejhEb1Y4Y2VtaW5DUkhHamFSbW9NeHBaN2cycFpBSk5aZVB4aTN5MWFOa0ZBWGU5Z1NVU2RqUloKUlhZa2E3d2gyQU85azJkbEdGQVlCK3Qzdld3SjZ0d2pHMFR0S1FyaFlNOU9kMS9vTjBFMDFMekJjWnV4a04xawo4Z2ZJSHk3Yk9GQ0JNMldURURXLzBhQXZjQVByTzhETHFESis2TWpjM3I3K3psemw4YVFzcGIwUzA4cFZ6a2k1CkR6Ly84M2t5dTBwaEp1aWo1ZUI4OFY3VWZQWHhYRi9FdFY2ZnZyTDdNTjRmQWdNQkFBR2pJekFoTUE0R0ExVWQKRHdFQi93UUVBd0lDQkRBUEJnTlZIUk1CQWY4RUJUQURBUUgvTUEwR0NTcUdTSWIzRFFFQkN3VUFBNElCQVFCdgpRc2FHNnFsY2FSa3RKMHpHaHh4SjUyTm5SVjJHY0lZUGVOM1p2MlZYZTNNTDNWZDZHMzJQVjdsSU9oangzS21BCi91TWg2TmhxQnpzZWtrVHowUHVDM3dKeU0yT0dvblZRaXNGbHF4OXNGUTNmVTJtSUdYQ2Ezd0M4ZS9xUDhCSFMKdzcvVmVBN2x6bWozVFFSRS9XMFUwWkdlb0F4bjliNkp0VDBpTXVjWXZQMGhYS1RQQldsbnpJaWphbVU1MHIyWQo3aWEwNjVVZzJ4VU41RkxYL3Z4T0EzeTRyanBraldvVlFjdTFwOFRaclZvTTNkc0dGV3AxMGZETVJpQUhUdk9ICloyM2pHdWs2cm45RFVIQzJ4UGozd0NUbWQ4U0dFSm9WMzFub0pWNWRWZVE5MHd1c1h6M3ZURzdmaWNLbnZIRlMKeHRyNVBTd0gxRHVzWWZWYUdIMk8KLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo="
var serviceAccountToken = "ZXlKaGJHY2lPaUpTVXpJMU5pSXNJbXRwWkNJNklpSjkuZXlKcGMzTWlPaUpyZFdKbGNtNWxkR1Z6TDNObGNuWnBZMlZoWTJOdmRXNTBJaXdpYTNWaVpYSnVaWFJsY3k1cGJ5OXpaWEoyYVdObFlXTmpiM1Z1ZEM5dVlXMWxjM0JoWTJVaU9pSmtaV1poZFd4MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WldOeVpYUXVibUZ0WlNJNkltdG9ZV3RwTFdGeVlXTm9ibWxrTFdOdmJuTjFiQzFqYjI1dVpXTjBMV2x1YW1WamRHOXlMV0YxZEdodFpYUm9iMlF0YzNaakxXRmpZMjlvYm1SaWRpSXNJbXQxWW1WeWJtVjBaWE11YVc4dmMyVnlkbWxqWldGalkyOTFiblF2YzJWeWRtbGpaUzFoWTJOdmRXNTBMbTVoYldVaU9pSnJhR0ZyYVMxaGNtRmphRzVwWkMxamIyNXpkV3d0WTI5dWJtVmpkQzFwYm1wbFkzUnZjaTFoZFhSb2JXVjBhRzlrTFhOMll5MWhZMk52ZFc1MElpd2lhM1ZpWlhKdVpYUmxjeTVwYnk5elpYSjJhV05sWVdOamIzVnVkQzl6WlhKMmFXTmxMV0ZqWTI5MWJuUXVkV2xrSWpvaU4yVTVOV1V4TWprdFpUUTNNeTB4TVdVNUxUaG1ZV0V0TkRJd01UQmhPREF3TVRJeUlpd2ljM1ZpSWpvaWMzbHpkR1Z0T25ObGNuWnBZMlZoWTJOdmRXNTBPbVJsWm1GMWJIUTZhMmhoYTJrdFlYSmhZMmh1YVdRdFkyOXVjM1ZzTFdOdmJtNWxZM1F0YVc1cVpXTjBiM0l0WVhWMGFHMWxkR2h2WkMxemRtTXRZV05qYjNWdWRDSjkuWWk2M01NdHpoNU1CV0tLZDNhN2R6Q0pqVElURTE1aWtGeV9UbnBka19Bd2R3QTlKNEFNU0dFZUhONXZXdEN1dUZqb19sTUpxQkJQSGtLMkFxYm5vRlVqOW01Q29wV3lxSUNKUWx2RU9QNGZVUS1SYzBXMVBfSmpVMXJaRVJIRzM5YjVUTUxnS1BRZ3V5aGFpWkVKNkNqVnRtOXdVVGFncmdpdXFZVjJpVXFMdUY2U1lObTZTckt0a1BTLWxxSU8tdTdDMDZ3Vms1bTV1cXdJVlFOcFpTSUNfNUxzNWFMbXlaVTNuSHZILVY3RTNIbUJoVnlaQUI3NmpnS0IwVHlWWDFJT3NrdDlQREZhck50VTNzdVp5Q2p2cUMtVUpBNnNZZXlTZTRkQk5Lc0tsU1o2WXV4VVVtbjFSZ3YzMllNZEltbnNXZzhraGYtekp2cWdXazdCNUVB"

0 comments on commit 6f384d3

Please sign in to comment.