diff --git a/api/acl.go b/api/acl.go index ad3bfbf2f56..c393505faf0 100644 --- a/api/acl.go +++ b/api/acl.go @@ -754,7 +754,7 @@ type ACLAuthMethod struct { // ACLAuthMethodTokenLocalityGlobal for convenience. TokenLocality string - // TokenNameFormat defines the template to use when building the token name + // TokenNameFormat defines the HIL template to use when building the token name TokenNameFormat string // MaxTokenTTL is the maximum life of a token created by this method. diff --git a/command/acl_auth_method_create.go b/command/acl_auth_method_create.go index 0f0609273ee..fac957ebbeb 100644 --- a/command/acl_auth_method_create.go +++ b/command/acl_auth_method_create.go @@ -65,7 +65,8 @@ ACL Auth Method Create Options: either 'local' or 'global'. -token-name-format - Sets the token format for the authenticated users. + Sets the token format for the authenticated users. This can be lightly + templated using HIL ${foo} syntax. Defaults to ${auth_type}-${auth_name} -default Specifies whether this auth method should be treated as a default one in diff --git a/command/acl_auth_method_update.go b/command/acl_auth_method_update.go index 436ad048bbf..6a13e009eb4 100644 --- a/command/acl_auth_method_update.go +++ b/command/acl_auth_method_update.go @@ -61,7 +61,8 @@ ACL Auth Method Update Options: either 'local' or 'global'. -token-name-format - Sets the token format for the authenticated users. + Sets the token format for the authenticated users. This can be lightly + templated using HIL ${foo} syntax. Defaults to ${auth_type}-${auth_name} -default Specifies whether this auth method should be treated as a default one in diff --git a/nomad/acl_endpoint.go b/nomad/acl_endpoint.go index 3b864542db1..23e3aa10d40 100644 --- a/nomad/acl_endpoint.go +++ b/nomad/acl_endpoint.go @@ -2972,7 +2972,7 @@ func formatTokenName(format, authType, authName string, claims map[string]string claimMappings["value."+k] = v } - tokenName, err := auth.InterpolateHIL(format, claimMappings, true) + tokenName, err := auth.InterpolateHIL(format, claimMappings, false) if err != nil { return "", err } diff --git a/nomad/acl_endpoint_test.go b/nomad/acl_endpoint_test.go index 72fd3bbae25..86eccf6fe58 100644 --- a/nomad/acl_endpoint_test.go +++ b/nomad/acl_endpoint_test.go @@ -3764,12 +3764,14 @@ func TestACL_Login(t *testing.T) { iat := time.Now().Unix() nbf := time.Now().Unix() exp := time.Now().Add(time.Hour).Unix() + user := "John" testToken, testPubKey, err := mock.SampleJWTokenWithKeys(jwt.MapClaims{ "http://nomad.internal/policies": []string{"engineering"}, "http://nomad.internal/roles": []string{"engineering"}, "iat": iat, "nbf": nbf, "exp": exp, + "sub": user, "iss": "nomad test suite", "aud": []string{"sales", "engineering"}, }, nil) @@ -3810,7 +3812,9 @@ func TestACL_Login(t *testing.T) { mockedAuthMethod.Config.BoundIssuer = []string{"nomad test suite"} mockedAuthMethod.Config.ExpirationLeeway = time.Duration(3600) mockedAuthMethod.Config.ClockSkewLeeway = time.Duration(3600) - mockedAuthMethod.Config.ClaimMappings = map[string]string{} + mockedAuthMethod.Config.ClaimMappings = map[string]string{ + "sub": "user", + } mockedAuthMethod.Config.ListClaimMappings = map[string]string{ "http://nomad.internal/roles": "roles", "http://nomad.internal/policies": "policies", @@ -3877,6 +3881,7 @@ func TestACL_Login(t *testing.T) { must.Len(t, 1, completeAuthResp4.ACLToken.Roles) must.Eq(t, mockACLRole.Name, completeAuthResp4.ACLToken.Roles[0].Name) must.Eq(t, mockACLRole.ID, completeAuthResp4.ACLToken.Roles[0].ID) + must.Eq(t, mockedAuthMethod.Type+"-"+mockedAuthMethod.Name, completeAuthResp4.ACLToken.Name) // Create a binding rule which generates management tokens. This should // override the other rules, giving us a management token when we next @@ -3901,8 +3906,26 @@ func TestACL_Login(t *testing.T) { var completeAuthResp5 structs.ACLLoginResponse err = msgpackrpc.CallWithCodec(codec, structs.ACLLoginRPCMethod, &loginReq5, &completeAuthResp5) must.NoError(t, err) - must.NotNil(t, completeAuthResp4.ACLToken) + must.NotNil(t, completeAuthResp5.ACLToken) must.Len(t, 0, completeAuthResp5.ACLToken.Policies) must.Len(t, 0, completeAuthResp5.ACLToken.Roles) must.Eq(t, structs.ACLManagementToken, completeAuthResp5.ACLToken.Type) + + // Change the token name format + mockedAuthMethod.TokenNameFormat = "${auth_type}-${auth_name}-${value.user}" + must.NoError(t, testServer.fsm.State().UpsertACLAuthMethods(60, []*structs.ACLAuthMethod{mockedAuthMethod})) + + loginReq6 := structs.ACLLoginRequest{ + AuthMethodName: mockedAuthMethod.Name, + LoginToken: testToken, + WriteRequest: structs.WriteRequest{ + Region: DefaultRegion, + }, + } + + var completeAuthResp6 structs.ACLLoginResponse + err = msgpackrpc.CallWithCodec(codec, structs.ACLLoginRPCMethod, &loginReq6, &completeAuthResp6) + must.NoError(t, err) + must.NotNil(t, completeAuthResp6.ACLToken) + must.Eq(t, mockedAuthMethod.Type+"-"+mockedAuthMethod.Name+"-"+user, completeAuthResp6.ACLToken.Name) }