Skip to content

Commit

Permalink
PMM-11315 Changes, refactor.
Browse files Browse the repository at this point in the history
  • Loading branch information
JiriCtvrtka committed Oct 2, 2024
1 parent 15e11f9 commit 1a70691
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 24 deletions.
22 changes: 7 additions & 15 deletions api-tests/server/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ package server
import (
"bytes"
"crypto/md5" //nolint:gosec
"crypto/rand"
"encoding/base64"
"encoding/json"
"fmt"
"io"
Expand All @@ -38,6 +36,7 @@ import (
pmmapitests "github.com/percona/pmm/api-tests"
serverClient "github.com/percona/pmm/api/server/v1/json/client"
server "github.com/percona/pmm/api/server/v1/json/client/server_service"
stringsgen "github.com/percona/pmm/managed/utils/strings"
)

const (
Expand Down Expand Up @@ -360,23 +359,13 @@ func setRole(t *testing.T, userID int, role string) {
require.Equalf(t, http.StatusOK, resp.StatusCode, "failed to set role for user, response: %s", b)
}

func generateRandomString(length int) (string, error) {
buffer := make([]byte, length)
_, err := rand.Read(buffer)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buffer)[:length], nil
}

func TestServiceAccountPermissions(t *testing.T) {
// service account role options: viewer, editor, admin
// service token role options: editor, admin
// basic auth format is skipped, endpoint /auth/serviceaccount (to get info about currently used token in request) requires Bearer authorization
// service_token:token format could be used in pmm-agent and pmm-admin (its transformed into Bearer authorization)
postfix, err := generateRandomString(256)
nodeName, err := stringsgen.GenerateRandomString(256)
require.NoError(t, err)
nodeName := fmt.Sprintf("test-node-%s", postfix)

viewerNodeName := fmt.Sprintf("%s-viewer", nodeName)
viewerAccountID := createServiceAccountWithRole(t, "Viewer", viewerNodeName)
Expand Down Expand Up @@ -633,9 +622,12 @@ func deleteServiceToken(t *testing.T, serviceAccountID, serviceTokenID int) {
}

func sanitizeSAName(name string) string {
if len(name) <= 190 {
fmt.Println(name)
if len(name) <= 185 {
return name
}

return fmt.Sprintf("%s%x", name[:158], md5.Sum([]byte(name[158:]))) //nolint:gosec
res := fmt.Sprintf("%s%x", name[:153], md5.Sum([]byte(name[153:]))) //nolint:gosec
fmt.Println(res)
return res
}
7 changes: 4 additions & 3 deletions managed/services/grafana/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,15 +673,15 @@ type serviceToken struct {
Role string `json:"role"`
}

// Max length of service account name is 190 chars (default limit in Grafana Postgres DB).
// Max length of service account name is 185 chars (limit in Grafana Postgres DB for 190 chars).
// Sanitizing, ensure its length by hashing postfix when length is exceeded.
// MD5 is used because it has fixed length 32 chars.
func sanitizeSAName(name string) string {
if len(name) <= 190 {
if len(name) <= 185 {
return name
}

return fmt.Sprintf("%s%x", name[:158], md5.Sum([]byte(name[158:]))) //nolint:gosec
return fmt.Sprintf("%s%x", name[:153], md5.Sum([]byte(name[153:]))) //nolint:gosec
}

func (c *Client) createServiceAccount(ctx context.Context, role role, nodeName string, reregister bool, authHeaders http.Header) (int, error) {
Expand All @@ -690,6 +690,7 @@ func (c *Client) createServiceAccount(ctx context.Context, role role, nodeName s
}

serviceAccountName := fmt.Sprintf("%s-%s", pmmServiceAccountName, nodeName)
fmt.Println(sanitizeSAName(serviceAccountName))
b, err := json.Marshal(serviceAccount{Name: sanitizeSAName(serviceAccountName), Role: role.String(), Force: reregister})
if err != nil {
return 0, errors.WithStack(err)
Expand Down
18 changes: 12 additions & 6 deletions managed/services/grafana/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import (
"testing"
"time"

stringsgen "github.com/percona/pmm/managed/utils/strings"
"github.com/pkg/errors"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -144,8 +145,11 @@ func TestClient(t *testing.T) {
})

t.Run(fmt.Sprintf("Service token auth %s", role.String()), func(t *testing.T) {
nodeName := fmt.Sprintf("test-node-%s", role)
name, err := stringsgen.GenerateRandomString(256)
require.NoError(t, err)
nodeName := fmt.Sprintf("%s-%s", name, role)
serviceAccountID, err := c.createServiceAccount(ctx, role, nodeName, true, authHeaders)
fmt.Println(serviceAccountID)
require.NoError(t, err)
defer func() {
err := c.deleteServiceAccount(ctx, serviceAccountID, authHeaders)
Expand Down Expand Up @@ -235,13 +239,15 @@ func TestClient(t *testing.T) {
})
}

func Test_sanitizeNodeName(t *testing.T) {
func Test_sanitizeSAName(t *testing.T) {
// max possible length without hashing
len190 := "verylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongnodenameverylongn"
require.Equal(t, len190, sanitizeSAName(len190))
len185, err := stringsgen.GenerateRandomString(185)
require.NoError(t, err)
require.Equal(t, len185, sanitizeSAName(len185))

// too long length - postfix hashed
len200 := fmt.Sprintf("%s1234567890", len190)
len200, err := stringsgen.GenerateRandomString(200)
require.NoError(t, err)
len200sanitized := sanitizeSAName(len200)
require.Equal(t, fmt.Sprintf("%s%s", len200[:158], len200sanitized[158:]), len200sanitized)
require.Equal(t, fmt.Sprintf("%s%s", len200[:153], len200sanitized[153:]), len200sanitized)
}
32 changes: 32 additions & 0 deletions managed/utils/strings/generate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2023 Percona LLC
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

// Package stringsgen provides functions to generate random strings.
package stringsgen

import (
"crypto/rand"
"encoding/base64"
)

// GenerateRandomString returns random string with given length.
func GenerateRandomString(length int) (string, error) {
buffer := make([]byte, length)
_, err := rand.Read(buffer)
if err != nil {
return "", err
}
return base64.URLEncoding.EncodeToString(buffer)[:length], nil
}

0 comments on commit 1a70691

Please sign in to comment.