github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/api/authentication/visitor.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package authentication 5 6 import ( 7 "encoding/json" 8 "net/http" 9 "net/url" 10 11 "github.com/juju/errors" 12 13 "gopkg.in/macaroon-bakery.v1/httpbakery" 14 ) 15 16 const authMethod = "juju_userpass" 17 18 // Visitor is a httpbakery.Visitor that will login directly 19 // to the Juju controller using password authentication. This 20 // only applies when logging in as a local user. 21 type Visitor struct { 22 username string 23 getPassword func(string) (string, error) 24 } 25 26 // NewVisitor returns a new Visitor. 27 func NewVisitor(username string, getPassword func(string) (string, error)) *Visitor { 28 return &Visitor{ 29 username: username, 30 getPassword: getPassword, 31 } 32 } 33 34 // VisitWebPage is part of the httpbakery.Visitor interface. 35 func (v *Visitor) VisitWebPage(client *httpbakery.Client, methodURLs map[string]*url.URL) error { 36 methodURL := methodURLs[authMethod] 37 if methodURL == nil { 38 return httpbakery.ErrMethodNotSupported 39 } 40 41 password, err := v.getPassword(v.username) 42 if err != nil { 43 return err 44 } 45 46 // POST to the URL with username and password. 47 resp, err := client.PostForm(methodURL.String(), url.Values{ 48 "user": {v.username}, 49 "password": {password}, 50 }) 51 if err != nil { 52 return err 53 } 54 defer resp.Body.Close() 55 56 if resp.StatusCode == http.StatusOK { 57 return nil 58 } 59 var jsonError httpbakery.Error 60 if err := json.NewDecoder(resp.Body).Decode(&jsonError); err != nil { 61 return errors.Annotate(err, "unmarshalling error") 62 } 63 return &jsonError 64 }