From d7ed8eb0361e4b97de7f4126d187b8e02812cc51 Mon Sep 17 00:00:00 2001
From: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
Date: Fri, 2 Feb 2024 11:12:05 +0000
Subject: [PATCH 1/2] Combine auth properties into GALASA_TOKEN and remove
client secret
Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
---
README.md | 15 +-
docs/generated/errors-list.md | 1 +
pkg/auth/authLogin_test.go | 36 +--
pkg/auth/authProperties.go | 67 +++---
pkg/auth/authProperties_test.go | 221 +++++-------------
.../templates/galasahome/galasactl.properties | 11 +-
pkg/errors/errorMessage.go | 1 +
7 files changed, 115 insertions(+), 237 deletions(-)
diff --git a/README.md b/README.md
index 833a9607..d1c8ab23 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,11 @@ The `--galasahome` command-line flag can override the `GALASA_HOME` environment
Note: If you change this to a non-existent and/or non-initialised folder path, then
you will have to create and re-initialise the folder using the `galasactl local init` command again. That command will respect the `GALASA_HOME` variable and will create the folder and initialise it were it not to exist.
+### GALASA_TOKEN
+In order to authenticate with a Galasa ecosystem, you will need to create a personal access token from the Galasa web user interface.
+
+Once a personal access token has been created, you can either store the token in the galasactl.properties file within your Galasa home folder, or set the token as an environment variable named `GALASA_TOKEN`.
+
## Syntax
The syntax is documented in generated documentation [here](docs/generated/galasactl.md)
@@ -95,17 +100,15 @@ If you wish the generated code to depend upon the very latest/bleeding-edge of g
Before interacting with a Galasa ecosystem using `galasactl`, you must be authenticated with it. The `auth login` command allows you to log in to an ecosystem provided by your `GALASA_BOOTSTRAP` environment variable or through the `--bootstrap` flag.
-Prior to running this command, you must have a `galasactl.properties` file in your `GALASA_HOME` directory, which is automatically created when running `galasactl local init`, that contains a set of `auth` properties with the following format:
+Prior to running this command, you must have a `galasactl.properties` file in your `GALASA_HOME` directory, which is automatically created when running `galasactl local init`, that contains a `GALASA_TOKEN` property with the following format:
```
-GALASA_CLIENT_ID=
-GALASA_SECRET=
-GALASA_ACCESS_TOKEN=
+GALASA_TOKEN=
```
-These properties can be retrieved by creating a new personal access token from a Galasa ecosystem's web user interface.
+A value for the `GALASA_TOKEN` property can be retrieved by creating a new personal access token from a Galasa ecosystem's web user interface.
-If you prefer, these variables can be set as environment variables instead of being read from this file.
+If you prefer, this property can be set as an environment variable instead of being read from this file.
On a successful login, a `bearer-token.json` file will be created in your `GALASA_HOME` directory. This file will contain a bearer token that `galasactl` will use to authenticate requests when communicating with a Galasa ecosystem.
diff --git a/docs/generated/errors-list.md b/docs/generated/errors-list.md
index 964a9b10..0a7a57e0 100644
--- a/docs/generated/errors-list.md
+++ b/docs/generated/errors-list.md
@@ -124,6 +124,7 @@ The `galasactl` tool can generate the following errors:
- GAL1122E: Authentication property {} is not available, which is needed to connect to the Galasa Ecosystem. It either needs to be in a file '{}' or set as an environment variable.
- GAL1123E: Failed to read 3270 terminal JSON because the content is in the wrong format. Reason: {}
- GAL1124E: Internal Failure. Terminal image could not be encoded into PNG format. Reason: {}
+- GAL1125E: Authentication property {} is invalid. Please ensure that it the value is made up of two parts that are separated by a '{}'.
- GAL1225E: Failed to open file '{}' cause: {}. Check that this file exists, and that you have read permissions.
- GAL1226E: Internal failure. Contents of gzip could be read, but not decoded. New gzip reader failed: file: {} error: {}
- GAL1227E: Internal failure. Contents of gzip could not be decoded. {} error: {}
diff --git a/pkg/auth/authLogin_test.go b/pkg/auth/authLogin_test.go
index 0aecfb9f..2048bd06 100644
--- a/pkg/auth/authLogin_test.go
+++ b/pkg/auth/authLogin_test.go
@@ -31,7 +31,6 @@ func NewAuthServletMock(t *testing.T, status int, mockResponse string) *httptest
requestBodyStr := string(requestBody)
assert.Contains(t, requestBodyStr, "client_id")
- assert.Contains(t, requestBodyStr, "secret")
assert.Contains(t, requestBodyStr, "refresh_token")
writer.Header().Set("Content-Type", "application/json")
@@ -95,12 +94,9 @@ func TestLoginCreatesBearerTokenFileContainingJWT(t *testing.T) {
galasactlPropertiesFilePath := mockGalasaHome.GetNativeFolderPath() + "/galasactl.properties"
mockClientId := "dummyId"
- mockSecret := "shhhh"
mockRefreshToken := "abcdefg"
- mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", mockClientId, mockSecret, mockRefreshToken))
+ tokenPropertyValue := mockRefreshToken + TOKEN_SEPARATOR + mockClientId
+ mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
mockResponse := `{"jwt":"blah"}`
server := NewAuthServletMock(t, 200, mockResponse)
@@ -130,12 +126,9 @@ func TestLoginWithFailedFileWriteReturnsError(t *testing.T) {
galasactlPropertiesFilePath := mockGalasaHome.GetNativeFolderPath() + "/galasactl.properties"
mockClientId := "dummyId"
- mockSecret := "shhhh"
mockRefreshToken := "abcdefg"
- mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", mockClientId, mockSecret, mockRefreshToken))
+ tokenPropertyValue := mockRefreshToken + TOKEN_SEPARATOR + mockClientId
+ mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
mockFileSystem.VirtualFunction_WriteTextFile = func(path string, contents string) error {
return errors.New("simulating a failed write operation")
@@ -164,13 +157,9 @@ func TestLoginWithFailedTokenRequestReturnsError(t *testing.T) {
galasactlPropertiesFilePath := mockGalasaHome.GetNativeFolderPath() + "/galasactl.properties"
mockClientId := "dummyId"
- mockSecret := "shhhh"
mockRefreshToken := "abcdefg"
-
- mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", mockClientId, mockSecret, mockRefreshToken))
+ tokenPropertyValue := mockRefreshToken + TOKEN_SEPARATOR + mockClientId
+ mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
mockResponse := `{"error":"something went wrong!"}`
server := NewAuthServletMock(t, 500, mockResponse)
@@ -194,11 +183,7 @@ func TestLoginWithMissingAuthPropertyReturnsError(t *testing.T) {
galasactlPropertiesFilePath := mockGalasaHome.GetNativeFolderPath() + "/galasactl.properties"
- mockClientId := "dummyId"
- mockSecret := "shhhh"
- mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n", mockClientId, mockSecret))
+ mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, "unknown.value=blah")
mockResponse := `{"jwt":"blah"}`
server := NewAuthServletMock(t, 200, mockResponse)
@@ -283,12 +268,9 @@ func TestGetAuthenticatedAPIClientWithUnavailableAPIContinuesWithoutToken(t *tes
galasactlPropertiesFilePath := mockGalasaHome.GetNativeFolderPath() + "/galasactl.properties"
mockClientId := "dummyId"
- mockSecret := "shhhh"
mockRefreshToken := "abcdefg"
- mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", mockClientId, mockSecret, mockRefreshToken))
+ tokenPropertyValue := mockRefreshToken + TOKEN_SEPARATOR + mockClientId
+ mockFileSystem.WriteTextFile(galasactlPropertiesFilePath, fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
server := NewAuthServletMock(t, 500, "")
defer server.Close()
diff --git a/pkg/auth/authProperties.go b/pkg/auth/authProperties.go
index 4de2b111..6fe16a0e 100644
--- a/pkg/auth/authProperties.go
+++ b/pkg/auth/authProperties.go
@@ -8,6 +8,7 @@ package auth
import (
"log"
"path/filepath"
+ "strings"
"github.com/galasa-dev/cli/pkg/files"
"github.com/galasa-dev/cli/pkg/galasaapi"
@@ -18,40 +19,39 @@ import (
)
const (
- CLIENT_ID_PROPERTY = "GALASA_CLIENT_ID"
- SECRET_PROPERTY = "GALASA_SECRET"
- ACCESS_TOKEN_PROPERTY = "GALASA_ACCESS_TOKEN"
+ TOKEN_PROPERTY = "GALASA_TOKEN"
+ TOKEN_SEPARATOR = ":"
)
// Gets authentication properties from the user's galasactl.properties file or from the environment or a mixture.
func GetAuthProperties(fileSystem files.FileSystem, galasaHome utils.GalasaHome, env utils.Environment) (galasaapi.AuthProperties, error) {
var err error = nil
+ authProperties := galasaapi.NewAuthProperties()
// Work out which file we we want to draw properties from.
galasactlPropertiesFilePath := filepath.Join(galasaHome.GetNativeFolderPath(), "galasactl.properties")
- // Get the file-based properties if we can
- authProperties, fileAccessErr := getAuthPropertiesFromFile(fileSystem, galasactlPropertiesFilePath, env)
- if fileAccessErr != nil {
- authProperties = *galasaapi.NewAuthProperties()
- }
+ // Get the file-based token property if we can
+ tokenProperty, fileAccessErr := getPropertyFromFile(fileSystem, galasactlPropertiesFilePath, env, TOKEN_PROPERTY)
- // We now have a structure which may be filled-in with values from the file.
- // Over-write those values if there is an environment variable set to do that.
- authProperties.SetClientId(getPropertyWithOverride(env, authProperties.GetClientId(), galasactlPropertiesFilePath, CLIENT_ID_PROPERTY))
- authProperties.SetRefreshToken(getPropertyWithOverride(env, authProperties.GetRefreshToken(), galasactlPropertiesFilePath, ACCESS_TOKEN_PROPERTY))
- authProperties.SetSecret(getPropertyWithOverride(env, authProperties.GetSecret(), galasactlPropertiesFilePath, SECRET_PROPERTY))
+ // Over-write the token property value if there is an environment variable set to do that.
+ tokenProperty = getPropertyWithOverride(env, tokenProperty, galasactlPropertiesFilePath, TOKEN_PROPERTY)
// Make sure all the properties have values that we need.
- err = checkPropertyIsSet(authProperties.GetClientId(), CLIENT_ID_PROPERTY, galasactlPropertiesFilePath, fileAccessErr)
+ err = checkPropertyIsSet(tokenProperty, TOKEN_PROPERTY, galasactlPropertiesFilePath, fileAccessErr)
if err == nil {
- err = checkPropertyIsSet(authProperties.GetRefreshToken(), ACCESS_TOKEN_PROPERTY, galasactlPropertiesFilePath, fileAccessErr)
+ var refreshToken string
+ var clientId string
+
+ // Get the authentication properties from the token
+ refreshToken, clientId, err = extractPropertiesFromToken(tokenProperty)
if err == nil {
- err = checkPropertyIsSet(authProperties.GetSecret(), SECRET_PROPERTY, galasactlPropertiesFilePath, fileAccessErr)
+ authProperties.SetClientId(clientId)
+ authProperties.SetRefreshToken(refreshToken)
}
}
- return authProperties, err
+ return *authProperties, err
}
func checkPropertyIsSet(propertyValue string, propertyName string, galasactlPropertiesFilePath string, fileAccessErr error) error {
@@ -84,24 +84,33 @@ func getPropertyWithOverride(env utils.Environment, valueFromFile string, filePa
return value
}
-// Gets authentication properties from the user's galasactl.properties file
-func getAuthPropertiesFromFile(fileSystem files.FileSystem, galasactlPropertiesFilePath string, env utils.Environment) (galasaapi.AuthProperties, error) {
+// Gets a property from the user's galasactl.properties file
+func getPropertyFromFile(fileSystem files.FileSystem, galasactlPropertiesFilePath string, env utils.Environment, propertyName string) (string, error) {
var err error = nil
- authProperties := galasaapi.NewAuthProperties()
-
var galasactlProperties props.JavaProperties
galasactlProperties, err = props.ReadPropertiesFile(fileSystem, galasactlPropertiesFilePath)
- if err == nil {
+ if err != nil {
+ err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_FAILED_TO_READ_FILE, galasactlPropertiesFilePath, err.Error())
+ }
- if err == nil {
- authProperties.SetClientId(galasactlProperties[CLIENT_ID_PROPERTY])
- authProperties.SetSecret(galasactlProperties[SECRET_PROPERTY])
- authProperties.SetRefreshToken(galasactlProperties[ACCESS_TOKEN_PROPERTY])
- }
+ return galasactlProperties[propertyName], err
+}
+
+func extractPropertiesFromToken(token string) (string, string, error) {
+ var err error
+ var refreshToken string
+ var clientId string
+
+ // The GALASA_TOKEN property should be in the form {GALASA_ACCESS_TOKEN}:{GALASA_CLIENT_ID},
+ // so it should split into two parts.
+ tokenParts := strings.Split(token, TOKEN_SEPARATOR)
+ if len(tokenParts) == 2 && tokenParts[0] != "" && tokenParts[1] != "" {
+ refreshToken = tokenParts[0]
+ clientId = tokenParts[1]
} else {
- err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_FAILED_TO_READ_FILE, galasactlPropertiesFilePath, err.Error())
+ err = galasaErrors.NewGalasaError(galasaErrors.GALASA_ERROR_BAD_TOKEN_PROPERTY_FORMAT, TOKEN_PROPERTY, TOKEN_SEPARATOR)
}
- return *authProperties, err
+ return refreshToken, clientId, err
}
diff --git a/pkg/auth/authProperties_test.go b/pkg/auth/authProperties_test.go
index 2c17c7c1..afb7aeeb 100644
--- a/pkg/auth/authProperties_test.go
+++ b/pkg/auth/authProperties_test.go
@@ -20,289 +20,173 @@ func TestGetAuthPropertiesWithValidPropertiesUnmarshalsAuthProperties(t *testing
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "dummyId"
- secretValue := "dummySecret"
accessTokenValue := "abc"
+ clientIdValue := "dummyId"
+ tokenPropertyValue := accessTokenValue + TOKEN_SEPARATOR + clientIdValue
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", clientIdValue, secretValue, accessTokenValue))
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
+
// When...
authProperties, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and all required properties are present")
+ assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and the token property is present")
assert.Equal(t, clientIdValue, authProperties.GetClientId())
- assert.Equal(t, secretValue, authProperties.GetSecret())
assert.Equal(t, accessTokenValue, authProperties.GetRefreshToken())
}
-func TestGetAuthPropertiesWithNoClientIdValidPropertiesUnmarshalsAuthPropertiesFails(t *testing.T) {
+func TestGetAuthPropertiesWithNoClientIdInTokenReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- secretValue := "dummySecret"
- accessTokenValue := "abc"
+ tokenPropertyValue := "this-is-my-access-token"
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- // "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s",
- // clientIdValue,
- secretValue, accessTokenValue))
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
+
// When...
_, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but the client id is missing from the file.")
- assert.Contains(t, err.Error(), "GAL1122E")
- assert.Contains(t, err.Error(), "GALASA_CLIENT_ID")
+ assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but is missing part of the token value.")
+ assert.Contains(t, err.Error(), "GAL1125E")
+ assert.Contains(t, err.Error(), "GALASA_TOKEN")
}
-func TestGetAuthPropertiesWithNoSecretIdValidPropertiesUnmarshalsAuthPropertiesFails(t *testing.T) {
+func TestGetAuthPropertiesWithSeparatorButNoClientIdReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "my-client-id"
- // secretValue := "dummySecret"
- accessTokenValue := "abc"
+ tokenPropertyValue := "my-token" + TOKEN_SEPARATOR
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- // "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s",
- clientIdValue,
- // secretValue,
- accessTokenValue))
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
+
// When...
_, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but the secret is missing from the file.")
- assert.Contains(t, err.Error(), "GAL1122E")
- assert.Contains(t, err.Error(), "GALASA_SECRET")
+ assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but is missing the client ID part of the token.")
+ assert.Contains(t, err.Error(), "GAL1125E")
+ assert.Contains(t, err.Error(), "GALASA_TOKEN")
}
-func TestGetAuthPropertiesWithNoRefreshTokenIdValidPropertiesUnmarshalsAuthPropertiesFails(t *testing.T) {
+func TestGetAuthPropertiesWithSeparatorButNoAccessTokenReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "my-client-id"
- secretValue := "dummySecret"
- // accessTokenValue := "abc"
+ tokenPropertyValue := TOKEN_SEPARATOR + "my-client-id"
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n",
- // "GALASA_ACCESS_TOKEN=%s",
- clientIdValue,
- secretValue,
- // accessTokenValue,
- ))
- // When...
- _, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
-
- // Then...
- assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but the secret is missing from the file.")
- assert.Contains(t, err.Error(), "GAL1122E")
- assert.Contains(t, err.Error(), "GALASA_ACCESS_TOKEN")
-}
-
-func TestGetAuthPropertiesWithEmptyGalasactlPropertiesReturnsError(t *testing.T) {
- // Given...
- mockFileSystem := files.NewMockFileSystem()
- mockEnvironment := utils.NewMockEnv()
- mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
-
- mockFileSystem.WriteTextFile(mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties", "")
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
// When...
_, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.NotNil(t, err, "Should return an error if the galasactl.properties is empty")
- assert.ErrorContains(t, err, "GAL1122E")
+ assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but is missing the access token part of the token.")
+ assert.Contains(t, err.Error(), "GAL1125E")
+ assert.Contains(t, err.Error(), "GALASA_TOKEN")
}
-func TestGetAuthPropertiesWithMissingPropertiesReturnsError(t *testing.T) {
+func TestGetAuthPropertiesWithBadlyFormattedTokenReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "dummyId"
+ tokenPropertyValue := "this:is:a:token:with:too:many:parts"
- // Create a galasactl.properties file that is missing the GALASA_SECRET and GALASA_ACCESS_TOKEN properties
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf("GALASA_CLIENT_ID=%s", clientIdValue))
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
// When...
_, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.NotNil(t, err, "Should return an error if the galasactl.properties exists and some required properties are missing")
- assert.ErrorContains(t, err, "GAL1122E")
+ assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but the access token is missing from the file.")
+ assert.Contains(t, err.Error(), "GAL1125E")
+ assert.Contains(t, err.Error(), "GALASA_TOKEN")
}
-func TestGetAuthPropertiesWithMissingGalasactlPropertiesFileReturnsError(t *testing.T) {
+func TestGetAuthPropertiesWithEmptyGalasactlPropertiesReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
+ mockFileSystem.WriteTextFile(mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties", "")
+
// When...
_, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.NotNil(t, err, "Should return an error if the galasactl.properties does not exist")
- assert.ErrorContains(t, err, "GAL1043E")
+ assert.NotNil(t, err, "Should return an error if the galasactl.properties is empty and an environment variable has not been set")
+ assert.ErrorContains(t, err, "GAL1122E")
}
-func TestGetAuthPropertiesEnvVarsOverridesFileValues(t *testing.T) {
+func TestGetAuthPropertiesWithMissingTokenPropertyReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "client-id-from-file"
- secretValue := "secret-from-file"
- accessTokenValue := "token-from-file"
-
- mockFileSystem.WriteTextFile(
- mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", clientIdValue, secretValue, accessTokenValue))
-
- clientIdValue = "client-id-from-env-var"
- secretValue = "secret-from-env-var"
- accessTokenValue = "token-from-env-var"
-
- mockEnvironment.SetEnv(CLIENT_ID_PROPERTY, clientIdValue)
- mockEnvironment.SetEnv(SECRET_PROPERTY, secretValue)
- mockEnvironment.SetEnv(ACCESS_TOKEN_PROPERTY, accessTokenValue)
+ // Create a galasactl.properties file that is missing the GALASA_TOKEN property
+ mockFileSystem.WriteTextFile(mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties", "unknown.value=blah")
// When...
- authProperties, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
+ _, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and all required properties are present")
- assert.Equal(t, clientIdValue, authProperties.GetClientId())
- assert.Equal(t, secretValue, authProperties.GetSecret())
- assert.Equal(t, accessTokenValue, authProperties.GetRefreshToken())
+ assert.NotNil(t, err, "Should return an error if the galasactl.properties exists and is missing a token property")
+ assert.ErrorContains(t, err, "GAL1122E")
}
-func TestGetAuthPropertiesClientIDEnvVarOverridesFileValue(t *testing.T) {
+func TestGetAuthPropertiesWithMissingGalasactlPropertiesFileReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "client-id-from-file"
- secretValue := "secret-from-file"
- accessTokenValue := "token-from-file"
-
- mockFileSystem.WriteTextFile(
- mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", clientIdValue, secretValue, accessTokenValue))
-
- clientIdValue = "client-id-from-env-var"
- // secretValue = "secret-from-env-var"
- // accessTokenValue = "token-from-env-var"
-
- mockEnvironment.SetEnv(CLIENT_ID_PROPERTY, clientIdValue)
- // mockEnvironment.SetEnv(SECRET_PROPERTY, secretValue)
- // mockEnvironment.SetEnv(ACCESS_TOKEN_PROPERTY, accessTokenValue)
-
// When...
- authProperties, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
+ _, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
// Then...
- assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and all required properties are present")
- assert.Equal(t, clientIdValue, authProperties.GetClientId())
- assert.Equal(t, secretValue, authProperties.GetSecret())
- assert.Equal(t, accessTokenValue, authProperties.GetRefreshToken())
+ assert.NotNil(t, err, "Should return an error if the galasactl.properties does not exist")
+ assert.ErrorContains(t, err, "GAL1043E")
}
-func TestGetAuthPropertiesSecretEnvVarOverridesFileValue(t *testing.T) {
+func TestGetAuthPropertiesTokenEnvVarOverridesFileValue(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()
mockEnvironment := utils.NewMockEnv()
mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
- clientIdValue := "client-id-from-file"
- secretValue := "secret-from-file"
accessTokenValue := "token-from-file"
-
- mockFileSystem.WriteTextFile(
- mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", clientIdValue, secretValue, accessTokenValue))
-
- // clientIdValue = "client-id-from-env-var"
- secretValue = "secret-from-env-var"
- // accessTokenValue = "token-from-env-var"
-
- // mockEnvironment.SetEnv(CLIENT_ID_PROPERTY, clientIdValue)
- mockEnvironment.SetEnv(SECRET_PROPERTY, secretValue)
- // mockEnvironment.SetEnv(ACCESS_TOKEN_PROPERTY, accessTokenValue)
-
- // When...
- authProperties, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
-
- // Then...
- assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and all required properties are present")
- assert.Equal(t, clientIdValue, authProperties.GetClientId())
- assert.Equal(t, secretValue, authProperties.GetSecret())
- assert.Equal(t, accessTokenValue, authProperties.GetRefreshToken())
-}
-
-func TestGetAuthPropertiesRefreshTokenEnvVarOverridesFileValue(t *testing.T) {
- // Given...
- mockFileSystem := files.NewMockFileSystem()
- mockEnvironment := utils.NewMockEnv()
- mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
-
clientIdValue := "client-id-from-file"
- secretValue := "secret-from-file"
- accessTokenValue := "token-from-file"
+ tokenPropertyValue := accessTokenValue + TOKEN_SEPARATOR + clientIdValue
mockFileSystem.WriteTextFile(
mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
- fmt.Sprintf(
- "GALASA_CLIENT_ID=%s\n"+
- "GALASA_SECRET=%s\n"+
- "GALASA_ACCESS_TOKEN=%s", clientIdValue, secretValue, accessTokenValue))
+ fmt.Sprintf("GALASA_TOKEN=%s", tokenPropertyValue))
- // clientIdValue = "client-id-from-env-var"
- // secretValue = "secret-from-env-var"
accessTokenValue = "token-from-env-var"
+ clientIdValue = "client-id-from-env-var"
+ tokenPropertyValue = accessTokenValue + TOKEN_SEPARATOR + clientIdValue
- // mockEnvironment.SetEnv(CLIENT_ID_PROPERTY, clientIdValue)
- // mockEnvironment.SetEnv(SECRET_PROPERTY, secretValue)
- mockEnvironment.SetEnv(ACCESS_TOKEN_PROPERTY, accessTokenValue)
+ mockEnvironment.SetEnv(TOKEN_PROPERTY, tokenPropertyValue)
// When...
authProperties, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
@@ -310,6 +194,5 @@ func TestGetAuthPropertiesRefreshTokenEnvVarOverridesFileValue(t *testing.T) {
// Then...
assert.Nil(t, err, "Should not return an error if the galasactl.properties exists and all required properties are present")
assert.Equal(t, clientIdValue, authProperties.GetClientId())
- assert.Equal(t, secretValue, authProperties.GetSecret())
assert.Equal(t, accessTokenValue, authProperties.GetRefreshToken())
}
diff --git a/pkg/embedded/templates/galasahome/galasactl.properties b/pkg/embedded/templates/galasahome/galasactl.properties
index bf057960..0388c89d 100644
--- a/pkg/embedded/templates/galasahome/galasactl.properties
+++ b/pkg/embedded/templates/galasahome/galasactl.properties
@@ -1,8 +1,7 @@
-# The following properties allow the galasactl tool to communicate with the Galasa Ecosystem.
+# The GALASA_TOKEN property allows the galasactl tool to communicate with the Galasa Ecosystem.
#
-# To obtain these values, log in to the Galasa web user interface and allocate a new personal
-# access token.
+# To obtain a value for this property, log in to the Galasa web user interface and allocate a new personal
+# access token. Once a personal access token has been allocated, please follow the instructions on the web
+# user interface to copy the token into this file or set it as an environment variable.
#
-# GALASA_ACCESS_TOKEN="my-access-token"
-# GALASA_CLIENT_ID="my-client-id"
-# GALASA_SECRET="my-secret"
+# GALASA_TOKEN=example:token
diff --git a/pkg/errors/errorMessage.go b/pkg/errors/errorMessage.go
index aae18c46..da1238a6 100644
--- a/pkg/errors/errorMessage.go
+++ b/pkg/errors/errorMessage.go
@@ -210,6 +210,7 @@ var (
GALASA_ERROR_AUTH_PROPERTY_NOT_AVAILABLE = NewMessageType("GAL1122E: Authentication property %s is not available, which is needed to connect to the Galasa Ecosystem. It either needs to be in a file '%s' or set as an environment variable.", 1122, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_BAD_TERMINAL_JSON_FORMAT = NewMessageType("GAL1123E: Failed to read 3270 terminal JSON because the content is in the wrong format. Reason: %s", 1123, STACK_TRACE_WANTED)
GALASA_ERROR_PNG_ENCODING_FAILED = NewMessageType("GAL1124E: Internal Failure. Terminal image could not be encoded into PNG format. Reason: %s", 1124, STACK_TRACE_NOT_WANTED)
+ GALASA_ERROR_BAD_TOKEN_PROPERTY_FORMAT = NewMessageType("GAL1125E: Authentication property %s is invalid. Please ensure that it the value is made up of two parts that are separated by a '%s'.", 1125, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_FAILED_TO_OPEN_GZIP_FILE = NewMessageType("GAL1225E: Failed to open file '%s' cause: %v. Check that this file exists, and that you have read permissions.", 1225, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_FAILED_TO_SETUP_READER_GZIP_FILE = NewMessageType("GAL1226E: Internal failure. Contents of gzip could be read, but not decoded. New gzip reader failed: file: %s error: %v", 1226, STACK_TRACE_NOT_WANTED)
GALASA_ERROR_FAILED_TO_UNCOMPRESS_GZIP_FILE = NewMessageType("GAL1227E: Internal failure. Contents of gzip could not be decoded. %v error: %v", 1227, STACK_TRACE_NOT_WANTED)
From 79f9433696f9a60f6ba4249266c267d0e90f73bd Mon Sep 17 00:00:00 2001
From: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
Date: Mon, 5 Feb 2024 11:15:15 +0000
Subject: [PATCH 2/2] Add unit test for GALASA_TOKEN=: case
Signed-off-by: Eamonn Mansour <47121388+eamansour@users.noreply.github.com>
---
pkg/auth/authProperties_test.go | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/pkg/auth/authProperties_test.go b/pkg/auth/authProperties_test.go
index afb7aeeb..ecb49780 100644
--- a/pkg/auth/authProperties_test.go
+++ b/pkg/auth/authProperties_test.go
@@ -58,6 +58,25 @@ func TestGetAuthPropertiesWithNoClientIdInTokenReturnsError(t *testing.T) {
assert.Contains(t, err.Error(), "GALASA_TOKEN")
}
+func TestGetAuthPropertiesWithOnlySeparatorReturnsError(t *testing.T) {
+ // Given...
+ mockFileSystem := files.NewMockFileSystem()
+ mockEnvironment := utils.NewMockEnv()
+ mockGalasaHome, _ := utils.NewGalasaHome(mockFileSystem, mockEnvironment, "")
+
+ mockFileSystem.WriteTextFile(
+ mockGalasaHome.GetNativeFolderPath()+"/galasactl.properties",
+ fmt.Sprintf("GALASA_TOKEN=%s", TOKEN_SEPARATOR))
+
+ // When...
+ _, err := GetAuthProperties(mockFileSystem, mockGalasaHome, mockEnvironment)
+
+ // Then...
+ assert.NotNil(t, err, "Should return an error as the galasactl.properties exists but is missing the access token and client ID parts of the token.")
+ assert.Contains(t, err.Error(), "GAL1125E")
+ assert.Contains(t, err.Error(), "GALASA_TOKEN")
+}
+
func TestGetAuthPropertiesWithSeparatorButNoClientIdReturnsError(t *testing.T) {
// Given...
mockFileSystem := files.NewMockFileSystem()