-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Expand file tree
/
Copy pathexternalauth.go
More file actions
138 lines (126 loc) · 3.69 KB
/
Copy pathexternalauth.go
File metadata and controls
138 lines (126 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package cli
import (
"encoding/json"
"github.com/tidwall/gjson"
"golang.org/x/xerrors"
"github.com/coder/coder/v2/cli/cliui"
"github.com/coder/coder/v2/codersdk/agentsdk"
"github.com/coder/serpent"
)
func externalAuth() *serpent.Command {
return &serpent.Command{
Use: "external-auth",
Short: "Manage external authentication",
Long: "Authenticate with external services inside of a workspace.",
Handler: func(i *serpent.Invocation) error {
return i.Command.HelpHandler(i)
},
Children: []*serpent.Command{
externalAuthAccessToken(),
},
}
}
func externalAuthAccessToken() *serpent.Command {
var (
extra string
outputFormat string
)
agentAuth := &AgentAuth{}
cmd := &serpent.Command{
Use: "access-token <provider>",
Short: "Print auth for an external provider",
Long: "Print an access-token for an external auth provider. " +
"The access-token will be validated and sent to stdout with exit code 0. " +
"If a valid access-token cannot be obtained, the URL to authenticate will be sent to stdout with exit code 1\n" + FormatExamples(
Example{
Description: "Ensure that the user is authenticated with GitHub before cloning.",
Command: `#!/usr/bin/env sh
OUTPUT=$(coder external-auth access-token github)
if [ $? -eq 0 ]; then
echo "Authenticated with GitHub"
else
echo "Please authenticate with GitHub:"
echo $OUTPUT
fi
`,
},
Example{
Description: "Obtain an extra property of an access token for additional metadata.",
Command: "coder external-auth access-token slack --extra \"authed_user.id\"",
},
Example{
Description: "Print the full token response as JSON.",
Command: "coder external-auth access-token github --output json",
},
),
Middleware: serpent.Chain(
serpent.RequireNArgs(1),
),
Options: serpent.OptionSet{
{
Name: "Extra",
Flag: "extra",
Description: "Extract a field from the \"extra\" properties of the OAuth token.",
Value: serpent.StringOf(&extra),
},
{
Name: "Output",
Flag: "output",
Description: "Output format. Available formats: text, json.",
Value: serpent.EnumOf(&outputFormat, "text", "json"),
Default: "text",
},
},
Handler: func(inv *serpent.Invocation) error {
ctx := inv.Context()
ctx, stop := inv.SignalNotifyContext(ctx, StopSignals...)
defer stop()
client, err := agentAuth.CreateClient()
if err != nil {
return xerrors.Errorf("create agent client: %w", err)
}
extAuth, err := client.ExternalAuth(ctx, agentsdk.ExternalAuthRequest{
ID: inv.Args[0],
})
if err != nil {
return xerrors.Errorf("get external auth token: %w", err)
}
switch {
case outputFormat == "json":
data, err := json.MarshalIndent(extAuth, "", " ")
if err != nil {
return xerrors.Errorf("marshal external auth response: %w", err)
}
if _, err := inv.Stdout.Write(data); err != nil {
return err
}
case extAuth.URL != "":
if _, err := inv.Stdout.Write([]byte(extAuth.URL)); err != nil {
return err
}
case extra != "":
if extAuth.TokenExtra == nil {
return xerrors.Errorf("no extra properties found for token")
}
data, err := json.Marshal(extAuth.TokenExtra)
if err != nil {
return xerrors.Errorf("marshal extra properties: %w", err)
}
result := gjson.GetBytes(data, extra)
if _, err := inv.Stdout.Write([]byte(result.String())); err != nil {
return err
}
default:
if _, err := inv.Stdout.Write([]byte(extAuth.AccessToken)); err != nil {
return err
}
}
if extAuth.URL != "" {
return cliui.ErrCanceled
}
return nil
},
}
agentAuth.AttachOptions(cmd, false)
return cmd
}