Skip to content

Commit

Permalink
supporting MFA and fixed some misc issues (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
rockspore authored Aug 20, 2020
1 parent 5bd533d commit a0d08ef
Show file tree
Hide file tree
Showing 8 changed files with 63 additions and 47 deletions.
22 changes: 10 additions & 12 deletions apigee/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,16 @@
package apigee

type Application struct {
AppID string `json:"appId"`
Attributes []interface{} `json:"attributes,omitempty"`
APIProducts []APIProductRef `json:"apiProducts,omitempty"`
CallBackURL string `json:"callbackUrl,omitempty"`
CreatedAt string `json:"createdAt,omitempty"`
Credentials []Credential `json:"credentials,omitempty"`
CompanyName string `json:"companyName,omitempty"`
DeveloperID string `json:"developerId,omitempty"`
LastModifiedAt string `json:"lastModifiedAt,omitempty"`
Name string `json:"name"`
Scopes []string `json:"scopes,omitempty"`
Status string `json:"status,omitempty"`
AppID string `json:"appId"`
Attributes interface{} `json:"attributes,omitempty"`
APIProducts []APIProductRef `json:"apiProducts,omitempty"`
CallBackURL string `json:"callbackUrl,omitempty"`
Credentials []Credential `json:"credentials,omitempty"`
CompanyName string `json:"companyName,omitempty"`
DeveloperID string `json:"developerId,omitempty"`
Name string `json:"name"`
Scopes []string `json:"scopes,omitempty"`
Status string `json:"status,omitempty"`
}

type Credential struct {
Expand Down
21 changes: 15 additions & 6 deletions apigee/edge_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import (
"net/url"
"os"
"path"
"strings"

"github.com/bgentry/go-netrc/netrc"
)
Expand Down Expand Up @@ -161,6 +160,9 @@ type EdgeAuth struct {
// Optional. Used if you explicitly specify a Password.
Password string

// Optional. Required if MFA (multi-factor authorization) is enabled.
MFAToken string

// if set to true, no auth will be set
SkipAuth bool

Expand Down Expand Up @@ -241,12 +243,13 @@ func NewEdgeClient(o *EdgeClientOptions) (*EdgeClient, error) {
Username: o.Auth.Username,
Password: o.Auth.Password,
BearerToken: o.Auth.BearerToken,
MFAToken: o.Auth.MFAToken,
}
}
if e != nil {
return nil, e
}
if o.MgmtURL == defaultBaseURL {
if o.MgmtURL == defaultBaseURL || c.auth.MFAToken != "" {
e = c.getOAuthToken()
if e != nil {
return nil, e
Expand All @@ -265,13 +268,19 @@ func NewEdgeClient(o *EdgeClientOptions) (*EdgeClient, error) {
}

func (c *EdgeClient) getOAuthToken() error {
oauthFormat := `username=%s&password=%s&grant_type=password`
oauthData := fmt.Sprintf(oauthFormat, c.auth.Username, c.auth.Password)
req, err := http.NewRequest(http.MethodPost, OAuthURL, strings.NewReader(oauthData))
req, err := http.NewRequest(http.MethodPost, OAuthURL, nil)
if err != nil {
return err
}
req.Header.Add("Content-type", "application/x-www-form-urlencoded;charset=utf-8")
q := req.URL.Query()
q.Set("username", c.auth.Username)
q.Set("password", c.auth.Password)
q.Set("grant_type", "password")
if c.auth.MFAToken != "" {
q.Set("mfa_token", c.auth.MFAToken)
}
req.URL.RawQuery = q.Encode()
req.Header.Add("Content-type", "application/x-www-form-urlencoded")
req.Header.Add("Authorization", basicAuthHeader)
res, err := c.client.Do(req)
if err != nil {
Expand Down
8 changes: 5 additions & 3 deletions cmd/bindings/bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ func Cmd(rootArgs *shared.RootArgs, printf shared.FormatFn) *cobra.Command {
"Apigee username (legacy or OPDK only)")
c.PersistentFlags().StringVarP(&rootArgs.Password, "password", "p", "",
"Apigee password (legacy or OPDK only)")
c.PersistentFlags().StringVarP(&rootArgs.MFAToken, "mfa", "", "",
"Apigee password (legacy)")
c.PersistentFlags().StringVarP(&rootArgs.ManagementBase, "management", "m",
"", "Apigee management base URL")

Expand Down Expand Up @@ -342,15 +344,15 @@ func (b *bindings) verifyAll(appMap map[string][]App, printf shared.FormatFn) er

func (b *bindings) verify(p *product.APIProduct, appMap map[string][]App, printf shared.FormatFn) error {
if p.GetBoundTargets() == nil {
printf("product %s is unbound to any target, no need to verify", p.Name)
printf("Product %s is unbound to any target, no need to verify.", p.Name)
return nil
}
apps, ok := appMap[p.Name]
if !ok {
printf("no app is found associated with product %s", p.Name)
printf("No app is found associated with product %s.", p.Name)
return nil
}
printf("verifying apps associated with product %s:", p.Name)
printf("Verifying apps associated with product %s:", p.Name)
for _, app := range apps {
if !app.hasRemoteService {
return fmt.Errorf(" app %s associated with product %s is not associated with remote-service product", app.name, p.Name)
Expand Down
12 changes: 6 additions & 6 deletions cmd/bindings/bindings_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,13 +225,13 @@ func TestBindingVerifyAll(t *testing.T) {
t.Errorf("want no error, got: %v", err)
}
wants = []string{
"product /product1/ is unbound to any target, no need to verify",
"product /product/ is unbound to any target, no need to verify",
"verifying apps associated with product /product2/:",
"Product /product1/ is unbound to any target, no need to verify.",
"Product /product/ is unbound to any target, no need to verify.",
"Verifying apps associated with product /product2/:",
" app /app1/ associated with product /product2/ is verified",
"verifying apps associated with product /product0/:",
"Verifying apps associated with product /product0/:",
" app /app0/ associated with product /product0/ is verified",
"no app is found associated with product /product4/",
"No app is found associated with product /product4/.",
}
print.Check(t, wants)
}
Expand All @@ -256,7 +256,7 @@ func TestBindingVerifyOne(t *testing.T) {
t.Errorf("want no error, got: %v", err)
}
wants = []string{
"verifying apps associated with product /product2/:",
"Verifying apps associated with product /product2/:",
" app /app1/ associated with product /product2/ is verified",
}
print.Check(t, wants)
Expand Down
2 changes: 2 additions & 0 deletions cmd/provision/provision.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ to your organization and environment.`,
"Apigee username (legacy or OPDK only)")
c.Flags().StringVarP(&rootArgs.Password, "password", "p", "",
"Apigee password (legacy or OPDK only)")
c.Flags().StringVarP(&rootArgs.MFAToken, "mfa", "", "",
"Apigee password (legacy)")

c.Flags().BoolVarP(&p.forceProxyInstall, "force-proxy-install", "f", false,
"force new proxy install (upgrades proxy)")
Expand Down
8 changes: 4 additions & 4 deletions cmd/samples/samples.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ files related to deployment of their target services.`,
}
printf("config files successfully generated.")
if s.template != "native" {
printf("please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.")
printf("Please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.")
}
return nil
},
Expand Down Expand Up @@ -151,11 +151,11 @@ func (s *samples) createSampleConfigs(printf shared.FormatFn) error {
return err
}
} else if s.overwrite {
printf("overwriting the existing directory...")
printf("Overwriting the existing directory!")
} else {
return fmt.Errorf("output directory already exists")
}
printf("generating %s configuration files...", s.template)
printf("Generating %s configuration files...", s.template)
return s.createConfig(s.template, printf)
}

Expand Down Expand Up @@ -196,7 +196,7 @@ func (s *samples) createConfigYaml(dir string, name string, printf shared.Format
if err != nil {
return err
}
printf("generating %s...", name)
printf(" generating %s...", name)
return tmpl.Execute(f, s)
}

Expand Down
32 changes: 16 additions & 16 deletions cmd/samples/samples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ func TestCreateNativeConfigs(t *testing.T) {
}

want := []string{
"generating native configuration files...",
"generating envoy-config.yaml...",
"Generating native configuration files...",
" generating envoy-config.yaml...",
"config files successfully generated.",
}

Expand Down Expand Up @@ -91,13 +91,13 @@ func TestCreateIstioConfigsWithHttpbin(t *testing.T) {
}

want := []string{
"generating istio-1.6 configuration files...",
"generating apigee-envoy-adapter.yaml...",
"generating envoyfilter-sidecar.yaml...",
"generating httpbin.yaml...",
"generating request-authentication.yaml...",
"Generating istio-1.6 configuration files...",
" generating apigee-envoy-adapter.yaml...",
" generating envoyfilter-sidecar.yaml...",
" generating httpbin.yaml...",
" generating request-authentication.yaml...",
"config files successfully generated.",
"please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.",
"Please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.",
}

print.CheckPrefix(t, want)
Expand Down Expand Up @@ -131,12 +131,12 @@ func TestCreateIstioConfigsWithoutHttpbin(t *testing.T) {
}

want := []string{
"generating istio-1.6 configuration files...",
"generating apigee-envoy-adapter.yaml...",
"generating envoyfilter-sidecar.yaml...",
"generating request-authentication.yaml...",
"Generating istio-1.6 configuration files...",
" generating apigee-envoy-adapter.yaml...",
" generating envoyfilter-sidecar.yaml...",
" generating request-authentication.yaml...",
"config files successfully generated.",
"please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.",
"Please enable istio sidecar injection on the default namespace before running kubectl apply on the directory with config files.",
}

print.CheckPrefix(t, want)
Expand Down Expand Up @@ -204,9 +204,9 @@ func TestExistingDirectoryOverwrite(t *testing.T) {
}

want := []string{
"overwriting the existing directory...",
"generating native configuration files...",
"generating envoy-config.yaml...",
"Overwriting the existing directory!",
"Generating native configuration files...",
" generating envoy-config.yaml...",
"config files successfully generated.",
}

Expand Down
5 changes: 5 additions & 0 deletions shared/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type RootArgs struct {
Env string
Username string
Password string
MFAToken string
Token string
NetrcPath string
IsOPDK bool
Expand Down Expand Up @@ -179,6 +180,7 @@ func (r *RootArgs) Resolve(skipAuth, requireRuntime bool) error {
Username: r.Username,
Password: r.Password,
BearerToken: r.Token,
MFAToken: r.MFAToken,
SkipAuth: skipAuth,
},
GCPManaged: r.IsGCPManaged,
Expand All @@ -196,6 +198,9 @@ func (r *RootArgs) Resolve(skipAuth, requireRuntime bool) error {
}
return fmt.Errorf("no auth: must have username and password or a ~/.netrc entry for %s", baseURL.Host)
}
if strings.Contains(err.Error(), "oauth") { // OAuth failure
return fmt.Errorf("error authorizing for OAuth token: %v", err)
}
return fmt.Errorf("error initializing Edge client: %v", err)
}

Expand Down

0 comments on commit a0d08ef

Please sign in to comment.