cmd/tailscale/cli: [up] change oauth authkey format

Updates #7982

Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick 2023-04-26 13:20:58 -07:00 committed by Maisem Ali
parent 13de36303d
commit b2b5379348

View File

@ -1118,33 +1118,31 @@ func init() {
tailscale.I_Acknowledge_This_API_Is_Unstable = true tailscale.I_Acknowledge_This_API_Is_Unstable = true
} }
// resolveAuthKey either returns v unchanged (in the common case) // resolveAuthKey either returns v unchanged (in the common case) or, if it
// or, if it starts with "oauth:" parses it as one of: // starts with "tskey-client-" (as Tailscale OAuth secrets do) parses it like
// //
// oauth2:CLIENT_ID:CLIENT_SECRET?ephemeral=false&tags=foo,bar&preauthorized=BOOL // tskey-client-xxxx[?ephemeral=false&tags=foo,bar&preauthorized=BOOL&baseURL=...]
// oauth2:CLIENT_ID:CLIENT_SECRET:BASE_URL?...
// //
// and does the OAuth2 dance to get and return an authkey. The "ephemeral" property // and does the OAuth2 dance to get and return an authkey. The "ephemeral"
// defaults to true if unspecified. The "preauthorized" defaults to false. // property defaults to true if unspecified. The "preauthorized" defaults to
// // false. The "baseURL" defaults to
// If the BASE_URL argument is not provided, it defaults to https://api.tailscale.com. // https://api.tailscale.com.
func resolveAuthKey(ctx context.Context, v string) (string, error) { func resolveAuthKey(ctx context.Context, v string) (string, error) {
suff, ok := strings.CutPrefix(v, "oauth:") if !strings.HasPrefix(v, "tskey-client-") {
if !ok {
return v, nil return v, nil
} }
if !envknob.Bool("TS_EXPERIMENT_OAUTH_AUTHKEY") { if !envknob.Bool("TS_EXPERIMENT_OAUTH_AUTHKEY") {
return "", errors.New("oauth authkeys are in experimental status") return "", errors.New("oauth authkeys are in experimental status")
} }
pos, named, _ := strings.Cut(suff, "?") clientSecret, named, _ := strings.Cut(v, "?")
attrs, err := url.ParseQuery(named) attrs, err := url.ParseQuery(named)
if err != nil { if err != nil {
return "", err return "", err
} }
for k := range attrs { for k := range attrs {
switch k { switch k {
case "ephemeral", "preauthorized", "tags": case "ephemeral", "preauthorized", "tags", "baseURL":
default: default:
return "", fmt.Errorf("unknown attribute %q", k) return "", fmt.Errorf("unknown attribute %q", k)
} }
@ -1173,18 +1171,13 @@ func resolveAuthKey(ctx context.Context, v string) (string, error) {
tags = strings.Split(v, ",") tags = strings.Split(v, ",")
} }
f := strings.SplitN(pos, ":", 3)
if len(f) < 2 || len(f) > 3 {
return "", errors.New("invalid auth key format; want oauth2:CLIENT_ID:CLIENT_SECRET[:BASE_URL]")
}
clientID, clientSecret := f[0], f[1]
baseURL := "https://api.tailscale.com" baseURL := "https://api.tailscale.com"
if len(f) == 3 { if v := attrs.Get("baseURL"); v != "" {
baseURL = f[2] baseURL = v
} }
credentials := clientcredentials.Config{ credentials := clientcredentials.Config{
ClientID: clientID, ClientID: "some-client-id", // ignored
ClientSecret: clientSecret, ClientSecret: clientSecret,
TokenURL: baseURL + "/api/v2/oauth/token", TokenURL: baseURL + "/api/v2/oauth/token",
Scopes: []string{"device"}, Scopes: []string{"device"},