github.com/nikkelma/oras-project_oras-go@v1.1.1-0.20220201001104-a75f6a419090/pkg/auth/docker/client_test.go (about) 1 /* 2 Copyright The ORAS Authors. 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 */ 15 16 package docker 17 18 import ( 19 "context" 20 "fmt" 21 "io/ioutil" 22 "net/http" 23 "os" 24 "path/filepath" 25 "testing" 26 "time" 27 28 "github.com/distribution/distribution/v3/configuration" 29 "github.com/distribution/distribution/v3/registry" 30 _ "github.com/distribution/distribution/v3/registry/auth/htpasswd" 31 _ "github.com/distribution/distribution/v3/registry/storage/driver/inmemory" 32 "github.com/phayes/freeport" 33 "github.com/stretchr/testify/suite" 34 "golang.org/x/crypto/bcrypt" 35 36 iface "oras.land/oras-go/pkg/auth" 37 ) 38 39 var ( 40 testConfig = "test.config" 41 testHtpasswd = "test.htpasswd" 42 testUsername = "alice" 43 testPassword = "wonderland" 44 ) 45 46 type DockerClientTestSuite struct { 47 suite.Suite 48 DockerRegistryHost string 49 Client *Client 50 TempTestDir string 51 } 52 53 func newContext() context.Context { 54 return context.Background() 55 } 56 57 func (suite *DockerClientTestSuite) SetupSuite() { 58 tempDir, err := ioutil.TempDir("", "oras_auth_docker_test") 59 suite.Nil(err, "no error creating temp directory for test") 60 suite.TempTestDir = tempDir 61 62 // Create client 63 client, err := NewClient(filepath.Join(suite.TempTestDir, testConfig)) 64 suite.Nil(err, "no error creating client") 65 var ok bool 66 suite.Client, ok = client.(*Client) 67 suite.True(ok, "NewClient returns a *docker.Client inside") 68 69 // Create htpasswd file with bcrypt 70 secret, err := bcrypt.GenerateFromPassword([]byte(testPassword), bcrypt.DefaultCost) 71 suite.Nil(err, "no error generating bcrypt password for test htpasswd file") 72 authRecord := fmt.Sprintf("%s:%s\n", testUsername, string(secret)) 73 htpasswdPath := filepath.Join(suite.TempTestDir, testHtpasswd) 74 err = ioutil.WriteFile(htpasswdPath, []byte(authRecord), 0644) 75 suite.Nil(err, "no error creating test htpasswd file") 76 77 // Registry config 78 config := &configuration.Configuration{} 79 port, err := freeport.GetFreePort() 80 suite.Nil(err, "no error finding free port for test registry") 81 suite.DockerRegistryHost = fmt.Sprintf("localhost:%d", port) 82 config.HTTP.Addr = fmt.Sprintf(":%d", port) 83 config.HTTP.DrainTimeout = time.Duration(10) * time.Second 84 config.Storage = map[string]configuration.Parameters{"inmemory": map[string]interface{}{}} 85 config.Auth = configuration.Auth{ 86 "htpasswd": configuration.Parameters{ 87 "realm": "localhost", 88 "path": htpasswdPath, 89 }, 90 } 91 dockerRegistry, err := registry.NewRegistry(context.Background(), config) 92 suite.Nil(err, "no error finding free port for test registry") 93 94 // Start Docker registry 95 go dockerRegistry.ListenAndServe() 96 ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) 97 defer cancel() 98 for { 99 select { 100 case <-ctx.Done(): 101 suite.FailNow("docker registry timed out") 102 default: 103 } 104 req, err := http.NewRequestWithContext( 105 ctx, 106 http.MethodGet, 107 fmt.Sprintf("http://%s/v2/", suite.DockerRegistryHost), 108 nil, 109 ) 110 suite.Nil(err, "no error in generate a /v2/ request") 111 resp, err := http.DefaultClient.Do(req) 112 if err == nil { 113 resp.Body.Close() 114 break 115 } 116 time.Sleep(time.Second) 117 } 118 } 119 120 func (suite *DockerClientTestSuite) TearDownSuite() { 121 os.RemoveAll(suite.TempTestDir) 122 } 123 124 func (suite *DockerClientTestSuite) Test_0_Login() { 125 var err error 126 127 err = suite.Client.Login(newContext(), suite.DockerRegistryHost, "oscar", "opponent", false) 128 suite.NotNil(err, "error logging into registry with invalid credentials") 129 130 err = suite.Client.Login(newContext(), suite.DockerRegistryHost, testUsername, testPassword, false) 131 suite.Nil(err, "no error logging into registry with valid credentials") 132 } 133 134 func (suite *DockerClientTestSuite) Test_1_LoginWithOpts() { 135 var err error 136 137 opts := []iface.LoginOption{ 138 iface.WithLoginContext(newContext()), 139 iface.WithLoginHostname(suite.DockerRegistryHost), 140 iface.WithLoginUsername("oscar"), 141 iface.WithLoginSecret("opponent"), 142 } 143 err = suite.Client.LoginWithOpts(opts...) 144 suite.NotNil(err, "error logging into registry with invalid credentials (LoginWithOpts)") 145 146 opts = []iface.LoginOption{ 147 iface.WithLoginContext(newContext()), 148 iface.WithLoginHostname(suite.DockerRegistryHost), 149 iface.WithLoginUsername(testUsername), 150 iface.WithLoginSecret(testPassword), 151 } 152 err = suite.Client.LoginWithOpts(opts...) 153 suite.Nil(err, "no error logging into registry with valid credentials (LoginWithOpts)") 154 } 155 156 func (suite *DockerClientTestSuite) Test_2_Logout() { 157 var err error 158 159 err = suite.Client.Logout(newContext(), "non-existing-host:42") 160 suite.NotNil(err, "error logging out of registry that has no entry") 161 162 err = suite.Client.Logout(newContext(), suite.DockerRegistryHost) 163 suite.Nil(err, "no error logging out of registry") 164 } 165 166 func TestDockerClientTestSuite(t *testing.T) { 167 suite.Run(t, new(DockerClientTestSuite)) 168 }