Skip to content

Commit d593e87

Browse files
committed
deduce organisation
1 parent 2fa0df8 commit d593e87

File tree

1 file changed

+20
-15
lines changed

1 file changed

+20
-15
lines changed

main.go

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,46 +81,47 @@ func main() {
8181
if verbose {
8282
fmt.Fprintln(os.Stderr, "input:", pairs)
8383
}
84-
result, err := authenticate(ctx)
84+
result, err := authenticate(ctx, pairs["username"])
8585
if err != nil {
8686
log.Fatalln(err)
8787
}
8888
if verbose {
8989
fmt.Fprintf(os.Stderr, "result: %+v\n", result)
9090
}
9191
organization := strings.SplitN(pairs["path"], "/", 2)[0]
92+
if organization == "" && !strings.Contains(pairs["username"], "@") {
93+
organization = pairs["username"]
94+
}
9295
var pt PatToken
96+
if organization == "" {
97+
fmt.Fprintln(os.Stderr, "unable to create personal access token because Azure DevOps organization not specified")
98+
}
9399
if organization != "" {
94100
pt, err = getPAT(organization, result.AccessToken)
95101
if err != nil {
96-
fmt.Fprintln(os.Stderr, "error acquiring Personal Access Token", err)
102+
fmt.Fprintln(os.Stderr, "error acquiring personal access token", err)
97103
}
98104
if verbose {
99105
fmt.Fprintf(os.Stderr, "pat: %+v\n", pt)
100106
}
101107
}
102-
var username string
103-
if pairs["username"] == "" {
104-
if organization != "" {
105-
username = organization
106-
} else {
107-
username = "oauth2"
108-
}
109-
}
110108
output := map[string]string{}
111-
if username != "" {
112-
output["username"] = username
113-
}
114109
var password string
115110
var expiry time.Time
111+
var username string
116112
if pt.Token != "" {
117113
password = pt.Token
118114
expiry = pt.ValidTo
115+
username = organization
119116
} else {
120117
password = result.AccessToken
121118
expiry = result.ExpiresOn
119+
username = result.Account.PreferredUsername
122120
}
123121
output["password"] = password
122+
if username != pairs["username"] {
123+
output["username"] = username
124+
}
124125
if !expiry.IsZero() {
125126
output["password_expiry_utc"] = fmt.Sprintf("%d", expiry.UTC().Unix())
126127
}
@@ -133,7 +134,7 @@ func main() {
133134
}
134135
}
135136

136-
func authenticate(ctx context.Context) (public.AuthResult, error) {
137+
func authenticate(ctx context.Context, username string) (public.AuthResult, error) {
137138
client, err := public.New(
138139
// https://github.com/git-ecosystem/git-credential-manager/blob/8c430c9484c90433ab30c25df7fc1005fe2f4ba4/src/shared/Microsoft.AzureRepos/AzureDevOpsConstants.cs#L15
139140
// magic https://developercommunity.visualstudio.com/t/non-interactive-aad-auth-works-for-visual-studio-a/387853
@@ -146,7 +147,11 @@ func authenticate(ctx context.Context) (public.AuthResult, error) {
146147
}
147148
// https://learn.microsoft.com/en-us/azure/devops/organizations/accounts/manage-personal-access-tokens-via-api?view=azure-devops
148149
scopes := []string{"499b84ac-1321-427f-aa17-267ca6975798/.default"}
149-
return client.AcquireTokenInteractive(ctx, scopes)
150+
opts := []public.AcquireInteractiveOption{}
151+
if strings.Contains(username, "@") {
152+
opts = append(opts, public.WithLoginHint(username))
153+
}
154+
return client.AcquireTokenInteractive(ctx, scopes, opts...)
150155
}
151156

152157
func getPAT(organization, accessToken string) (PatToken, error) {

0 commit comments

Comments
 (0)