<commit_before>package adal

import (
	"github.com/mitchellh/go-homedir"
	"strconv"
)

// 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"`
	RefreshToken     string `json:"refreshToken"`
	Resource         string `json:"resource"`
	TokenType        string `json:"tokenType"`
	UserID           string `json:"userId"`
}

// AzureCLIProfile represents a Profile from the Azure CLI
type AzureCLIProfile struct {
	InstallationID string                 `json:"installationId"`
	Subscriptions  []AzureCLISubscription `json:"subscriptions"`
}

// AzureCLISubscription represents a Subscription from the Azure CLI
type AzureCLISubscription struct {
	EnvironmentName string `json:"environmentName"`
	ID              string `json:"id"`
	IsDefault       bool   `json:"isDefault"`
	Name            string `json:"name"`
	State           string `json:"state"`
	TenantID        string `json:"tenantId"`
}

// AzureCLIAccessTokensPath returns the path where access tokens are stored from the Azure CLI
func AzureCLIAccessTokensPath() (string, error) {
	return homedir.Expand("~/.azure/accessTokens.json")
}

// AzureCLIProfilePath returns the path where the Azure Profile is stored from the Azure CLI
func AzureCLIProfilePath() (string, error) {
	return homedir.Expand("~/.azure/azureProfile.json")
}

// ToToken converts an AzureCLIToken to a Token
func (t AzureCLIToken) ToToken() Token {
	return Token{
		AccessToken:  t.AccessToken,
		Type:         t.TokenType,
		ExpiresIn:    strconv.Itoa(t.ExpiresIn),
		ExpiresOn:    t.ExpiresOn,
		RefreshToken: t.RefreshToken,
		Resource:     t.Resource,
	}
}<commit_msg>Fixing AzureCLI / CloudShell authentication<commit_after>package adal

import (
	"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"`
	ExpiresOn        string `json:"expiresOn"`
	IdentityProvider string `json:"identityProvider"`
	IsMRRT           bool   `json:"isMRRT"`
	RefreshToken     string `json:"refreshToken"`
	Resource         string `json:"resource"`
	TokenType        string `json:"tokenType"`
	UserID           string `json:"userId"`
}

// AzureCLIProfile represents a Profile from the Azure CLI
type AzureCLIProfile struct {
	InstallationID string                 `json:"installationId"`
	Subscriptions  []AzureCLISubscription `json:"subscriptions"`
}

// AzureCLISubscription represents a Subscription from the Azure CLI
type AzureCLISubscription struct {
	EnvironmentName string `json:"environmentName"`
	ID              string `json:"id"`
	IsDefault       bool   `json:"isDefault"`
	Name            string `json:"name"`
	State           string `json:"state"`
	TenantID        string `json:"tenantId"`
}

// AzureCLIAccessTokensPath returns the path where access tokens are stored from the Azure CLI
func AzureCLIAccessTokensPath() (string, error) {
	return homedir.Expand("~/.azure/accessTokens.json")
}

// AzureCLIProfilePath returns the path where the Azure Profile is stored from the Azure CLI
func AzureCLIProfilePath() (string, error) {
	return homedir.Expand("~/.azure/azureProfile.json")
}

// ToToken converts an AzureCLIToken to a 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:    "3600",
		ExpiresOn:    strconv.Itoa(int(seconds)),
		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) {
	log.Printf("[DEBUG] Token Date: %s", input)

	// 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
}
{'fraction_non_alphanumeric': 0.10522104420884176, 'fraction_numerical': 0.009601920384076815, 'mean_word_length': 3.859086491739553, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6845866', 'n_tokens_mistral': 1603, 'n_tokens_neox': 1532, 'n_words': 426}