github.com/cspotcode/docker-cli@v20.10.0-rc1.0.20201201121459-3faad7acc5b8+incompatible/cli/command/registry/login_test.go (about)

     1  package registry
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"testing"
     8  
     9  	configtypes "github.com/docker/cli/cli/config/types"
    10  	"github.com/docker/cli/internal/test"
    11  	"github.com/docker/docker/api/types"
    12  	registrytypes "github.com/docker/docker/api/types/registry"
    13  	"github.com/docker/docker/client"
    14  	"gotest.tools/v3/assert"
    15  	is "gotest.tools/v3/assert/cmp"
    16  	"gotest.tools/v3/fs"
    17  )
    18  
    19  const userErr = "userunknownError"
    20  const testAuthErrMsg = "UNKNOWN_ERR"
    21  
    22  var testAuthErrors = map[string]error{
    23  	userErr: fmt.Errorf(testAuthErrMsg),
    24  }
    25  
    26  var expiredPassword = "I_M_EXPIRED"
    27  var useToken = "I_M_TOKEN"
    28  
    29  type fakeClient struct {
    30  	client.Client
    31  }
    32  
    33  func (c fakeClient) Info(ctx context.Context) (types.Info, error) {
    34  	return types.Info{}, nil
    35  }
    36  
    37  func (c fakeClient) RegistryLogin(ctx context.Context, auth types.AuthConfig) (registrytypes.AuthenticateOKBody, error) {
    38  	if auth.Password == expiredPassword {
    39  		return registrytypes.AuthenticateOKBody{}, fmt.Errorf("Invalid Username or Password")
    40  	}
    41  	if auth.Password == useToken {
    42  		return registrytypes.AuthenticateOKBody{
    43  			IdentityToken: auth.Password,
    44  		}, nil
    45  	}
    46  	err := testAuthErrors[auth.Username]
    47  	return registrytypes.AuthenticateOKBody{}, err
    48  }
    49  
    50  func TestLoginWithCredStoreCreds(t *testing.T) {
    51  	testCases := []struct {
    52  		inputAuthConfig types.AuthConfig
    53  		expectedMsg     string
    54  		expectedErr     string
    55  	}{
    56  		{
    57  			inputAuthConfig: types.AuthConfig{},
    58  			expectedMsg:     "Authenticating with existing credentials...\n",
    59  		},
    60  		{
    61  			inputAuthConfig: types.AuthConfig{
    62  				Username: userErr,
    63  			},
    64  			expectedMsg: "Authenticating with existing credentials...\n",
    65  			expectedErr: fmt.Sprintf("Login did not succeed, error: %s\n", testAuthErrMsg),
    66  		},
    67  		// can't easily test the 401 case because client.IsErrUnauthorized(err) involving
    68  		// creating an error of a private type
    69  	}
    70  	ctx := context.Background()
    71  	for _, tc := range testCases {
    72  		cli := test.NewFakeCli(&fakeClient{})
    73  		errBuf := new(bytes.Buffer)
    74  		cli.SetErr(errBuf)
    75  		loginWithCredStoreCreds(ctx, cli, &tc.inputAuthConfig)
    76  		outputString := cli.OutBuffer().String()
    77  		assert.Check(t, is.Equal(tc.expectedMsg, outputString))
    78  		errorString := errBuf.String()
    79  		assert.Check(t, is.Equal(tc.expectedErr, errorString))
    80  	}
    81  }
    82  
    83  func TestRunLogin(t *testing.T) {
    84  	const storedServerAddress = "reg1"
    85  	const validUsername = "u1"
    86  	const validPassword = "p1"
    87  	const validPassword2 = "p2"
    88  
    89  	validAuthConfig := configtypes.AuthConfig{
    90  		ServerAddress: storedServerAddress,
    91  		Username:      validUsername,
    92  		Password:      validPassword,
    93  	}
    94  	expiredAuthConfig := configtypes.AuthConfig{
    95  		ServerAddress: storedServerAddress,
    96  		Username:      validUsername,
    97  		Password:      expiredPassword,
    98  	}
    99  	validIdentityToken := configtypes.AuthConfig{
   100  		ServerAddress: storedServerAddress,
   101  		Username:      validUsername,
   102  		IdentityToken: useToken,
   103  	}
   104  	testCases := []struct {
   105  		inputLoginOption  loginOptions
   106  		inputStoredCred   *configtypes.AuthConfig
   107  		expectedErr       string
   108  		expectedSavedCred configtypes.AuthConfig
   109  	}{
   110  		{
   111  			inputLoginOption: loginOptions{
   112  				serverAddress: storedServerAddress,
   113  			},
   114  			inputStoredCred:   &validAuthConfig,
   115  			expectedErr:       "",
   116  			expectedSavedCred: validAuthConfig,
   117  		},
   118  		{
   119  			inputLoginOption: loginOptions{
   120  				serverAddress: storedServerAddress,
   121  			},
   122  			inputStoredCred: &expiredAuthConfig,
   123  			expectedErr:     "Error: Cannot perform an interactive login from a non TTY device",
   124  		},
   125  		{
   126  			inputLoginOption: loginOptions{
   127  				serverAddress: storedServerAddress,
   128  				user:          validUsername,
   129  				password:      validPassword2,
   130  			},
   131  			inputStoredCred: &validAuthConfig,
   132  			expectedErr:     "",
   133  			expectedSavedCred: configtypes.AuthConfig{
   134  				ServerAddress: storedServerAddress,
   135  				Username:      validUsername,
   136  				Password:      validPassword2,
   137  			},
   138  		},
   139  		{
   140  			inputLoginOption: loginOptions{
   141  				serverAddress: storedServerAddress,
   142  				user:          userErr,
   143  				password:      validPassword,
   144  			},
   145  			inputStoredCred: &validAuthConfig,
   146  			expectedErr:     testAuthErrMsg,
   147  		},
   148  		{
   149  			inputLoginOption: loginOptions{
   150  				serverAddress: storedServerAddress,
   151  				user:          validUsername,
   152  				password:      useToken,
   153  			},
   154  			inputStoredCred:   &validIdentityToken,
   155  			expectedErr:       "",
   156  			expectedSavedCred: validIdentityToken,
   157  		},
   158  	}
   159  	for i, tc := range testCases {
   160  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   161  			tmpFile := fs.NewFile(t, "test-run-login")
   162  			defer tmpFile.Remove()
   163  			cli := test.NewFakeCli(&fakeClient{})
   164  			configfile := cli.ConfigFile()
   165  			configfile.Filename = tmpFile.Path()
   166  
   167  			if tc.inputStoredCred != nil {
   168  				cred := *tc.inputStoredCred
   169  				assert.NilError(t, configfile.GetCredentialsStore(cred.ServerAddress).Store(cred))
   170  			}
   171  			loginErr := runLogin(cli, tc.inputLoginOption)
   172  			if tc.expectedErr != "" {
   173  				assert.Error(t, loginErr, tc.expectedErr)
   174  				return
   175  			}
   176  			assert.NilError(t, loginErr)
   177  			savedCred, credStoreErr := configfile.GetCredentialsStore(tc.inputStoredCred.ServerAddress).Get(tc.inputStoredCred.ServerAddress)
   178  			assert.Check(t, credStoreErr)
   179  			assert.DeepEqual(t, tc.expectedSavedCred, savedCred)
   180  		})
   181  	}
   182  }