-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fixing AzureCLI / CloudShell authentication #169
Changes from 1 commit
a04d94c
575eb82
ede361e
a32ff8d
954fd09
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,19 @@ | ||
package adal | ||
|
||
import ( | ||
"github.com/mitchellh/go-homedir" | ||
"fmt" | ||
"log" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/mitchellh/go-homedir" | ||
) | ||
|
||
// AzureCLIToken represents an AccessToken from the Azure CLI | ||
type AzureCLIToken struct { | ||
AccessToken string `json:"accessToken"` | ||
Authority string `json:"_authority"` | ||
ClientID string `json:"_clientId"` | ||
ExpiresIn int `json:"expiresIn"` | ||
ExpiresOn string `json:"expiresOn"` | ||
IdentityProvider string `json:"identityProvider"` | ||
IsMRRT bool `json:"isMRRT"` | ||
|
@@ -47,13 +50,42 @@ func AzureCLIProfilePath() (string, error) { | |
} | ||
|
||
// ToToken converts an AzureCLIToken to a Token | ||
func (t AzureCLIToken) ToToken() Token { | ||
return Token{ | ||
func (t AzureCLIToken) ToToken() (*Token, error) { | ||
tokenExpirationDate, err := ParseAzureCLIExpirationDate(t.ExpiresOn) | ||
if err != nil { | ||
return nil, fmt.Errorf("Error parsing Token Expiration Date %q: %+v", t.ExpiresOn, err) | ||
} | ||
|
||
difference := tokenExpirationDate.Sub(expirationBase) | ||
seconds := difference.Seconds() | ||
|
||
token := Token{ | ||
AccessToken: t.AccessToken, | ||
Type: t.TokenType, | ||
ExpiresIn: strconv.Itoa(t.ExpiresIn), | ||
ExpiresOn: t.ExpiresOn, | ||
ExpiresIn: "3600", | ||
ExpiresOn: strconv.Itoa(int(seconds)), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [nit] I think this would be more readable as There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated :) |
||
RefreshToken: t.RefreshToken, | ||
Resource: t.Resource, | ||
} | ||
return &token, nil | ||
} | ||
|
||
// ParseAzureCLIExpirationDate parses either a Azure CLI or CloudShell date into a time object | ||
func ParseAzureCLIExpirationDate(input string) (*time.Time, error) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Q: why do you return pointer to time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I’ve opted for this approach since we’re returning nil for an invalid/unparseable date; given returning an empty object in addition to an error in the failure case feels misleading as a consumer of the API There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It seems like you use that pattern pretty religiously, @tombuildsstuff. I'm not really convinced either way, other than sorta general intuitiveness, can you build a case for why it's better to return a pointer? Personally, when I'm writing Go, I just treat retvals that accompany an error as garbage, it doesn't matter if the value is the default or memory with random bits. As you can imagine, in my workflow, changing the return type to a pointer has almost no consequence. What scenario am I missing where it's totally important? :) edit: this isn't important enough for me to hold up a PR. Don't feel like this comment is holding you hostage. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not particularly - I've only opted for this approach to force the consumer to handle the error case, rather than accidental comparing the values returned by the default object (it's more habit than anything else) - but totally happy to switch this out :) |
||
log.Printf("[DEBUG] Token Date: %s", input) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's remove this line before we commit this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated :) |
||
|
||
// CloudShell (and potentially the Azure CLI in future) | ||
expirationDate, cloudShellErr := time.Parse(time.RFC3339, input) | ||
if cloudShellErr != nil { | ||
// Azure CLI (Python) e.g. 2017-08-31 19:48:57.998857 (plus the local timezone) | ||
cliFormat := "2006-01-02 15:04:05.999999" | ||
expirationDate, cliErr := time.ParseInLocation(cliFormat, input, time.Local) | ||
if cliErr == nil { | ||
return &expirationDate, nil | ||
} | ||
|
||
return nil, fmt.Errorf("Error parsing expiration date %q.\n\nCloudShell Error: \n%+v\n\nCLI Error:\n%+v", input, cloudShellErr, cliErr) | ||
} | ||
|
||
return &expirationDate, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about this a little this morning, and think that this code would be better off in a
cli
package. Particularly, I think it makes sense as a child of theazure
package. In general, I'd like to have as few Azure specific references in theadal
package as possible, that applies doubly to CLI specific code :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated :)