github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/modelcmd/apicontext.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package modelcmd 5 6 import ( 7 "os" 8 9 "github.com/juju/errors" 10 "github.com/juju/gnuflag" 11 "github.com/juju/idmclient/ussologin" 12 "github.com/juju/persistent-cookiejar" 13 "gopkg.in/juju/environschema.v1/form" 14 "gopkg.in/macaroon-bakery.v1/httpbakery" 15 16 "github.com/juju/cmd" 17 "github.com/juju/juju/jujuclient" 18 ) 19 20 // APIContext holds the context required for making connections to 21 // APIs used by juju. 22 type APIContext struct { 23 Jar *cookiejar.Jar 24 WebPageVisitor httpbakery.Visitor 25 } 26 27 // AuthOpts holds flags relating to authentication. 28 type AuthOpts struct { 29 // NoBrowser specifies that web-browser-based auth should 30 // not be used when authenticating. 31 NoBrowser bool 32 } 33 34 func (o *AuthOpts) SetFlags(f *gnuflag.FlagSet) { 35 f.BoolVar(&o.NoBrowser, "B", false, "Do not use web browser for authentication") 36 f.BoolVar(&o.NoBrowser, "no-browser-login", false, "") 37 } 38 39 // NewAPIContext returns an API context that will use the given 40 // context for user interactions when authorizing. 41 // The returned API context must be closed after use. 42 // 43 // If ctxt is nil, no command-line authorization 44 // will be supported. 45 // 46 // This function is provided for use by commands that cannot use 47 // JujuCommandBase. Most clients should use that instead. 48 func NewAPIContext(ctxt *cmd.Context, opts *AuthOpts) (*APIContext, error) { 49 jar, err := cookiejar.New(&cookiejar.Options{ 50 Filename: cookieFile(), 51 }) 52 if err != nil { 53 return nil, errors.Trace(err) 54 } 55 var visitors []httpbakery.Visitor 56 if ctxt != nil && opts != nil && opts.NoBrowser { 57 filler := &form.IOFiller{ 58 In: ctxt.Stdin, 59 Out: ctxt.Stdout, 60 } 61 visitors = append(visitors, ussologin.NewVisitor("juju", filler, jujuclient.NewTokenStore())) 62 } else { 63 visitors = append(visitors, httpbakery.WebBrowserVisitor) 64 } 65 webPageVisitor := httpbakery.NewMultiVisitor(visitors...) 66 return &APIContext{ 67 Jar: jar, 68 WebPageVisitor: webPageVisitor, 69 }, nil 70 } 71 72 // NewBakeryClient returns a new httpbakery.Client, using the API context's 73 // persistent cookie jar and web page visitor. 74 func (ctx *APIContext) NewBakeryClient() *httpbakery.Client { 75 client := httpbakery.NewClient() 76 client.Jar = ctx.Jar 77 client.WebPageVisitor = ctx.WebPageVisitor 78 return client 79 } 80 81 // cookieFile returns the path to the cookie used to store authorization 82 // macaroons. The returned value can be overridden by setting the 83 // JUJU_COOKIEFILE or GO_COOKIEFILE environment variables. 84 func cookieFile() string { 85 if file := os.Getenv("JUJU_COOKIEFILE"); file != "" { 86 return file 87 } 88 return cookiejar.DefaultCookieFile() 89 } 90 91 // Close closes the API context, saving any cookies to the 92 // persistent cookie jar. 93 func (ctxt *APIContext) Close() error { 94 if err := ctxt.Jar.Save(); err != nil { 95 return errors.Annotatef(err, "cannot save cookie jar") 96 } 97 return nil 98 }