mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #20565 from kencochrane/remove_email_on_login
Remove email address field from login
This commit is contained in:
commit
2453262e7b
18 changed files with 180 additions and 182 deletions
|
@ -17,7 +17,7 @@ import (
|
|||
"github.com/docker/engine-api/types"
|
||||
)
|
||||
|
||||
// CmdLogin logs in or registers a user to a Docker registry service.
|
||||
// CmdLogin logs in a user to a Docker registry service.
|
||||
//
|
||||
// If no server is specified, the user will be logged into or registered to the registry's index server.
|
||||
//
|
||||
|
@ -28,7 +28,9 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
|||
|
||||
flUser := cmd.String([]string{"u", "-username"}, "", "Username")
|
||||
flPassword := cmd.String([]string{"p", "-password"}, "", "Password")
|
||||
flEmail := cmd.String([]string{"e", "-email"}, "", "Email")
|
||||
|
||||
// Deprecated in 1.11: Should be removed in docker 1.13
|
||||
cmd.String([]string{"#e", "#-email"}, "", "Email")
|
||||
|
||||
cmd.ParseFlags(args, true)
|
||||
|
||||
|
@ -38,13 +40,15 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
|
|||
}
|
||||
|
||||
var serverAddress string
|
||||
var isDefaultRegistry bool
|
||||
if len(cmd.Args()) > 0 {
|
||||
serverAddress = cmd.Arg(0)
|
||||
} else {
|
||||
serverAddress = cli.electAuthServer()
|
||||
isDefaultRegistry = true
|
||||
}
|
||||
|
||||
authConfig, err := cli.configureAuth(*flUser, *flPassword, *flEmail, serverAddress)
|
||||
authConfig, err := cli.configureAuth(*flUser, *flPassword, serverAddress, isDefaultRegistry)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -77,7 +81,7 @@ func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) {
|
|||
}
|
||||
}
|
||||
|
||||
func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) {
|
||||
func (cli *DockerCli) configureAuth(flUser, flPassword, serverAddress string, isDefaultRegistry bool) (types.AuthConfig, error) {
|
||||
authconfig, err := getCredentials(cli.configFile, serverAddress)
|
||||
if err != nil {
|
||||
return authconfig, err
|
||||
|
@ -86,6 +90,10 @@ func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress s
|
|||
authconfig.Username = strings.TrimSpace(authconfig.Username)
|
||||
|
||||
if flUser = strings.TrimSpace(flUser); flUser == "" {
|
||||
if isDefaultRegistry {
|
||||
// if this is a defauly registry (docker hub), then display the following message.
|
||||
fmt.Fprintln(cli.out, "Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.")
|
||||
}
|
||||
cli.promptWithDefault("Username", authconfig.Username)
|
||||
flUser = readInput(cli.in, cli.out)
|
||||
flUser = strings.TrimSpace(flUser)
|
||||
|
@ -115,29 +123,8 @@ func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress s
|
|||
}
|
||||
}
|
||||
|
||||
// Assume that a different username means they may not want to use
|
||||
// the email from the config file, so prompt it
|
||||
if flUser != authconfig.Username {
|
||||
if flEmail == "" {
|
||||
cli.promptWithDefault("Email", authconfig.Email)
|
||||
flEmail = readInput(cli.in, cli.out)
|
||||
if flEmail == "" {
|
||||
flEmail = authconfig.Email
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// However, if they don't override the username use the
|
||||
// email from the cmd line if specified. IOW, allow
|
||||
// then to change/override them. And if not specified, just
|
||||
// use what's in the config file
|
||||
if flEmail == "" {
|
||||
flEmail = authconfig.Email
|
||||
}
|
||||
}
|
||||
|
||||
authconfig.Username = flUser
|
||||
authconfig.Password = flPassword
|
||||
authconfig.Email = flEmail
|
||||
authconfig.ServerAddress = serverAddress
|
||||
|
||||
return authconfig, nil
|
||||
|
|
|
@ -48,7 +48,7 @@ func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.
|
|||
return func() (string, error) {
|
||||
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
|
||||
indexServer := registry.GetAuthConfigKey(index)
|
||||
authConfig, err := cli.configureAuth("", "", "", indexServer)
|
||||
authConfig, err := cli.configureAuth("", "", indexServer, false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
|
|
@ -88,11 +88,6 @@ func (configFile *ConfigFile) LegacyLoadFromReader(configData io.Reader) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origEmail := strings.Split(arr[1], " = ")
|
||||
if len(origEmail) != 2 {
|
||||
return fmt.Errorf("Invalid Auth config file")
|
||||
}
|
||||
authConfig.Email = origEmail[1]
|
||||
authConfig.ServerAddress = defaultIndexserver
|
||||
configFile.AuthConfigs[defaultIndexserver] = authConfig
|
||||
} else {
|
||||
|
|
|
@ -111,12 +111,9 @@ func TestOldInvalidsAuth(t *testing.T) {
|
|||
invalids := map[string]string{
|
||||
`username = test`: "The Auth config file is empty",
|
||||
`username
|
||||
password
|
||||
email`: "Invalid Auth config file",
|
||||
password`: "Invalid Auth config file",
|
||||
`username = test
|
||||
email`: "Invalid auth configuration file",
|
||||
`username = am9lam9lOmhlbGxv
|
||||
email`: "Invalid Auth config file",
|
||||
}
|
||||
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
|
@ -164,7 +161,7 @@ func TestOldValidAuth(t *testing.T) {
|
|||
|
||||
fn := filepath.Join(tmpHome, oldConfigfile)
|
||||
js := `username = am9lam9lOmhlbGxv
|
||||
email = user@example.com`
|
||||
email = user@example.com`
|
||||
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -176,15 +173,23 @@ email = user@example.com`
|
|||
|
||||
// defaultIndexserver is https://index.docker.io/v1/
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
|
||||
// Now save it and make sure it shows up in new form
|
||||
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
|
||||
|
||||
if !strings.Contains(configStr, "user@example.com") {
|
||||
t.Fatalf("Should have save in new form: %s", configStr)
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if configStr != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,15 +244,24 @@ func TestOldJson(t *testing.T) {
|
|||
}
|
||||
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
|
||||
// Now save it and make sure it shows up in new form
|
||||
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
|
||||
|
||||
if !strings.Contains(configStr, "user@example.com") {
|
||||
t.Fatalf("Should have save in new form: %s", configStr)
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if configStr != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n'%s'\n not \n'%s'\n", configStr, expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,7 +273,7 @@ func TestNewJson(t *testing.T) {
|
|||
defer os.RemoveAll(tmpHome)
|
||||
|
||||
fn := filepath.Join(tmpHome, ConfigFileName)
|
||||
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } } }`
|
||||
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } }`
|
||||
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -270,15 +284,62 @@ func TestNewJson(t *testing.T) {
|
|||
}
|
||||
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
|
||||
// Now save it and make sure it shows up in new form
|
||||
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
|
||||
|
||||
if !strings.Contains(configStr, "user@example.com") {
|
||||
t.Fatalf("Should have save in new form: %s", configStr)
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if configStr != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewJsonNoEmail(t *testing.T) {
|
||||
tmpHome, err := ioutil.TempDir("", "config-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpHome)
|
||||
|
||||
fn := filepath.Join(tmpHome, ConfigFileName)
|
||||
js := ` { "auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } } }`
|
||||
if err := ioutil.WriteFile(fn, []byte(js), 0600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
config, err := Load(tmpHome)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed loading on empty json file: %q", err)
|
||||
}
|
||||
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
|
||||
// Now save it and make sure it shows up in new form
|
||||
configStr := saveConfigAndValidateNewFormat(t, config, tmpHome)
|
||||
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if configStr != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n%s\n not \n%s", configStr, expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -366,7 +427,7 @@ func TestJsonReaderNoFile(t *testing.T) {
|
|||
}
|
||||
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
|
||||
|
@ -381,7 +442,7 @@ func TestOldJsonReaderNoFile(t *testing.T) {
|
|||
}
|
||||
|
||||
ac := config.AuthConfigs["https://index.docker.io/v1/"]
|
||||
if ac.Email != "user@example.com" || ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
if ac.Username != "joejoe" || ac.Password != "hello" {
|
||||
t.Fatalf("Missing data from parsing:\n%q", config)
|
||||
}
|
||||
}
|
||||
|
@ -404,7 +465,7 @@ func TestJsonWithPsFormatNoFile(t *testing.T) {
|
|||
|
||||
func TestJsonSaveWithNoFile(t *testing.T) {
|
||||
js := `{
|
||||
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv", "email": "user@example.com" } },
|
||||
"auths": { "https://index.docker.io/v1/": { "auth": "am9lam9lOmhlbGxv" } },
|
||||
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
|
||||
}`
|
||||
config, err := LoadFromReader(strings.NewReader(js))
|
||||
|
@ -426,9 +487,16 @@ func TestJsonSaveWithNoFile(t *testing.T) {
|
|||
t.Fatalf("Failed saving to file: %q", err)
|
||||
}
|
||||
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
|
||||
if !strings.Contains(string(buf), `"auths":`) ||
|
||||
!strings.Contains(string(buf), "user@example.com") {
|
||||
t.Fatalf("Should have save in new form: %s", string(buf))
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv"
|
||||
}
|
||||
},
|
||||
"psFormat": "table {{.ID}}\\t{{.Label \"com.docker.label.cpu\"}}"
|
||||
}`
|
||||
if string(buf) != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n%s\nnot \n%s", string(buf), expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -454,14 +522,23 @@ func TestLegacyJsonSaveWithNoFile(t *testing.T) {
|
|||
t.Fatalf("Failed saving to file: %q", err)
|
||||
}
|
||||
buf, err := ioutil.ReadFile(filepath.Join(tmpHome, ConfigFileName))
|
||||
if !strings.Contains(string(buf), `"auths":`) ||
|
||||
!strings.Contains(string(buf), "user@example.com") {
|
||||
t.Fatalf("Should have save in new form: %s", string(buf))
|
||||
|
||||
expConfStr := `{
|
||||
"auths": {
|
||||
"https://index.docker.io/v1/": {
|
||||
"auth": "am9lam9lOmhlbGxv",
|
||||
"email": "user@example.com"
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
if string(buf) != expConfStr {
|
||||
t.Fatalf("Should have save in new form: \n%s\n not \n%s", string(buf), expConfStr)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeAuth(t *testing.T) {
|
||||
newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test", Email: "test@example.com"}
|
||||
newAuthConfig := &types.AuthConfig{Username: "ken", Password: "test"}
|
||||
authStr := encodeAuth(newAuthConfig)
|
||||
decAuthConfig := &types.AuthConfig{}
|
||||
var err error
|
||||
|
|
|
@ -811,7 +811,7 @@ _docker_daemon() {
|
|||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
local key=$(__docker_map_key_of_current_option '--storage-opt')
|
||||
case "$key" in
|
||||
dm.@(blkdiscard|override_udev_sync_check|use_deferred_@(removal|deletion)))
|
||||
|
@ -1205,14 +1205,14 @@ _docker_load() {
|
|||
|
||||
_docker_login() {
|
||||
case "$prev" in
|
||||
--email|-e|--password|-p|--username|-u)
|
||||
--password|-p|--username|-u)
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=( $( compgen -W "--email -e --help --password -p --username -u" -- "$cur" ) )
|
||||
COMPREPLY=( $( compgen -W "--help --password -p --username -u" -- "$cur" ) )
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
|
|
@ -221,8 +221,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from load' -l help -d 'Print
|
|||
complete -c docker -A -f -n '__fish_seen_subcommand_from load' -s i -l input -d 'Read from a tar archive file, instead of STDIN'
|
||||
|
||||
# login
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a login -d 'Register or log in to a Docker registry server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s e -l email -d 'Email'
|
||||
complete -c docker -f -n '__fish_docker_no_subcommand' -a login -d 'Log in to a Docker registry server'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s p -l password -d 'Password'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from login' -s u -l username -d 'Username'
|
||||
|
@ -399,5 +398,3 @@ complete -c docker -f -n '__fish_docker_no_subcommand' -a version -d 'Show the D
|
|||
complete -c docker -f -n '__fish_docker_no_subcommand' -a wait -d 'Block until a container stops, then print its exit code'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -l help -d 'Print usage'
|
||||
complete -c docker -A -f -n '__fish_seen_subcommand_from wait' -a '(__fish_print_docker_containers running)' -d "Container"
|
||||
|
||||
|
||||
|
|
|
@ -812,7 +812,6 @@ __docker_subcommand() {
|
|||
(login)
|
||||
_arguments $(__docker_arguments) \
|
||||
$opts_help \
|
||||
"($help -e --email)"{-e=,--email=}"[Email]:email: " \
|
||||
"($help -p --password)"{-p=,--password=}"[Password]:password: " \
|
||||
"($help -u --user)"{-u=,--user=}"[Username]:username: " \
|
||||
"($help -)1:server: " && ret=0
|
||||
|
|
|
@ -14,6 +14,13 @@ weight=80
|
|||
|
||||
The following list of features are deprecated in Engine.
|
||||
|
||||
### `-e` and `--email` flags on `docker login`
|
||||
**Deprecated In Release: v1.11**
|
||||
|
||||
**Target For Removal In Release: v1.13**
|
||||
|
||||
The docker login command is removing the ability to automatically register for an account with the target registry if the given username doesn't exist. Due to this change, the email flag is no longer required, and will be deprecated.
|
||||
|
||||
### Ambiguous event fields in API
|
||||
**Deprecated In Release: v1.10**
|
||||
|
||||
|
|
|
@ -12,10 +12,9 @@ parent = "smn_cli"
|
|||
|
||||
Usage: docker login [OPTIONS] [SERVER]
|
||||
|
||||
Register or log in to a Docker registry server, if no server is
|
||||
Log in to a Docker registry server, if no server is
|
||||
specified "https://index.docker.io/v1/" is the default.
|
||||
|
||||
-e, --email="" Email
|
||||
--help Print usage
|
||||
-p, --password="" Password
|
||||
-u, --username="" Username
|
||||
|
@ -27,10 +26,10 @@ adding the server name.
|
|||
$ docker login localhost:8080
|
||||
|
||||
|
||||
`docker login` requires user to use `sudo` or be `root`, except when:
|
||||
`docker login` requires user to use `sudo` or be `root`, except when:
|
||||
|
||||
1. connecting to a remote daemon, such as a `docker-machine` provisioned `docker engine`.
|
||||
2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/security/security/#docker-daemon-attack-surface) for details.
|
||||
2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/security/security/#docker-daemon-attack-surface) for details.
|
||||
|
||||
You can log into any public or private repository for which you have
|
||||
credentials. When you log in, the command stores encoded credentials in
|
||||
|
|
|
@ -33,15 +33,11 @@ Docker itself provides access to Docker Hub services via the `docker search`,
|
|||
### Account creation and login
|
||||
Typically, you'll want to start by creating an account on Docker Hub (if you haven't
|
||||
already) and logging in. You can create your account directly on
|
||||
[Docker Hub](https://hub.docker.com/account/signup/), or by running:
|
||||
[Docker Hub](https://hub.docker.com/account/signup/).
|
||||
|
||||
$ docker login
|
||||
|
||||
This will prompt you for a user name, which will become the public namespace for your
|
||||
public repositories.
|
||||
If your user name is available, Docker will prompt you to enter a password and your
|
||||
e-mail address. It will then automatically log you in. You can now commit and
|
||||
push your own images up to your repos on Docker Hub.
|
||||
You can now commit and push your own images up to your repos on Docker Hub.
|
||||
|
||||
> **Note:**
|
||||
> Your authentication credentials will be stored in the `~/.docker/config.json`
|
||||
|
|
|
@ -6568,7 +6568,7 @@ func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerRegistryAuthSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
|
||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, "-e", s.reg.email, privateRegistryURL)
|
||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
|
||||
|
||||
baseImage := privateRegistryURL + "/baseimage"
|
||||
|
||||
|
|
|
@ -20,11 +20,25 @@ func (s *DockerSuite) TestLoginWithoutTTY(c *check.C) {
|
|||
}
|
||||
|
||||
func (s *DockerRegistryAuthSuite) TestLoginToPrivateRegistry(c *check.C) {
|
||||
// wrong credentials
|
||||
out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", privateRegistryURL)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "401 Unauthorized")
|
||||
|
||||
// now it's fine
|
||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
|
||||
}
|
||||
|
||||
func (s *DockerRegistryAuthSuite) TestLoginToPrivateRegistryDeprecatedEmailFlag(c *check.C) {
|
||||
// Test to make sure login still works with the deprecated -e and --email flags
|
||||
// wrong credentials
|
||||
out, _, err := dockerCmdWithError("login", "-u", s.reg.username, "-p", "WRONGPASSWORD", "-e", s.reg.email, privateRegistryURL)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
c.Assert(out, checker.Contains, "401 Unauthorized")
|
||||
|
||||
// now it's fine
|
||||
// -e flag
|
||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, "-e", s.reg.email, privateRegistryURL)
|
||||
// --email flag
|
||||
dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, "--email", s.reg.email, privateRegistryURL)
|
||||
}
|
||||
|
|
|
@ -390,7 +390,6 @@ func (s *DockerRegistryAuthSuite) TestPullWithExternalAuth(c *check.C) {
|
|||
b, err := ioutil.ReadFile(configPath)
|
||||
c.Assert(err, checker.IsNil)
|
||||
c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
|
||||
c.Assert(string(b), checker.Contains, "email")
|
||||
|
||||
dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
|
||||
dockerCmd(c, "--config", tmp, "push", repoName)
|
||||
|
|
|
@ -112,7 +112,7 @@ func (s *DockerRegistrySuite) TestV1(c *check.C) {
|
|||
s.d.Cmd("run", repoName)
|
||||
c.Assert(v1Repo, check.Not(check.Equals), 1, check.Commentf("Expected v1 repository access after run"))
|
||||
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport)
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", reg.hostport)
|
||||
c.Assert(v1Logins, check.Not(check.Equals), 0, check.Commentf("Expected v1 login attempt"))
|
||||
|
||||
s.d.Cmd("tag", "busybox", repoName)
|
||||
|
|
|
@ -2,26 +2,25 @@
|
|||
% Docker Community
|
||||
% JUNE 2014
|
||||
# NAME
|
||||
docker-login - Register or log in to a Docker registry.
|
||||
docker-login - Log in to a Docker registry.
|
||||
|
||||
# SYNOPSIS
|
||||
**docker login**
|
||||
[**-e**|**--email**[=*EMAIL*]]
|
||||
[**--help**]
|
||||
[**-p**|**--password**[=*PASSWORD*]]
|
||||
[**-u**|**--username**[=*USERNAME*]]
|
||||
[SERVER]
|
||||
|
||||
# DESCRIPTION
|
||||
Register or log in to a Docker Registry located on the specified
|
||||
Log in to a Docker Registry located on the specified
|
||||
`SERVER`. You can specify a URL or a `hostname` for the `SERVER` value. If you
|
||||
do not specify a `SERVER`, the command uses Docker's public registry located at
|
||||
`https://registry-1.docker.io/` by default. To get a username/password for Docker's public registry, create an account on Docker Hub.
|
||||
|
||||
`docker login` requires user to use `sudo` or be `root`, except when:
|
||||
`docker login` requires user to use `sudo` or be `root`, except when:
|
||||
|
||||
1. connecting to a remote daemon, such as a `docker-machine` provisioned `docker engine`.
|
||||
2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/articles/security/#docker-daemon-attack-surface) for details.
|
||||
2. user is added to the `docker` group. This will impact the security of your system; the `docker` group is `root` equivalent. See [Docker Daemon Attack Surface](https://docs.docker.com/articles/security/#docker-daemon-attack-surface) for details.
|
||||
|
||||
You can log into any public or private repository for which you have
|
||||
credentials. When you log in, the command stores encoded credentials in
|
||||
|
@ -31,9 +30,6 @@ credentials. When you log in, the command stores encoded credentials in
|
|||
>
|
||||
|
||||
# OPTIONS
|
||||
**-e**, **--email**=""
|
||||
Email
|
||||
|
||||
**--help**
|
||||
Print usage statement
|
||||
|
||||
|
|
108
registry/auth.go
108
registry/auth.go
|
@ -1,7 +1,6 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
|
@ -24,11 +23,8 @@ func Login(authConfig *types.AuthConfig, registryEndpoint *Endpoint) (string, er
|
|||
// loginV1 tries to register/login to the v1 registry server.
|
||||
func loginV1(authConfig *types.AuthConfig, registryEndpoint *Endpoint) (string, error) {
|
||||
var (
|
||||
status string
|
||||
respBody []byte
|
||||
err error
|
||||
respStatusCode = 0
|
||||
serverAddress = authConfig.ServerAddress
|
||||
err error
|
||||
serverAddress = authConfig.ServerAddress
|
||||
)
|
||||
|
||||
logrus.Debugf("attempting v1 login to registry endpoint %s", registryEndpoint)
|
||||
|
@ -39,93 +35,37 @@ func loginV1(authConfig *types.AuthConfig, registryEndpoint *Endpoint) (string,
|
|||
|
||||
loginAgainstOfficialIndex := serverAddress == IndexServer
|
||||
|
||||
// to avoid sending the server address to the server it should be removed before being marshaled
|
||||
authCopy := *authConfig
|
||||
authCopy.ServerAddress = ""
|
||||
|
||||
jsonBody, err := json.Marshal(authCopy)
|
||||
req, err := http.NewRequest("GET", serverAddress+"users/", nil)
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
resp, err := registryEndpoint.client.Do(req)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Config Error: %s", err)
|
||||
return "", err
|
||||
}
|
||||
|
||||
// using `bytes.NewReader(jsonBody)` here causes the server to respond with a 411 status.
|
||||
b := strings.NewReader(string(jsonBody))
|
||||
resp1, err := registryEndpoint.client.Post(serverAddress+"users/", "application/json; charset=utf-8", b)
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Server Error: %s", err)
|
||||
return "", err
|
||||
}
|
||||
defer resp1.Body.Close()
|
||||
respStatusCode = resp1.StatusCode
|
||||
respBody, err = ioutil.ReadAll(resp1.Body)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("Server Error: [%#v] %s", respStatusCode, err)
|
||||
}
|
||||
|
||||
if respStatusCode == 201 {
|
||||
if resp.StatusCode == http.StatusOK {
|
||||
return "Login Succeeded", nil
|
||||
} else if resp.StatusCode == http.StatusUnauthorized {
|
||||
if loginAgainstOfficialIndex {
|
||||
status = "Account created. Please use the confirmation link we sent" +
|
||||
" to your e-mail to activate it."
|
||||
} else {
|
||||
// *TODO: Use registry configuration to determine what this says, if anything?
|
||||
status = "Account created. Please see the documentation of the registry " + serverAddress + " for instructions how to activate it."
|
||||
return "", fmt.Errorf("Wrong login/password, please try again. Haven't got a Docker ID? Create one at https://hub.docker.com")
|
||||
}
|
||||
} else if respStatusCode == 400 {
|
||||
if string(respBody) == "\"Username or email already exists\"" {
|
||||
req, err := http.NewRequest("GET", serverAddress+"users/", nil)
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
resp, err := registryEndpoint.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
return "Login Succeeded", nil
|
||||
} else if resp.StatusCode == 401 {
|
||||
return "", fmt.Errorf("Wrong login/password, please try again")
|
||||
} else if resp.StatusCode == 403 {
|
||||
if loginAgainstOfficialIndex {
|
||||
return "", fmt.Errorf("Login: Account is not Active. Please check your e-mail for a confirmation link.")
|
||||
}
|
||||
// *TODO: Use registry configuration to determine what this says, if anything?
|
||||
return "", fmt.Errorf("Login: Account is not Active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress)
|
||||
} else if resp.StatusCode == 500 { // Issue #14326
|
||||
logrus.Errorf("%s returned status code %d. Response Body :\n%s", req.URL.String(), resp.StatusCode, body)
|
||||
return "", fmt.Errorf("Internal Server Error")
|
||||
}
|
||||
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body, resp.StatusCode, resp.Header)
|
||||
}
|
||||
return "", fmt.Errorf("Registration: %s", respBody)
|
||||
|
||||
} else if respStatusCode == 401 {
|
||||
// This case would happen with private registries where /v1/users is
|
||||
// protected, so people can use `docker login` as an auth check.
|
||||
req, err := http.NewRequest("GET", serverAddress+"users/", nil)
|
||||
req.SetBasicAuth(authConfig.Username, authConfig.Password)
|
||||
resp, err := registryEndpoint.client.Do(req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if resp.StatusCode == 200 {
|
||||
return "Login Succeeded", nil
|
||||
} else if resp.StatusCode == 401 {
|
||||
return "", fmt.Errorf("Wrong login/password, please try again")
|
||||
} else {
|
||||
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
|
||||
resp.StatusCode, resp.Header)
|
||||
return "", fmt.Errorf("Wrong login/password, please try again")
|
||||
} else if resp.StatusCode == http.StatusForbidden {
|
||||
if loginAgainstOfficialIndex {
|
||||
return "", fmt.Errorf("Login: Account is not active. Please check your e-mail for a confirmation link.")
|
||||
}
|
||||
// *TODO: Use registry configuration to determine what this says, if anything?
|
||||
return "", fmt.Errorf("Login: Account is not active. Please see the documentation of the registry %s for instructions how to activate it.", serverAddress)
|
||||
} else if resp.StatusCode == http.StatusInternalServerError { // Issue #14326
|
||||
logrus.Errorf("%s returned status code %d. Response Body :\n%s", req.URL.String(), resp.StatusCode, body)
|
||||
return "", fmt.Errorf("Internal Server Error")
|
||||
} else {
|
||||
return "", fmt.Errorf("Unexpected status code [%d] : %s", respStatusCode, respBody)
|
||||
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
|
||||
resp.StatusCode, resp.Header)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// loginV2 tries to login to the v2 registry server. The given registry endpoint has been
|
||||
|
|
|
@ -14,7 +14,6 @@ func buildAuthConfigs() map[string]types.AuthConfig {
|
|||
authConfigs[registry] = types.AuthConfig{
|
||||
Username: "docker-user",
|
||||
Password: "docker-pass",
|
||||
Email: "docker@docker.io",
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,9 +29,6 @@ func TestSameAuthDataPostSave(t *testing.T) {
|
|||
if authConfig.Password != "docker-pass" {
|
||||
t.Fail()
|
||||
}
|
||||
if authConfig.Email != "docker@docker.io" {
|
||||
t.Fail()
|
||||
}
|
||||
if authConfig.Auth != "" {
|
||||
t.Fail()
|
||||
}
|
||||
|
@ -62,17 +58,14 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
|
|||
registryAuth := types.AuthConfig{
|
||||
Username: "foo-user",
|
||||
Password: "foo-pass",
|
||||
Email: "foo@example.com",
|
||||
}
|
||||
localAuth := types.AuthConfig{
|
||||
Username: "bar-user",
|
||||
Password: "bar-pass",
|
||||
Email: "bar@example.com",
|
||||
}
|
||||
officialAuth := types.AuthConfig{
|
||||
Username: "baz-user",
|
||||
Password: "baz-pass",
|
||||
Email: "baz@example.com",
|
||||
}
|
||||
authConfigs[IndexServer] = officialAuth
|
||||
|
||||
|
@ -105,7 +98,7 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
|
|||
|
||||
for configKey, registries := range validRegistries {
|
||||
configured, ok := expectedAuths[configKey]
|
||||
if !ok || configured.Email == "" {
|
||||
if !ok {
|
||||
t.Fail()
|
||||
}
|
||||
index := ®istrytypes.IndexInfo{
|
||||
|
@ -114,13 +107,13 @@ func TestResolveAuthConfigFullURL(t *testing.T) {
|
|||
for _, registry := range registries {
|
||||
authConfigs[registry] = configured
|
||||
resolved := ResolveAuthConfig(authConfigs, index)
|
||||
if resolved.Email != configured.Email {
|
||||
t.Errorf("%s -> %q != %q\n", registry, resolved.Email, configured.Email)
|
||||
if resolved.Username != configured.Username || resolved.Password != configured.Password {
|
||||
t.Errorf("%s -> %v != %v\n", registry, resolved, configured)
|
||||
}
|
||||
delete(authConfigs, registry)
|
||||
resolved = ResolveAuthConfig(authConfigs, index)
|
||||
if resolved.Email == configured.Email {
|
||||
t.Errorf("%s -> %q == %q\n", registry, resolved.Email, configured.Email)
|
||||
if resolved.Username == configured.Username || resolved.Password == configured.Password {
|
||||
t.Errorf("%s -> %v == %v\n", registry, resolved, configured)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -752,7 +752,6 @@ func (r *Session) GetAuthConfig(withPasswd bool) *types.AuthConfig {
|
|||
return &types.AuthConfig{
|
||||
Username: r.authConfig.Username,
|
||||
Password: password,
|
||||
Email: r.authConfig.Email,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue