@@ -9,8 +9,11 @@ import (
9
9
"log"
10
10
"net/http"
11
11
"os"
12
+ "time"
12
13
13
14
"github.com/galleybytes/terraform-operator-api/pkg/api"
15
+ "github.com/gin-gonic/gin"
16
+ "github.com/skratchdot/open-golang/open"
14
17
"github.com/spf13/cobra"
15
18
"github.com/spf13/viper"
16
19
xterm "golang.org/x/term"
@@ -29,12 +32,14 @@ var connectCmd = &cobra.Command{
29
32
if host == "" {
30
33
return fmt .Errorf ("`--host` is required" )
31
34
}
35
+ if viper .ConfigFileUsed () == "" {
36
+ return fmt .Errorf ("config file not defined" )
37
+ }
32
38
return nil
33
39
},
34
40
Run : func (cmd * cobra.Command , args []string ) {
35
- url := host + "/login"
36
- log .Println ("Connecting to" , url )
37
- connect (url )
41
+ log .Println ("Connecting to" , host )
42
+ connect (host )
38
43
},
39
44
}
40
45
@@ -45,7 +50,65 @@ func init() {
45
50
rootCmd .AddCommand (connectCmd )
46
51
}
47
52
48
- func connect (url string ) {
53
+ func connect (host string ) {
54
+ var token string
55
+
56
+ connecter , err := getConnecter (host )
57
+ if err != nil {
58
+ log .Fatal (err )
59
+ }
60
+ if connecter == "sso" {
61
+ token , err = ssoConnecter (host )
62
+ if err != nil {
63
+ log .Fatal (err )
64
+ }
65
+ } else {
66
+ token , err = loginConnecter (host )
67
+ if err != nil {
68
+ log .Fatal (err )
69
+ }
70
+ }
71
+ fmt .Println ("Login succeeded" )
72
+ viper .Set ("host" , host )
73
+ viper .Set ("username" , username )
74
+ viper .Set ("token" , token )
75
+ viper .WriteConfig ()
76
+
77
+ }
78
+
79
+ func getConnecter (host string ) (string , error ) {
80
+ url := host + "/connect"
81
+ tr := & http.Transport {
82
+ TLSClientConfig : & tls.Config {InsecureSkipVerify : true },
83
+ }
84
+ httpClient := http.Client {Transport : tr }
85
+
86
+ resp , err := httpClient .Get (url )
87
+ if err != nil {
88
+ return "" , err
89
+ }
90
+ defer resp .Body .Close ()
91
+
92
+ body , err := io .ReadAll (resp .Body )
93
+ if err != nil {
94
+ return "" , err
95
+ }
96
+
97
+ var respData api.Response
98
+ err = json .Unmarshal (body , & respData )
99
+ if err != nil {
100
+ return "" , fmt .Errorf ("error parsing %s: %s" , url , string (body ))
101
+ }
102
+
103
+ if respData .StatusInfo .StatusCode != 200 {
104
+ return "" , fmt .Errorf (respData .StatusInfo .Message )
105
+ }
106
+
107
+ return respData .Data .([]interface {})[0 ].(string ), nil
108
+ }
109
+
110
+ func loginConnecter (host string ) (string , error ) {
111
+ url := host + "/login"
49
112
username = viper .GetString ("username" )
50
113
if username == "" {
51
114
fmt .Print ("Login username: " )
@@ -57,9 +120,10 @@ func connect(url string) {
57
120
password = []byte (viper .GetString ("password" )) // Not a very smart place to put a password...
58
121
if len (password ) == 0 {
59
122
fmt .Print ("Login password: " )
123
+
60
124
p , err := xterm .ReadPassword (int (os .Stdin .Fd ()))
61
125
if err != nil {
62
- log . Fatal ( err )
126
+ return "" , err
63
127
}
64
128
fmt .Println ()
65
129
password = p
@@ -79,37 +143,99 @@ func connect(url string) {
79
143
}
80
144
b , err := json .Marshal (d )
81
145
if err != nil {
82
- log . Fatal ( err )
146
+ return "" , err
83
147
}
84
148
data := bytes .NewBuffer (b )
85
149
86
150
resp , err := httpClient .Post (url , "application/json" , data )
87
151
if err != nil {
88
- log . Panic ( err )
152
+ return "" , err
89
153
}
90
154
defer resp .Body .Close ()
91
155
92
156
body , err := io .ReadAll (resp .Body )
93
157
if err != nil {
94
- log . Fatal ( err )
158
+ return "" , err
95
159
}
96
160
97
161
var respData api.Response
98
162
err = json .Unmarshal (body , & respData )
99
163
if err != nil {
100
- log . Fatal ( err )
164
+ return "" , err
101
165
}
102
166
103
167
if respData .StatusInfo .StatusCode != 200 {
104
- fmt .Println (respData .StatusInfo .Message )
105
- os . Exit ( 1 )
168
+ return "" , fmt .Errorf (respData .StatusInfo .Message )
169
+
106
170
}
107
171
108
172
token := respData .Data .([]interface {})[0 ].(string )
109
- fmt .Println ("Login succeeded" )
110
- viper .Set ("host" , host )
111
- viper .Set ("username" , username )
112
- viper .Set ("token" , token )
113
- viper .WriteConfig ()
173
+ return token , nil
174
+ }
114
175
176
+ func corsMiddleware () gin.HandlerFunc {
177
+ return func (c * gin.Context ) {
178
+ // Set CORS headers
179
+ c .Writer .Header ().Set ("Access-Control-Allow-Origin" , "*" )
180
+ c .Writer .Header ().Set ("Access-Control-Allow-Methods" , "POST, GET, OPTIONS, PUT, DELETE" )
181
+ c .Writer .Header ().Set ("Access-Control-Allow-Headers" , "*" )
182
+
183
+ // Check if the request method is OPTIONS
184
+ if c .Request .Method == "OPTIONS" {
185
+ // If so, abort with a 204 status code
186
+ c .AbortWithStatus (204 )
187
+ return
188
+ }
189
+
190
+ // Continue processing the request
191
+ c .Next ()
192
+ }
193
+ }
194
+
195
+ func ssoConnecter (host string ) (string , error ) {
196
+
197
+ gin .SetMode (gin .ReleaseMode )
198
+ gin .DefaultWriter = io .Discard // Shut up!
199
+ router := gin .Default ()
200
+
201
+ router .Use (corsMiddleware ())
202
+
203
+ stopCh := make (chan bool )
204
+ tokenCh := make (chan string )
205
+ errorCh := make (chan error )
206
+
207
+ router .POST ("/connecter" , func (c * gin.Context ) {
208
+ token := c .Query ("token" )
209
+ defer func () {
210
+ stopCh <- true
211
+ tokenCh <- token
212
+ }()
213
+ if token == "" {
214
+ c .AbortWithError (http .StatusNotFound , fmt .Errorf ("failed to get token" ))
215
+ return
216
+ }
217
+ fmt .Fprintln (c .Writer , "" )
218
+ })
219
+
220
+ go func () {
221
+ errorCh <- router .Run (":18080" )
222
+ }()
223
+
224
+ // Once the server has started, connect to the SSO Identity Provider (IDP)
225
+ err := open .Start (host + "/sso" )
226
+ if err != nil {
227
+ return "" , err
228
+ }
229
+
230
+ select {
231
+ case err := <- errorCh :
232
+ return "" , err
233
+ case <- stopCh :
234
+ token := <- tokenCh
235
+ time .Sleep (100 * time .Millisecond ) // Time for response to send
236
+ if token == "" {
237
+ return "" , fmt .Errorf ("the connecter did not receive a token" )
238
+ }
239
+ return token , nil
240
+ }
115
241
}
0 commit comments