Skip to content

Commit

Permalink
Merge pull request #6 from bloodorangeio/login-with-opts
Browse files Browse the repository at this point in the history
Add new LoginWithOpts
  • Loading branch information
jdolitsky authored Jun 9, 2021
2 parents 933c6d5 + dc9aa47 commit 356245d
Show file tree
Hide file tree
Showing 7 changed files with 302 additions and 107 deletions.
39 changes: 3 additions & 36 deletions pkg/auth/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,13 @@ var (
ErrNotLoggedIn = errors.New("not logged in")
)

type (
// ResolverOption allows specifying various settings on the resolver.
ResolverOption func(*ResolverSettings)

// ResolverSettings represent all the various settings on a resolver.
ResolverSettings struct {
// Headers are the HTTP request header fields sent by the resolver.
Client *http.Client
// PlainHTTP specifies to use plain http and not https.
PlainHTTP bool
// Client is the http client to used when making registry requests.
Headers http.Header
}
)

// Client provides authentication operations for remotes.
type Client interface {
// Login logs in to a remote server identified by the hostname.
// Deprecated: use LoginWithOpts
Login(ctx context.Context, hostname, username, secret string, insecure bool) error
// LoginWithOpts logs in to a remote server identified by the hostname with custom options
LoginWithOpts(options ...LoginOption) error
// Logout logs out from a remote server identified by the hostname.
Logout(ctx context.Context, hostname string) error
// Resolver returns a new authenticated resolver.
Expand All @@ -55,24 +43,3 @@ type Client interface {
// ResolverWithOpts returns a new authenticated resolver with custom options.
ResolverWithOpts(options ...ResolverOption) (remotes.Resolver, error)
}

// WithResolverClient returns a function that sets the Client setting on resolver.
func WithResolverClient(client *http.Client) ResolverOption {
return func(settings *ResolverSettings) {
settings.Client = client
}
}

// WithResolverPlainHTTP returns a function that sets the PlainHTTP setting to true on resolver.
func WithResolverPlainHTTP() ResolverOption {
return func(settings *ResolverSettings) {
settings.PlainHTTP = true
}
}

// WithResolverHeaders returns a function that sets the Headers setting on resolver.
func WithResolverHeaders(headers http.Header) ResolverOption {
return func(settings *ResolverSettings) {
settings.Headers = headers
}
}
111 changes: 111 additions & 0 deletions pkg/auth/client_opts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
"context"
"net/http"
)

type (
// LoginOption allows specifying various settings on login.
LoginOption func(*LoginSettings)

// LoginSettings represent all the various settings on login.
LoginSettings struct {
Context context.Context
Hostname string
Username string
Secret string
Insecure bool
UserAgent string
}
)

// WithLoginContext returns a function that sets the Context setting on login.
func WithLoginContext(context context.Context) LoginOption {
return func(settings *LoginSettings) {
settings.Context = context
}
}

// WithLoginHostname returns a function that sets the Hostname setting on login.
func WithLoginHostname(hostname string) LoginOption {
return func(settings *LoginSettings) {
settings.Hostname = hostname
}
}

// WithLoginUsername returns a function that sets the Username setting on login.
func WithLoginUsername(username string) LoginOption {
return func(settings *LoginSettings) {
settings.Username = username
}
}

// WithLoginSecret returns a function that sets the Secret setting on login.
func WithLoginSecret(secret string) LoginOption {
return func(settings *LoginSettings) {
settings.Secret = secret
}
}

// WithLoginInsecure returns a function that sets the Insecure setting to true on login.
func WithLoginInsecure() LoginOption {
return func(settings *LoginSettings) {
settings.Insecure = true
}
}

// WithLoginUserAgent returns a function that sets the UserAgent setting on login.
func WithLoginUserAgent(userAgent string) LoginOption {
return func(settings *LoginSettings) {
settings.UserAgent = userAgent
}
}

type (
// ResolverOption allows specifying various settings on the resolver.
ResolverOption func(*ResolverSettings)

// ResolverSettings represent all the various settings on a resolver.
ResolverSettings struct {
Client *http.Client
PlainHTTP bool
Headers http.Header
}
)

// WithResolverClient returns a function that sets the Client setting on resolver.
func WithResolverClient(client *http.Client) ResolverOption {
return func(settings *ResolverSettings) {
settings.Client = client
}
}

// WithResolverPlainHTTP returns a function that sets the PlainHTTP setting to true on resolver.
func WithResolverPlainHTTP() ResolverOption {
return func(settings *ResolverSettings) {
settings.PlainHTTP = true
}
}

// WithResolverHeaders returns a function that sets the Headers setting on resolver.
func WithResolverHeaders(headers http.Header) ResolverOption {
return func(settings *ResolverSettings) {
settings.Headers = headers
}
}
124 changes: 124 additions & 0 deletions pkg/auth/client_opts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
Copyright The ORAS Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package auth

import (
"context"
"net/http"
"testing"

"github.com/stretchr/testify/suite"
)

type ClientOptsSuite struct {
suite.Suite
}

func (suite *ClientOptsSuite) TestWithLoginContext() {
settings := &LoginSettings{}
suite.Nil(settings.Context, "settings.Context is nil by default")

ctx := context.Background()
opt := WithLoginContext(ctx)
opt(settings)
suite.Equal(ctx, settings.Context, "Able to override settings.Context")
}

func (suite *ClientOptsSuite) TestWithLoginHostname() {
settings := &LoginSettings{}
suite.Equal("", settings.Hostname, "settings.Hostname is empty string by default")

hostname := "example.com"
opt := WithLoginHostname(hostname)
opt(settings)
suite.Equal(hostname, settings.Hostname, "Able to override settings.Hostname")
}

func (suite *ClientOptsSuite) TestWithLoginUsername() {
settings := &LoginSettings{}
suite.Equal("", settings.Username, "settings.Username is empty string by default")

username := "fran"
opt := WithLoginUsername(username)
opt(settings)
suite.Equal(username, settings.Username, "Able to override settings.Username")
}

func (suite *ClientOptsSuite) TestWithLoginSecret() {
settings := &LoginSettings{}
suite.Equal("", settings.Secret, "settings.Secret is empty string by default")

secret := "shhhhhhhhhh"
opt := WithLoginSecret(secret)
opt(settings)
suite.Equal(secret, settings.Secret, "Able to override settings.Secret")
}

func (suite *ClientOptsSuite) TestWithLoginInsecure() {
settings := &LoginSettings{}
suite.Equal(false, settings.Insecure, "settings.Insecure is false by default")

opt := WithLoginInsecure()
opt(settings)
suite.Equal(true, settings.Insecure, "Able to override settings.Insecure")
}

func (suite *ClientOptsSuite) TestWithLoginUserAgent() {
settings := &LoginSettings{}
suite.Equal("", settings.UserAgent, "settings.UserAgent is empty string by default")

userAgent := "superclient"
opt := WithLoginUserAgent(userAgent)
opt(settings)
suite.Equal(userAgent, settings.UserAgent, "Able to override settings.UserAgent")
}

func (suite *ClientOptsSuite) TestWithResolverClient() {
settings := &ResolverSettings{}
suite.Nil(settings.Client, "settings.Client is nil by default")

defaultClient := http.DefaultClient
opt := WithResolverClient(defaultClient)
opt(settings)
suite.Equal(defaultClient, settings.Client, "Able to override settings.Client")
}

func (suite *ClientOptsSuite) TestWithResolverPlainHTTP() {
settings := &ResolverSettings{}
suite.Equal(false, settings.PlainHTTP, "settings.PlainHTTP is false by default")

plainHTTP := true
opt := WithResolverPlainHTTP()
opt(settings)
suite.Equal(plainHTTP, settings.PlainHTTP, "Able to override settings.PlainHTTP")
}

func (suite *ClientOptsSuite) TestWithResolverHeaders() {
settings := &ResolverSettings{}
suite.Nil(settings.Headers, "settings.Headers is nil by default")

key := "User-Agent"
value := "oras-go/test"
headers := http.Header{}
headers.Set(key, value)
opt := WithResolverHeaders(headers)
opt(settings)
suite.Equal(settings.Headers.Get(key), value, "Able to override settings.Headers")
}

func TestClientOptsSuite(t *testing.T) {
suite.Run(t, new(ClientOptsSuite))
}
64 changes: 0 additions & 64 deletions pkg/auth/client_test.go

This file was deleted.

25 changes: 25 additions & 0 deletions pkg/auth/docker/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ import (
"github.com/phayes/freeport"
"github.com/stretchr/testify/suite"
"golang.org/x/crypto/bcrypt"

iface "github.com/oras-project/oras-go/pkg/auth"
)

var (
Expand Down Expand Up @@ -128,6 +130,29 @@ func (suite *DockerClientTestSuite) Test_0_Login() {
err = suite.Client.Login(newContext(), suite.DockerRegistryHost, testUsername, testPassword, false)
suite.Nil(err, "no error logging into registry with valid credentials")
}

func (suite *DockerClientTestSuite) Test_1_LoginWithOpts() {
var err error

opts := []iface.LoginOption{
iface.WithLoginContext(newContext()),
iface.WithLoginHostname(suite.DockerRegistryHost),
iface.WithLoginUsername("oscar"),
iface.WithLoginSecret("opponent"),
}
err = suite.Client.LoginWithOpts(opts...)
suite.NotNil(err, "error logging into registry with invalid credentials (LoginWithOpts)")

opts = []iface.LoginOption{
iface.WithLoginContext(newContext()),
iface.WithLoginHostname(suite.DockerRegistryHost),
iface.WithLoginUsername(testUsername),
iface.WithLoginSecret(testPassword),
}
err = suite.Client.LoginWithOpts(opts...)
suite.Nil(err, "no error logging into registry with valid credentials (LoginWithOpts)")
}

func (suite *DockerClientTestSuite) Test_2_Logout() {
var err error

Expand Down
Loading

0 comments on commit 356245d

Please sign in to comment.