From 591324c858083da27235415d52ef386a07bfb407 Mon Sep 17 00:00:00 2001 From: Don Petersen Date: Mon, 9 Nov 2015 21:07:27 +0000 Subject: [PATCH] Add cli helpers, move service-to-service into this package. This probably could have been two changes, but here I really wasn't sure what I wanted to get to until I was finished. --- client/cliconfig/cliconfig.go | 100 ++++++++++++++++++++++++++++++++++ client/config.go | 35 +++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) create mode 100644 client/cliconfig/cliconfig.go diff --git a/client/cliconfig/cliconfig.go b/client/cliconfig/cliconfig.go new file mode 100644 index 0000000..879b5f2 --- /dev/null +++ b/client/cliconfig/cliconfig.go @@ -0,0 +1,100 @@ +// Package cliconfig provides integration with the codegangsta/cli library, so +// that CLI applications that require auth can easily get their command-line +// flags documented but integrated with what gog5auth requires. +// +// It is a separate package so that non-CLI packages won't end up pulling in +// the CLI code when they are importing the rest of gog5auth. +package cliconfig + +import ( + "fmt" + + "github.com/G5/gog5auth/client" + "github.com/codegangsta/cli" +) + +// CLI flags that may be registered and validated against by this package. You +// can use them in your own packages when you need to pull their values from +// the cli.Context. +const ( + ClientIDFlag = "g5-auth-client-id" + ClientSecretFlag = "g5-auth-client-secret" + EndpointFlag = "g5-auth-endpoint" + UsernameFlag = "g5-auth-username" + PasswordFlag = "g5-auth-password" +) + +var serviceToServiceIsRegistered bool + +// RegisterStandardFlags accepts an App to register flags that gog5auth +// accepts. This registers the typical flags for application and auth server. +// Should be paired with InitializeFromContext. +func RegisterStandardFlags(app *cli.App) { + fs := []cli.Flag{ + cli.StringFlag{ + Name: ClientIDFlag, + Usage: "G5 Auth application ID", + EnvVar: "G5_AUTH_CLIENT_ID", + }, + cli.StringFlag{ + Name: ClientSecretFlag, + Usage: "G5 Auth application secret", + EnvVar: "G5_AUTH_CLIENT_SECRET", + }, + cli.StringFlag{ + Name: EndpointFlag, + Value: client.Endpoint, + Usage: "G5 Auth endpoint", + EnvVar: "G5_AUTH_ENDPOINT", + }, + } + app.Flags = append(app.Flags, fs...) +} + +// InitializeFromContext sets all package-level variables based on the values +// of cli flags, whether they come from environment variables or from +// command-line flags. It will return an error if any required flag is not +// present. Any by required, I mean any, because they're all required. +// +// It will check for the presence of more flags if +// RegisterServiceToServiceFlags has been called. +func InitializeFromContext(c *cli.Context) error { + reqd := map[*string]string{ + &client.ClientID: ClientIDFlag, + &client.ClientSecret: ClientSecretFlag, + &client.Endpoint: EndpointFlag, + } + if serviceToServiceIsRegistered { + reqd[&client.ServiceAccountUsername] = UsernameFlag + reqd[&client.ServiceAccountPassword] = PasswordFlag + } + for toSet, flagName := range reqd { + s := c.String(flagName) + if s == "" { + return fmt.Errorf("missing required flag %s", flagName) + } + *toSet = s + } + + return nil +} + +// RegisterServiceToServiceFlags accepts an App to register flags that gog5auth +// accepts. This registers the flags needed for service-to-service auth. Should +// be paired with InitializeFromContext. +func RegisterServiceToServiceFlags(app *cli.App) { + serviceToServiceIsRegistered = true + fs := []cli.Flag{ + cli.StringFlag{ + Name: UsernameFlag, + Usage: "G5 Auth Service Account Username", + EnvVar: "G5_AUTH_USERNAME", + }, + cli.StringFlag{ + Name: PasswordFlag, + Usage: "G5 Auth Service Account Password", + EnvVar: "G5_AUTH_PASSWORD", + }, + } + app.Flags = append(app.Flags, fs...) +} diff --git a/client/config.go b/client/config.go index 7561788..9b4fa15 100644 --- a/client/config.go +++ b/client/config.go @@ -3,6 +3,7 @@ package client import ( "errors" "fmt" + "net/http" "os" "github.com/G5/oauth2" @@ -12,9 +13,11 @@ import ( // all are required. Use InitializeFromEnvironment to automatically set these // from G5-standard environment variable names. var ( - Endpoint = "auth.g5search.com" - ClientID string - ClientSecret string + Endpoint = "auth.g5search.com" + ClientID string + ClientSecret string + ServiceAccountUsername string + ServiceAccountPassword string ) // InitializeFromEnvironment sets package-level configuration via G5-standard @@ -67,3 +70,29 @@ func NewDefaultEndpoint() oauth2.Endpoint { TokenURL: fmt.Sprintf("https://%s/oauth/token", Endpoint), } } + +// ServiceToServiceClient instantiates a http.Client which will pass a token +// with all of its requests. If a token cannot be aquired, the Client will be +// nil and the error will show the issue. There will also be an error if the +// ServiceAccountUsername and ServiceAccountPassword are not set. +// +// This will make a network request to the auth server immediately, and will +// fail if there is a problem with any portion of the auth configuration. +// +// I am currently unsure of how the expiration of this token will affect the +// client. There is information in the oauth2 documentation that suggests it +// might refresh itself, but I have no tested it. +func ServiceToServiceClient() (*oauth2.Config, *http.Client, error) { + if ServiceAccountUsername == "" || ServiceAccountPassword == "" { + return nil, nil, errors.New("missing ServiceAccountUsername/ServiceAccountPassword values") + } + + conf := NewStandaloneConfig() + cl, err := PasswordAuthenticatedClientFromConfig( + conf, + ServiceAccountUsername, ServiceAccountPassword, + nil, + ) + + return conf, cl, err +}