github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 "gopkg.in/macaroon-bakery.v2-unstable/httpbakery" 13 ) 14 15 const authMethod = "juju_userpass" 16 17 // Visitor is a httpbakery.Visitor that will login directly 18 // to the Juju controller using password authentication. This 19 // only applies when logging in as a local user. 20 type Visitor struct { 21 username string 22 getPassword func(string) (string, error) 23 } 24 25 // NewVisitor returns a new Visitor. 26 func NewVisitor(username string, getPassword func(string) (string, error)) *Visitor { 27 return &Visitor{ 28 username: username, 29 getPassword: getPassword, 30 } 31 } 32 33 // VisitWebPage is part of the httpbakery.Visitor interface. 34 func (v *Visitor) VisitWebPage(client *httpbakery.Client, methodURLs map[string]*url.URL) error { 35 methodURL := methodURLs[authMethod] 36 if methodURL == nil { 37 return httpbakery.ErrMethodNotSupported 38 } 39 40 password, err := v.getPassword(v.username) 41 if err != nil { 42 return err 43 } 44 45 // POST to the URL with username and password. 46 resp, err := client.PostForm(methodURL.String(), url.Values{ 47 "user": {v.username}, 48 "password": {password}, 49 }) 50 if err != nil { 51 return err 52 } 53 defer resp.Body.Close() 54 55 if resp.StatusCode == http.StatusOK { 56 return nil 57 } 58 var jsonError httpbakery.Error 59 if err := json.NewDecoder(resp.Body).Decode(&jsonError); err != nil { 60 return errors.Annotate(err, "unmarshalling error") 61 } 62 return &jsonError 63 }