Skip to content

Commit

Permalink
Merge pull request #200 from Scalingo/authentication_through_ssh
Browse files Browse the repository at this point in the history
Allow user to authenticate through SSH (scalingo login --ssh) Fixes #196
  • Loading branch information
Soulou committed Jan 21, 2016
2 parents e5bc839 + 98b3e0f commit ce3f194
Show file tree
Hide file tree
Showing 14 changed files with 337 additions and 117 deletions.
2 changes: 1 addition & 1 deletion Godeps/Godeps.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 7 additions & 8 deletions Godeps/_workspace/src/github.com/Scalingo/go-scalingo/auth.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions Godeps/_workspace/src/github.com/Scalingo/go-scalingo/http.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 12 additions & 4 deletions Godeps/_workspace/src/github.com/Scalingo/go-scalingo/users.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

This file was deleted.

4 changes: 2 additions & 2 deletions apps/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func (ctx *runContext) connectToRunServer(rawUrl string) (*http.Response, net.Co
if err != nil {
return nil, nil, errgo.Mask(err, errgo.Any)
}
req.SetBasicAuth("", scalingo.CurrentUser.AuthToken)
req.SetBasicAuth("", scalingo.CurrentUser.AuthenticationToken)

url, err := url.Parse(rawUrl)
if err != nil {
Expand Down Expand Up @@ -387,7 +387,7 @@ func (ctx *runContext) uploadFile(endpoint string, file string) error {
if err != nil {
return errgo.Mask(err, errgo.Any)
}
req.SetBasicAuth("", scalingo.CurrentUser.AuthToken)
req.SetBasicAuth("", scalingo.CurrentUser.AuthenticationToken)

req.Header.Set("Content-Type", multipartFile.FormDataContentType())

Expand Down
2 changes: 1 addition & 1 deletion apps/run/run_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func updateTtySize(url string) error {
if err != nil {
return errgo.Mask(err, errgo.Any)
}
req.SetBasicAuth("", scalingo.CurrentUser.AuthToken)
req.SetBasicAuth("", scalingo.CurrentUser.AuthenticationToken)

res, err := httpclient.Do(req)
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions cmd/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"time"

"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/Scalingo/go-scalingo"
"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/Scalingo/go-scalingo/users"
"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/Soulou/errgo-rollbar"
"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/stvp/rollbar"
"github.com/Scalingo/cli/Godeps/_workspace/src/gopkg.in/errgo.v1"
Expand All @@ -28,7 +27,7 @@ type Sysinfo struct {

type ReportError struct {
Time time.Time
User *users.User
User *scalingo.User
Error error
Command string
Version string
Expand Down
13 changes: 11 additions & 2 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,21 @@ var (
LoginCommand = cli.Command{
Name: "login",
Category: "Global",
Usage: "Login to Scalingo platform",
Flags: []cli.Flag{
cli.StringFlag{Name: "api-key", Usage: "Authenticate with an API key instead of login/password"},
cli.BoolFlag{Name: "ssh", Usage: "Login with you SSH identity instead of login/password"},
cli.StringFlag{Name: "ssh-identity", Value: "ssh-agent", Usage: "Use a custom SSH key, only compatible if --ssh is set"},
},
Usage: "Login to Scalingo platform",
Description: `
Example
'scalingo login'`,
Action: func(c *cli.Context) {
err := session.Login()
err := session.Login(session.LoginOpts{
ApiKey: c.String("api-key"),
Ssh: c.Bool("ssh"),
SshIdentity: c.String("ssh-identity"),
})
if err != nil {
errorQuit(err)
}
Expand Down
95 changes: 70 additions & 25 deletions config/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,18 @@ import (
"time"

"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/Scalingo/go-scalingo"
"github.com/Scalingo/cli/Godeps/_workspace/src/github.com/Scalingo/go-scalingo/users"
"github.com/Scalingo/cli/Godeps/_workspace/src/gopkg.in/errgo.v1"
"github.com/Scalingo/cli/config/auth"
"github.com/Scalingo/cli/debug"
"github.com/Scalingo/cli/term"
)

type CliAuthenticator struct{}

type AuthConfigData struct {
LastUpdate time.Time `json:"last_update"`
AuthConfigPerHost map[string]*users.User `json:"auth_config_data"`
}

var Authenticator = &CliAuthenticator{}

func Auth() (*users.User, error) {
var user *users.User
func Auth() (*scalingo.User, error) {
var user *scalingo.User
var err error

fmt.Fprintln(os.Stderr, "You need to be authenticated to use Scalingo client.\nNo account ? → https://scalingo.com")
Expand Down Expand Up @@ -57,35 +53,66 @@ func Auth() (*users.User, error) {
return user, nil
}

func (a *CliAuthenticator) StoreAuth(user *users.User) error {
func (a *CliAuthenticator) StoreAuth(user *scalingo.User) error {
authConfig, err := existingAuth()
if err != nil {
return errgo.Mask(err)
}

authConfig.AuthConfigPerHost[C.apiHost] = user
var c auth.ConfigPerHostV1
err = json.Unmarshal(authConfig.AuthConfigPerHost, &c)
if err != nil {
return errgo.Mask(err)
}

c[C.apiHost] = user
authConfig.LastUpdate = time.Now()

buffer, err := json.Marshal(&c)
if err != nil {
return errgo.Mask(err)
}

authConfig.AuthConfigPerHost = json.RawMessage(buffer)
return writeAuthFile(authConfig)
}

func (a *CliAuthenticator) LoadAuth() (*users.User, error) {
file, err := os.OpenFile(C.AuthFile, os.O_RDONLY, 0644)
func (a *CliAuthenticator) LoadAuth() (*scalingo.User, error) {
file, err := os.OpenFile(C.AuthFile, os.O_RDONLY, 0600)
if os.IsNotExist(err) {
return Auth()
}
if err != nil {
return nil, errgo.Mask(err, errgo.Any)
}
defer file.Close()

var authConfig AuthConfigData
dec := json.NewDecoder(file)
if err := dec.Decode(&authConfig); err != nil {
var authConfig auth.ConfigData
if err := json.NewDecoder(file).Decode(&authConfig); err != nil {
file.Close()
return nil, errgo.Mask(err, errgo.Any)
}
file.Close()

if authConfig.AuthDataVersion == "" {
debug.Println("auth config should be updated")
err = authConfig.MigrateToV1()
if err != nil {
return nil, errgo.Mask(err)
}
err = writeAuthFile(&authConfig)
if err != nil {
return nil, errgo.Mask(err)
}
debug.Println("auth config has been updated to V1")
}

var configPerHost auth.ConfigPerHostV1
err = json.Unmarshal(authConfig.AuthConfigPerHost, &configPerHost)
if err != nil {
return nil, errgo.Mask(err)
}

if user, ok := authConfig.AuthConfigPerHost[C.apiHost]; !ok {
if user, ok := configPerHost[C.apiHost]; !ok {
return Auth()
} else {
if user == nil {
Expand All @@ -100,14 +127,27 @@ func (a *CliAuthenticator) RemoveAuth() error {
if err != nil {
return errgo.Mask(err)
}
if _, ok := authConfig.AuthConfigPerHost[C.apiHost]; ok {
delete(authConfig.AuthConfigPerHost, C.apiHost)

var c auth.ConfigPerHostV1
err = json.Unmarshal(authConfig.AuthConfigPerHost, &c)
if err != nil {
return errgo.Mask(err)
}

if _, ok := c[C.apiHost]; ok {
delete(c, C.apiHost)
}

buffer, err := json.Marshal(&c)
if err != nil {
return errgo.Mask(err)
}

authConfig.AuthConfigPerHost = json.RawMessage(buffer)
return writeAuthFile(authConfig)
}

func tryAuth() (*users.User, error) {
func tryAuth() (*scalingo.User, error) {
var login string
var err error

Expand Down Expand Up @@ -136,29 +176,34 @@ func tryAuth() (*users.User, error) {
return user, nil
}

func writeAuthFile(auth *AuthConfigData) error {
func writeAuthFile(authConfig *auth.ConfigData) error {
file, err := os.OpenFile(C.AuthFile, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, 0700)
if err != nil {
return errgo.Mask(err, errgo.Any)
}
defer file.Close()

enc := json.NewEncoder(file)
if err := enc.Encode(auth); err != nil {
if err := enc.Encode(authConfig); err != nil {
return errgo.Mask(err, errgo.Any)
}
return nil

}

func existingAuth() (*AuthConfigData, error) {
authConfig := &AuthConfigData{}
func existingAuth() (*auth.ConfigData, error) {
authConfig := &auth.ConfigData{}
content, err := ioutil.ReadFile(C.AuthFile)
if err == nil {
// We don't care of the error
json.Unmarshal(content, &authConfig)
} else if os.IsNotExist(err) {
authConfig.AuthConfigPerHost = make(map[string]*users.User)
config := make(auth.ConfigPerHostV1)
buffer, err := json.Marshal(&config)
if err != nil {
return nil, errgo.Mask(err)
}
authConfig.AuthConfigPerHost = json.RawMessage(buffer)
} else {
return nil, errgo.Mask(err)
}
Expand Down
Loading

0 comments on commit ce3f194

Please sign in to comment.