move auth to the client WIP

This commit is contained in:
Victor Vieux 2013-05-30 15:39:43 +00:00
parent 7ff2e6b797
commit 49e656839f
8 changed files with 55 additions and 168 deletions

50
api.go
View file

@ -66,48 +66,15 @@ func getBoolParam(value string) (bool, error) {
return false, fmt.Errorf("Bad parameter")
}
func getAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
// FIXME: Handle multiple login at once
// FIXME: return specific error code if config file missing?
authConfig, err := auth.LoadConfig(srv.runtime.root)
if err != nil {
if err != auth.ErrConfigFileMissing {
return err
}
authConfig = &auth.AuthConfig{}
}
b, err := json.Marshal(&auth.AuthConfig{Username: authConfig.Username, Email: authConfig.Email})
if err != nil {
return err
}
writeJson(w, b)
return nil
}
func postAuth(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
// FIXME: Handle multiple login at once
config := &auth.AuthConfig{}
if err := json.NewDecoder(r.Body).Decode(config); err != nil {
authConfig := &auth.AuthConfig{}
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return err
}
authConfig, err := auth.LoadConfig(srv.runtime.root)
if err != nil {
if err != auth.ErrConfigFileMissing {
return err
}
authConfig = &auth.AuthConfig{}
}
if config.Username == authConfig.Username {
config.Password = authConfig.Password
}
newAuthConfig := auth.NewAuthConfig(config.Username, config.Password, config.Email, srv.runtime.root)
status, err := auth.Login(newAuthConfig)
status, err := auth.Login(authConfig)
if err != nil {
return err
}
if status != "" {
b, err := json.Marshal(&ApiAuth{Status: status})
if err != nil {
@ -317,7 +284,9 @@ func postImagesCreate(srv *Server, version float64, w http.ResponseWriter, r *ht
if version > 1.0 {
w.Header().Set("Content-Type", "application/json")
}
if err := srv.ImagePull(image, tag, registry, w, version > 1.0); err != nil {
authConfig := &auth.AuthConfig{}
json.NewDecoder(r.Body).Decode(authConfig)
if err := srv.ImagePull(image, tag, registry, w, version > 1.0, authConfig); err != nil {
return err
}
} else { //import
@ -371,6 +340,10 @@ func postImagesInsert(srv *Server, version float64, w http.ResponseWriter, r *ht
}
func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
authConfig := &auth.AuthConfig{}
if err := json.NewDecoder(r.Body).Decode(authConfig); err != nil {
return err
}
if err := parseForm(r); err != nil {
return err
}
@ -381,7 +354,7 @@ func postImagesPush(srv *Server, version float64, w http.ResponseWriter, r *http
}
name := vars["name"]
if err := srv.ImagePush(name, registry, w); err != nil {
if err := srv.ImagePush(name, registry, w, authConfig); err != nil {
return err
}
return nil
@ -676,7 +649,6 @@ func ListenAndServe(addr string, srv *Server, logging bool) error {
m := map[string]map[string]func(*Server, float64, http.ResponseWriter, *http.Request, map[string]string) error{
"GET": {
"/auth": getAuth,
"/version": getVersion,
"/info": getInfo,
"/images/json": getImagesJson,

View file

@ -6,7 +6,6 @@ import (
"bytes"
"encoding/json"
"github.com/dotcloud/docker/auth"
"github.com/dotcloud/docker/registry"
"github.com/dotcloud/docker/utils"
"io"
"net"
@ -18,7 +17,7 @@ import (
"time"
)
func TestGetAuth(t *testing.T) {
func TestPostAuth(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
@ -54,12 +53,6 @@ func TestGetAuth(t *testing.T) {
if r.Code != http.StatusOK && r.Code != 0 {
t.Fatalf("%d OK or 0 expected, received %d\n", http.StatusOK, r.Code)
}
newAuthConfig := registry.NewRegistry(runtime.root).GetAuthConfig(false)
if newAuthConfig.Username != authConfig.Username ||
newAuthConfig.Email != authConfig.Email {
t.Fatalf("The auth configuration hasn't been set correctly")
}
}
func TestGetVersion(t *testing.T) {
@ -494,40 +487,6 @@ func TestGetContainersByName(t *testing.T) {
}
}
func TestPostAuth(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {
t.Fatal(err)
}
defer nuke(runtime)
srv := &Server{
runtime: runtime,
}
config := &auth.AuthConfig{
Username: "utest",
Email: "utest@yopmail.com",
}
authStr := auth.EncodeAuth(config)
auth.SaveConfig(runtime.root, authStr, config.Email)
r := httptest.NewRecorder()
if err := getAuth(srv, API_VERSION, r, nil, nil); err != nil {
t.Fatal(err)
}
authConfig := &auth.AuthConfig{}
if err := json.Unmarshal(r.Body.Bytes(), authConfig); err != nil {
t.Fatal(err)
}
if authConfig.Username != config.Username || authConfig.Email != config.Email {
t.Errorf("The retrieve auth mismatch with the one set.")
}
}
func TestPostCommit(t *testing.T) {
runtime, err := newTestRuntime()
if err != nil {

View file

@ -48,7 +48,7 @@ func IndexServerAddress() string {
}
// create a base64 encoded auth string to store in config
func EncodeAuth(authConfig *AuthConfig) string {
func encodeAuth(authConfig *AuthConfig) string {
authStr := authConfig.Username + ":" + authConfig.Password
msg := []byte(authStr)
encoded := make([]byte, base64.StdEncoding.EncodedLen(len(msg)))
@ -57,7 +57,7 @@ func EncodeAuth(authConfig *AuthConfig) string {
}
// decode the auth string
func DecodeAuth(authStr string) (*AuthConfig, error) {
func decodeAuth(authStr string) (*AuthConfig, error) {
decLen := base64.StdEncoding.DecodedLen(len(authStr))
decoded := make([]byte, decLen)
authByte := []byte(authStr)
@ -82,7 +82,7 @@ func DecodeAuth(authStr string) (*AuthConfig, error) {
func LoadConfig(rootPath string) (*AuthConfig, error) {
confFile := path.Join(rootPath, CONFIGFILE)
if _, err := os.Stat(confFile); err != nil {
return nil, ErrConfigFileMissing
return &AuthConfig{rootPath:rootPath}, ErrConfigFileMissing
}
b, err := ioutil.ReadFile(confFile)
if err != nil {
@ -94,7 +94,7 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
}
origAuth := strings.Split(arr[0], " = ")
origEmail := strings.Split(arr[1], " = ")
authConfig, err := DecodeAuth(origAuth[1])
authConfig, err := decodeAuth(origAuth[1])
if err != nil {
return nil, err
}
@ -104,13 +104,13 @@ func LoadConfig(rootPath string) (*AuthConfig, error) {
}
// save the auth config
func SaveConfig(rootPath, authStr string, email string) error {
confFile := path.Join(rootPath, CONFIGFILE)
if len(email) == 0 {
func SaveConfig(authConfig *AuthConfig) error {
confFile := path.Join(authConfig.rootPath, CONFIGFILE)
if len(authConfig.Email) == 0 {
os.Remove(confFile)
return nil
}
lines := "auth = " + authStr + "\n" + "email = " + email + "\n"
lines := "auth = " + encodeAuth(authConfig) + "\n" + "email = " + authConfig.Email + "\n"
b := []byte(lines)
err := ioutil.WriteFile(confFile, b, 0600)
if err != nil {
@ -121,7 +121,6 @@ func SaveConfig(rootPath, authStr string, email string) error {
// try to register/login to the registry server
func Login(authConfig *AuthConfig) (string, error) {
storeConfig := false
client := &http.Client{}
reqStatusCode := 0
var status string
@ -147,7 +146,6 @@ func Login(authConfig *AuthConfig) (string, error) {
if reqStatusCode == 201 {
status = "Account created. Please use the confirmation link we sent" +
" to your e-mail to activate it.\n"
storeConfig = true
} else if reqStatusCode == 403 {
return "", fmt.Errorf("Login: Your account hasn't been activated. " +
"Please check your e-mail for a confirmation link.")
@ -166,11 +164,7 @@ func Login(authConfig *AuthConfig) (string, error) {
}
if resp.StatusCode == 200 {
status = "Login Succeeded\n"
storeConfig = true
} else if resp.StatusCode == 401 {
if err := SaveConfig(authConfig.rootPath, "", ""); err != nil {
return "", err
}
return "", fmt.Errorf("Wrong login/password, please try again")
} else {
return "", fmt.Errorf("Login: %s (Code: %d; Headers: %s)", body,
@ -182,11 +176,5 @@ func Login(authConfig *AuthConfig) (string, error) {
} else {
return "", fmt.Errorf("Unexpected status code [%d] : %s", reqStatusCode, reqBody)
}
if storeConfig {
authStr := EncodeAuth(authConfig)
if err := SaveConfig(authConfig.rootPath, authStr, authConfig.Email); err != nil {
return "", err
}
}
return status, nil
}

View file

@ -63,7 +63,7 @@ func (b *buildFile) CmdFrom(name string) error {
remote = name
}
if err := b.srv.ImagePull(remote, tag, "", b.out, false); err != nil {
if err := b.srv.ImagePull(remote, tag, "", b.out, false, nil); err != nil {
return err
}

View file

@ -279,27 +279,16 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
return nil
}
body, _, err := cli.call("GET", "/auth", nil)
if err != nil {
return err
}
var out auth.AuthConfig
err = json.Unmarshal(body, &out)
if err != nil {
return err
}
var username string
var password string
var email string
fmt.Print("Username (", out.Username, "): ")
fmt.Print("Username (", cli.authConfig.Username, "): ")
username = readAndEchoString(os.Stdin, os.Stdout)
if username == "" {
username = out.Username
username = cli.authConfig.Username
}
if username != out.Username {
if username != cli.authConfig.Username {
fmt.Print("Password: ")
password = readString(os.Stdin, os.Stdout)
@ -307,20 +296,21 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
return fmt.Errorf("Error : Password Required")
}
fmt.Print("Email (", out.Email, "): ")
fmt.Print("Email (", cli.authConfig.Email, "): ")
email = readAndEchoString(os.Stdin, os.Stdout)
if email == "" {
email = out.Email
email = cli.authConfig.Email
}
} else {
email = out.Email
email = cli.authConfig.Email
}
term.RestoreTerminal(oldState)
out.Username = username
out.Password = password
out.Email = email
cli.authConfig.Username = username
cli.authConfig.Password = password
cli.authConfig.Email = email
body, _, err = cli.call("POST", "/auth", out)
body, _, err := cli.call("POST", "/auth", cli.authConfig)
if err != nil {
return err
}
@ -328,10 +318,11 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
var out2 ApiAuth
err = json.Unmarshal(body, &out2)
if err != nil {
auth.LoadConfig(os.Getenv("HOME"))
return err
}
auth.SaveConfig(cli.authConfig)
if out2.Status != "" {
term.RestoreTerminal(oldState)
fmt.Print(out2.Status)
}
return nil
@ -688,13 +679,12 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return nil
}
username, err := cli.checkIfLogged(*registry == "", "push")
if err != nil {
if err := cli.checkIfLogged(*registry == "", "push"); err != nil {
return err
}
if len(strings.SplitN(name, "/", 2)) == 1 {
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", username, name)
return fmt.Errorf("Impossible to push a \"root\" repository. Please rename your repository in <user>/<repo> (ex: %s/%s)", cli.authConfig.Username, name)
}
v := url.Values{}
@ -726,7 +716,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
}
if strings.Contains(remote, "/") {
if _, err := cli.checkIfLogged(true, "pull"); err != nil {
if err := cli.checkIfLogged(true, "pull"); err != nil {
return err
}
}
@ -1220,38 +1210,17 @@ func (cli *DockerCli) CmdRun(args ...string) error {
return nil
}
func (cli *DockerCli) checkIfLogged(condition bool, action string) (string, error) {
body, _, err := cli.call("GET", "/auth", nil)
if err != nil {
return "", err
}
var out auth.AuthConfig
err = json.Unmarshal(body, &out)
if err != nil {
return "", err
}
func (cli *DockerCli) checkIfLogged(condition bool, action string) error {
// If condition AND the login failed
if condition && out.Username == "" {
if condition && cli.authConfig.Username == "" {
if err := cli.CmdLogin(""); err != nil {
return "", err
return err
}
body, _, err = cli.call("GET", "/auth", nil)
if err != nil {
return "", err
}
err = json.Unmarshal(body, &out)
if err != nil {
return "", err
}
if out.Username == "" {
return "", fmt.Errorf("Please login prior to %s. ('docker login')", action)
if cli.authConfig.Username == "" {
return fmt.Errorf("Please login prior to %s. ('docker login')", action)
}
}
return out.Username, nil
return nil
}
func (cli *DockerCli) call(method, path string, data interface{}) ([]byte, int, error) {
@ -1435,10 +1404,12 @@ func Subcmd(name, signature, description string) *flag.FlagSet {
}
func NewDockerCli(addr string, port int) *DockerCli {
return &DockerCli{addr, port}
authConfig, _ := auth.LoadConfig(os.Getenv("HOME"))
return &DockerCli{addr, port, authConfig}
}
type DockerCli struct {
host string
port int
host string
port int
authConfig *auth.AuthConfig
}

View file

@ -466,10 +466,7 @@ type Registry struct {
authConfig *auth.AuthConfig
}
func NewRegistry(root string) *Registry {
// If the auth file does not exist, keep going
authConfig, _ := auth.LoadConfig(root)
func NewRegistry(root string, authConfig *auth.AuthConfig) *Registry {
r := &Registry{
authConfig: authConfig,
client: &http.Client{},

View file

@ -65,7 +65,7 @@ func init() {
runtime: runtime,
}
// Retrieve the Image
if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false); err != nil {
if err := srv.ImagePull(unitTestImageName, "", "", os.Stdout, false, nil); err != nil {
panic(err)
}
}

View file

@ -50,7 +50,7 @@ func (srv *Server) ContainerExport(name string, out io.Writer) error {
func (srv *Server) ImagesSearch(term string) ([]ApiSearch, error) {
results, err := registry.NewRegistry(srv.runtime.root).SearchRepositories(term)
results, err := registry.NewRegistry(srv.runtime.root, nil).SearchRepositories(term)
if err != nil {
return nil, err
}
@ -394,8 +394,8 @@ func (srv *Server) pullRepository(r *registry.Registry, out io.Writer, remote, a
return nil
}
func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool) error {
r := registry.NewRegistry(srv.runtime.root)
func (srv *Server) ImagePull(name, tag, endpoint string, out io.Writer, json bool, authConfig *auth.AuthConfig) error {
r := registry.NewRegistry(srv.runtime.root, authConfig)
out = utils.NewWriteFlusher(out)
if endpoint != "" {
if err := srv.pullImage(r, out, name, endpoint, nil, json); err != nil {
@ -576,10 +576,10 @@ func (srv *Server) pushImage(r *registry.Registry, out io.Writer, remote, imgId,
return nil
}
func (srv *Server) ImagePush(name, endpoint string, out io.Writer) error {
func (srv *Server) ImagePush(name, endpoint string, out io.Writer, authConfig *auth.AuthConfig) error {
out = utils.NewWriteFlusher(out)
img, err := srv.runtime.graph.Get(name)
r := registry.NewRegistry(srv.runtime.root)
r := registry.NewRegistry(srv.runtime.root, authConfig)
if err != nil {
fmt.Fprintf(out, "The push refers to a repository [%s] (len: %d)\n", name, len(srv.runtime.repositories.Repositories[name]))