Skip to content

Commit

Permalink
Bug fixes for JWT with scope and token extras (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
andyrzhao authored Aug 3, 2021
1 parent 937167c commit 6aa2b5c
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 39 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,17 +262,17 @@ $ oauth2l fetch --type oauth --credentials ~/client_credentials.json --scope clo

When jwt is selected and the json file specified in the `--credentials` option
is a service account key file, a JWT token signed by the service account private
key will be generated. Either `--scope` or `--audience` must be specified for
key will be generated. Either `--audience` or `--scope` must be specified for
this option. See how to construct the audience [here](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#jwt-auth).

- With scope:
- With audience:
```bash
$ oauth2l fetch --type jwt --credentials ~/client_credentials.json --scope cloud-platform
$ oauth2l fetch --type jwt --credentials ~/service_account.json --audience https://pubsub.googleapis.com/
```

- With audience:
- With scope:
```bash
$ oauth2l fetch --type jwt --credentials ~/service_account.json --audience https://pubsub.googleapis.com/
$ oauth2l fetch --type jwt --credentials ~/service_account.json --scope cloud-platform
```

#### sso
Expand Down
2 changes: 1 addition & 1 deletion integration/golden/no-scope-or-audience.golden
Original file line number Diff line number Diff line change
@@ -1 +1 @@
neither audience nor scope is provided
Neither audience nor scope argument is provided for JWT
8 changes: 7 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,11 +316,17 @@ func main() {
}
}

scopes := getScopesWithFallback(scope, remainingArgs...)
if audience == "" && len(scopes) < 1 {
fmt.Println("Neither audience nor scope argument is provided for JWT")
return
}

settings = &util.Settings{
AuthType: util.AuthTypeJWT,
CredentialsJSON: json,
Audience: audience,
Scope: scope,
Scope: parseScopes(scopes),
}
} else if authType == util.AuthTypeSSO {
// Fallback to reading email from first remaining arg
Expand Down
49 changes: 42 additions & 7 deletions util/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ func LookupCache(settings *Settings) (*oauth2.Token, error) {
if CacheLocation == "" {
return nil, nil
}
var token oauth2.Token
var cache, err = loadCache()
if err != nil {
return nil, err
Expand All @@ -63,11 +62,7 @@ func LookupCache(settings *Settings) (*oauth2.Token, error) {
return nil, err
}
val := cache[string(key)]
err = json.Unmarshal(val, &token)
if err != nil {
return nil, err
}
return &token, nil
return UnmarshalWithExtras(val)
}

func InsertCache(settings *Settings, token *oauth2.Token) error {
Expand All @@ -78,7 +73,7 @@ func InsertCache(settings *Settings, token *oauth2.Token) error {
if err != nil {
return err
}
val, err := json.Marshal(*token)
val, err := MarshalWithExtras(token, "")
if err != nil {
return err
}
Expand Down Expand Up @@ -155,3 +150,43 @@ func GuessUnixHomeDir() string {
}
return ""
}

// Marshals the given oauth2.Token into a JSON bytearray and include Extra
// fields that normally would be omitted with default marshalling.
func MarshalWithExtras(token *oauth2.Token, indent string) ([]byte, error) {
data, err := json.Marshal(token)
if err != nil {
return nil, err
}
var m map[string]string
err = json.Unmarshal(data, &m)
if err != nil {
return nil, err
}
if token.Extra("issued_token_type") != nil {
m["issued_token_type"] = token.Extra("issued_token_type").(string)
}
if token.Extra("id_token") != nil {
m["id_token"] = token.Extra("id_token").(string)
}
if token.Extra("scope") != nil {
m["scope"] = token.Extra("scope").(string)
}
return json.MarshalIndent(m, "", indent)
}

// Unmarshals the given JSON bytearray into oauth2.Token and include Extra
// fields that normally would be omitted with default unmarshalling.
func UnmarshalWithExtras(data []byte) (*oauth2.Token, error) {
var extra map[string]interface{}
err := json.Unmarshal(data, &extra)
if err != nil {
return nil, err
}
var token oauth2.Token
err = json.Unmarshal(data, &token)
if err != nil {
return nil, err
}
return token.WithExtra(extra), nil
}
5 changes: 2 additions & 3 deletions util/fetch.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ func newTokenSource(ctx context.Context, settings *Settings) (*oauth2.TokenSourc
} else if settings.GetAuthType() == AuthTypeJWT {
ts, err = JWTTokenSource(ctx, settings)
} else {
return nil, fmt.Errorf(
"Unsupported authentcation method: %s", settings.GetAuthType())
return nil, fmt.Errorf("Unsupported authentcation method: %s", settings.GetAuthType())
}
if err != nil {
return nil, err
Expand Down Expand Up @@ -86,7 +85,7 @@ func JWTTokenSource(ctx context.Context, settings *Settings) (oauth2.TokenSource
} else if settings.Scope != "" {
return google.JWTAccessTokenSourceWithScope(creds.JSON, settings.Scope)
} else {
return nil, errors.New("neither audience nor scope is provided")
return nil, errors.New("Neither audience nor scope is provided for JWTTokenSource")
}
}

Expand Down
23 changes: 1 addition & 22 deletions util/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,27 +227,6 @@ func getCredentialType(creds *google.Credentials) string {
return ""
}

// Marshals the given oauth2.Token into a JSON bytearray and include Extra
// fields that normally would be omitted with default marshalling.
func marshalWithExtras(token *oauth2.Token, indent string) ([]byte, error) {
data, err := json.Marshal(token)
if err != nil {
return nil, err
}
var m map[string]string
err = json.Unmarshal(data, &m)
if err != nil {
return nil, err
}
if token.Extra("issued_token_type") != nil {
m["issued_token_type"] = token.Extra("issued_token_type").(string)
}
if token.Extra("id_token") != nil {
m["id_token"] = token.Extra("id_token").(string)
}
return json.MarshalIndent(m, "", indent)
}

// Prints the token with the specified format.
func printToken(token *oauth2.Token, format string, settings *Settings) {
if token != nil {
Expand Down Expand Up @@ -295,7 +274,7 @@ func printHeader(tokenType string, token string) {
}

func printJson(token *oauth2.Token, indent string) {
data, err := marshalWithExtras(token, indent)
data, err := MarshalWithExtras(token, indent)
if err != nil {
log.Fatal(err.Error())
return
Expand Down

0 comments on commit 6aa2b5c

Please sign in to comment.