github.com/nuvolaris/nuv@v0.0.0-20240511174247-a74e3a52bfd8/auth/login_test.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one
     2  // or more contributor license agreements.  See the NOTICE file
     3  // distributed with this work for additional information
     4  // regarding copyright ownership.  The ASF licenses this file
     5  // to you under the Apache License, Version 2.0 (the
     6  // "License"); you may not use this file except in compliance
     7  // with the License.  You may obtain a copy of the License at
     8  //
     9  //   http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing,
    12  // software distributed under the License is distributed on an
    13  // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    14  // KIND, either express or implied.  See the License for the
    15  // specific language governing permissions and limitations
    16  // under the License.
    17  
    18  package auth
    19  
    20  import (
    21  	"encoding/json"
    22  	"net/http"
    23  	"net/http/httptest"
    24  	"os"
    25  	"path/filepath"
    26  	"testing"
    27  
    28  	"github.com/mitchellh/go-homedir"
    29  	"github.com/nuvolaris/nuv/config"
    30  	"github.com/stretchr/testify/require"
    31  	"github.com/zalando/go-keyring"
    32  )
    33  
    34  // setupMockServer sets up a new mock HTTP server with the given test data and expected response
    35  func setupMockServer(t *testing.T, expectedLogin, expectedPass, expectedRes string) *httptest.Server {
    36  	t.Helper()
    37  	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    38  		var requestBody map[string]string
    39  		err := json.NewDecoder(r.Body).Decode(&requestBody)
    40  		if err != nil {
    41  			http.Error(w, err.Error(), http.StatusBadRequest)
    42  			return
    43  		}
    44  
    45  		login, ok := requestBody["login"]
    46  		require.True(t, ok, "expected login field in request body")
    47  		require.Equal(t, expectedLogin, login, "expected login %s, got %s", expectedLogin, login)
    48  
    49  		password, ok := requestBody["password"]
    50  		require.True(t, ok, "expected password field in request body")
    51  		require.Equal(t, expectedPass, password, "expected password %s, got %s", expectedPass, password)
    52  
    53  		_, _ = w.Write([]byte(expectedRes))
    54  	}))
    55  
    56  	return server
    57  }
    58  func TestLoginCmd(t *testing.T) {
    59  	keyring.MockInit()
    60  
    61  	t.Run("error: returns error when empty password", func(t *testing.T) {
    62  		oldPwdReader := pwdReader
    63  		pwdReader = &stubPasswordReader{
    64  			Password:    "",
    65  			ReturnError: false,
    66  		}
    67  		os.Args = []string{"login", "fakeApiHost", "fakeUser"}
    68  		res, err := LoginCmd()
    69  		pwdReader = oldPwdReader
    70  		if err == nil {
    71  			t.Error("Expected error, got nil")
    72  		}
    73  		if err.Error() != "password is empty" {
    74  			t.Errorf("Expected error to be 'password is empty', got %s", err.Error())
    75  		}
    76  		if res != nil {
    77  			t.Errorf("Expected response to be nil, got %v", res)
    78  		}
    79  	})
    80  
    81  	t.Run("with only apihost, add received credentials", func(t *testing.T) {
    82  		mockServer := setupMockServer(t, "nuvolaris", "a password", "{\"AUTH\": \"test\"}")
    83  		defer mockServer.Close()
    84  
    85  		oldPwdReader := pwdReader
    86  		pwdReader = &stubPasswordReader{
    87  			Password:    "a password",
    88  			ReturnError: false,
    89  		}
    90  
    91  		os.Args = []string{"login", mockServer.URL}
    92  		loginResult, err := LoginCmd()
    93  		pwdReader = oldPwdReader
    94  
    95  		require.NoError(t, err)
    96  		require.NotNil(t, loginResult)
    97  
    98  		// cred, err := keyring.Get(nuvSecretServiceName, "AUTH")
    99  		nuvHome, err := homedir.Expand("~/.nuv")
   100  		require.NoError(t, err)
   101  
   102  		configMap, err := config.NewConfigMapBuilder().
   103  			WithConfigJson(filepath.Join(nuvHome, "config.json")).
   104  			Build()
   105  		require.NoError(t, err)
   106  
   107  		v, err := configMap.Get("AUTH")
   108  		require.NoError(t, err)
   109  		require.Equal(t, "test", v)
   110  	})
   111  
   112  	t.Run("with apihost and user adds received credentials to secret store", func(t *testing.T) {
   113  		mockServer := setupMockServer(t, "a user", "a password", "{ \"AUTH\": \"testauth\", \"fakeCred\": \"test\"}")
   114  		defer mockServer.Close()
   115  
   116  		oldPwdReader := pwdReader
   117  		pwdReader = &stubPasswordReader{
   118  			Password:    "a password",
   119  			ReturnError: false,
   120  		}
   121  
   122  		os.Args = []string{"login", mockServer.URL, "a user"}
   123  		loginResult, err := LoginCmd()
   124  		pwdReader = oldPwdReader
   125  		require.NoError(t, err)
   126  		require.NotNil(t, loginResult)
   127  
   128  		// cred, err := keyring.Get(nuvSecretServiceName, "fakeCred")
   129  		// require.NoError(t, err)
   130  		// require.Equal(t, "test", cred)
   131  
   132  		nuvHome, err := homedir.Expand("~/.nuv")
   133  		require.NoError(t, err)
   134  
   135  		configMap, err := config.NewConfigMapBuilder().
   136  			WithConfigJson(filepath.Join(nuvHome, "config.json")).
   137  			Build()
   138  		require.NoError(t, err)
   139  
   140  		v, err := configMap.Get("AUTH")
   141  		require.NoError(t, err)
   142  		require.Equal(t, "testauth", v)
   143  
   144  		v, err = configMap.Get("FAKECRED")
   145  		require.NoError(t, err)
   146  		require.Equal(t, "test", v)
   147  	})
   148  
   149  	t.Run("error when response body is invalid", func(t *testing.T) {
   150  		mockServer := setupMockServer(t, "a user", "a password", "invalid json")
   151  		defer mockServer.Close()
   152  
   153  		oldPwdReader := pwdReader
   154  		pwdReader = &stubPasswordReader{
   155  			Password:    "a password",
   156  			ReturnError: false,
   157  		}
   158  		os.Args = []string{"login", mockServer.URL, "a user"}
   159  		loginResult, err := LoginCmd()
   160  		pwdReader = oldPwdReader
   161  		require.Error(t, err)
   162  		require.Equal(t, "failed to decode response from login request", err.Error())
   163  		require.Nil(t, loginResult)
   164  	})
   165  
   166  	t.Run("error when response body is missing AUTH token", func(t *testing.T) {
   167  		mockServer := setupMockServer(t, "a user", "a password", "{\"fakeCred\": \"test\"}")
   168  		defer mockServer.Close()
   169  
   170  		oldPwdReader := pwdReader
   171  		pwdReader = &stubPasswordReader{
   172  			Password:    "a password",
   173  			ReturnError: false,
   174  		}
   175  		os.Args = []string{"login", mockServer.URL, "a user"}
   176  		loginResult, err := LoginCmd()
   177  		pwdReader = oldPwdReader
   178  		require.Error(t, err)
   179  		require.Equal(t, "missing AUTH token from login response", err.Error())
   180  		require.Nil(t, loginResult)
   181  	})
   182  }
   183  
   184  func Test_doLogin(t *testing.T) {
   185  	mockServer := setupMockServer(t, "a user", "a password", "{\"fakeCred\": \"test\"}")
   186  	defer mockServer.Close()
   187  
   188  	cred, err := doLogin(mockServer.URL, "a user", "a password")
   189  	require.NoError(t, err)
   190  	require.NotNil(t, cred)
   191  	require.Equal(t, "test", cred["fakeCred"])
   192  }
   193  
   194  func Test_storeCredentials(t *testing.T) {
   195  	keyring.MockInit()
   196  
   197  	fakeCreds := make(map[string]string)
   198  	fakeCreds["AUTH"] = "fakeValue"
   199  	fakeCreds["REDIS_URL"] = "fakeValue"
   200  	fakeCreds["MONGODB"] = "fakeValue"
   201  
   202  	err := storeCredentials(fakeCreds)
   203  	require.NoError(t, err)
   204  	require.NotNil(t, fakeCreds)
   205  
   206  	for k := range fakeCreds {
   207  		cred, err := keyring.Get(nuvSecretServiceName, k)
   208  		require.NoError(t, err)
   209  		require.Equal(t, fakeCreds[k], cred)
   210  	}
   211  }