forked from micahhausler/k8s-oidc-helper
/
helper.go
157 lines (135 loc) · 3.52 KB
/
helper.go
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package helper
import (
"encoding/json"
"fmt"
"net/http"
"net/url"
"os"
"os/exec"
"runtime"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
)
type ConfigFile struct {
Installed *GoogleConfig `json:"installed"`
}
type GoogleConfig struct {
ClientID string `json:"client_id"`
ClientSecret string `json:"client_secret"`
}
type TokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
IdToken string `json:"id_token"`
}
func ReadConfig(path string) (*GoogleConfig, error) {
f, err := os.Open(path)
defer f.Close()
if err != nil {
return nil, err
}
cf := &ConfigFile{}
err = json.NewDecoder(f).Decode(cf)
if err != nil {
return nil, err
}
return cf.Installed, nil
}
// Get the id_token and refresh_token from google
func GetToken(clientID, clientSecret, code string) (*TokenResponse, error) {
val := url.Values{}
val.Add("grant_type", "authorization_code")
val.Add("redirect_uri", "urn:ietf:wg:oauth:2.0:oob")
val.Add("client_id", clientID)
val.Add("client_secret", clientSecret)
val.Add("code", code)
resp, err := http.PostForm("https://www.googleapis.com/oauth2/v3/token", val)
defer resp.Body.Close()
if err != nil {
return nil, err
}
tr := &TokenResponse{}
err = json.NewDecoder(resp.Body).Decode(tr)
if err != nil {
return nil, err
}
return tr, nil
}
type KubectlUser struct {
Name string `yaml:"name"`
KubeUserInfo *KubeUserInfo `yaml:"user"`
}
type KubeUserInfo struct {
AuthProvider *AuthProvider `yaml:"auth-provider"`
}
type AuthProvider struct {
APConfig *APConfig `yaml:"config"`
Name string `yaml:"name"`
}
type APConfig struct {
ClientID string `yaml:"client-id"`
ClientSecret string `yaml:"client-secret"`
IdToken string `yaml:"id-token"`
IdpIssuerUrl string `yaml:"idp-issuer-url"`
RefreshToken string `yaml:"refresh-token"`
}
type UserInfo struct {
Email string `json:"email"`
}
func GetUserEmail(accessToken string) (string, error) {
uri, _ := url.Parse("https://www.googleapis.com/oauth2/v1/userinfo")
q := uri.Query()
q.Set("alt", "json")
q.Set("access_token", accessToken)
uri.RawQuery = q.Encode()
resp, err := http.Get(uri.String())
defer resp.Body.Close()
if err != nil {
return "", err
}
ui := &UserInfo{}
err = json.NewDecoder(resp.Body).Decode(ui)
if err != nil {
return "", err
}
return ui.Email, nil
}
func GenerateAuthInfo(clientId, clientSecret, idToken, refreshToken string) *clientcmdapi.AuthInfo {
return &clientcmdapi.AuthInfo{
AuthProvider: &clientcmdapi.AuthProviderConfig{
Name: "oidc",
Config: map[string]string{
"client-id": clientId,
"client-secret": clientSecret,
"id-token": idToken,
"idp-issuer-url": "https://accounts.google.com",
"refresh-token": refreshToken,
},
},
}
}
func createOpenCmd(oauthUrl, clientID string) (*exec.Cmd, error) {
url := fmt.Sprintf(oauthUrl, clientID)
switch os := runtime.GOOS; os {
case "darwin":
return exec.Command("open", url), nil
case "linux":
return exec.Command("xdg-open", url), nil
}
return nil, fmt.Errorf("Could not detect the open command for OS: %s", runtime.GOOS)
}
func LaunchBrowser(openBrowser bool, oauthUrl, clientID string) {
openInstructions := fmt.Sprintf("Open this url in your browser: %s\n", fmt.Sprintf(oauthUrl, clientID))
if !openBrowser {
fmt.Print(openInstructions)
return
}
cmd, err := createOpenCmd(oauthUrl, clientID)
if err != nil {
fmt.Print(openInstructions)
return
}
err = cmd.Start()
if err != nil {
fmt.Print(openInstructions)
}
}