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  }