Skip to content

Commit 2fed4f7

Browse files
committed
add an sso connecter
1 parent e444f83 commit 2fed4f7

File tree

4 files changed

+149
-18
lines changed

4 files changed

+149
-18
lines changed

Makefile

+2
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ check-version:
1414
build: check-version
1515
mkdir ${RELEASES}
1616
env GOOS=darwin GOARCH=amd64 go build -v -o ${RELEASES}/${OUT}-darwin-amd64 -ldflags="-X main.version=${VERSION}" ${PKG}
17+
env GOOS=darwin GOARCH=arm64 go build -v -o ${RELEASES}/${OUT}-darwin-arm64 -ldflags="-X main.version=${VERSION}" ${PKG}
1718
env GOOS=linux GOARCH=amd64 go build -v -o ${RELEASES}/${OUT}-linux-amd64 -ldflags="-X main.version=${VERSION}" ${PKG}
1819
env GOOS=linux GOARCH=arm64 go build -v -o ${RELEASES}/${OUT}-linux-arm64 -ldflags="-X main.version=${VERSION}" ${PKG}
1920
mv ${RELEASES}/${OUT}-linux-amd64 ${RELEASES}/${OUT} && cd ${RELEASES} && tar czf ${OUT}-${VERSION}-linux-amd64.tgz ${OUT}
2021
mv ${RELEASES}/${OUT}-linux-arm64 ${RELEASES}/${OUT} && cd ${RELEASES} && tar czf ${OUT}-${VERSION}-linux-arm64.tgz ${OUT}
22+
mv ${RELEASES}/${OUT}-darwin-arm64 ${RELEASES}/${OUT} && cd ${RELEASES} && tar czf ${OUT}-${VERSION}-darwin-arm64.tgz ${OUT}
2123
mv ${RELEASES}/${OUT}-darwin-amd64 ${RELEASES}/${OUT} && cd ${RELEASES} && tar czf ${OUT}-${VERSION}-darwin-amd64.tgz ${OUT}
2224

2325
release: build

cmd/connect_cmd.go

+142-16
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ import (
99
"log"
1010
"net/http"
1111
"os"
12+
"time"
1213

1314
"github.com/galleybytes/terraform-operator-api/pkg/api"
15+
"github.com/gin-gonic/gin"
16+
"github.com/skratchdot/open-golang/open"
1417
"github.com/spf13/cobra"
1518
"github.com/spf13/viper"
1619
xterm "golang.org/x/term"
@@ -29,12 +32,14 @@ var connectCmd = &cobra.Command{
2932
if host == "" {
3033
return fmt.Errorf("`--host` is required")
3134
}
35+
if viper.ConfigFileUsed() == "" {
36+
return fmt.Errorf("config file not defined")
37+
}
3238
return nil
3339
},
3440
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)
3843
},
3944
}
4045

@@ -45,7 +50,65 @@ func init() {
4550
rootCmd.AddCommand(connectCmd)
4651
}
4752

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"
49112
username = viper.GetString("username")
50113
if username == "" {
51114
fmt.Print("Login username: ")
@@ -57,9 +120,10 @@ func connect(url string) {
57120
password = []byte(viper.GetString("password")) // Not a very smart place to put a password...
58121
if len(password) == 0 {
59122
fmt.Print("Login password: ")
123+
60124
p, err := xterm.ReadPassword(int(os.Stdin.Fd()))
61125
if err != nil {
62-
log.Fatal(err)
126+
return "", err
63127
}
64128
fmt.Println()
65129
password = p
@@ -79,37 +143,99 @@ func connect(url string) {
79143
}
80144
b, err := json.Marshal(d)
81145
if err != nil {
82-
log.Fatal(err)
146+
return "", err
83147
}
84148
data := bytes.NewBuffer(b)
85149

86150
resp, err := httpClient.Post(url, "application/json", data)
87151
if err != nil {
88-
log.Panic(err)
152+
return "", err
89153
}
90154
defer resp.Body.Close()
91155

92156
body, err := io.ReadAll(resp.Body)
93157
if err != nil {
94-
log.Fatal(err)
158+
return "", err
95159
}
96160

97161
var respData api.Response
98162
err = json.Unmarshal(body, &respData)
99163
if err != nil {
100-
log.Fatal(err)
164+
return "", err
101165
}
102166

103167
if respData.StatusInfo.StatusCode != 200 {
104-
fmt.Println(respData.StatusInfo.Message)
105-
os.Exit(1)
168+
return "", fmt.Errorf(respData.StatusInfo.Message)
169+
106170
}
107171

108172
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+
}
114175

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+
}
115241
}

go.mod

+3-2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ module github.com/isaaguilar/terraform-operator-cli
33
go 1.20
44

55
require (
6+
github.com/gin-gonic/gin v1.8.1
7+
github.com/gorilla/websocket v1.5.0
8+
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966
69
github.com/spf13/cobra v1.7.0
710
github.com/spf13/viper v1.16.0
811
golang.org/x/term v0.9.0
@@ -31,7 +34,6 @@ require (
3134
github.com/fvbommel/sortorder v1.1.0 // indirect
3235
github.com/gammazero/deque v0.2.1 // indirect
3336
github.com/gin-contrib/sse v0.1.0 // indirect
34-
github.com/gin-gonic/gin v1.8.1 // indirect
3537
github.com/go-errors/errors v1.4.2 // indirect
3638
github.com/go-logr/logr v1.2.4 // indirect
3739
github.com/go-openapi/jsonpointer v0.19.6 // indirect
@@ -50,7 +52,6 @@ require (
5052
github.com/google/gofuzz v1.2.0 // indirect
5153
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
5254
github.com/google/uuid v1.3.0 // indirect
53-
github.com/gorilla/websocket v1.5.0 // indirect
5455
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
5556
github.com/hashicorp/hcl v1.0.0 // indirect
5657
github.com/imdario/mergo v0.3.16 // indirect

go.sum

+2
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
612612
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
613613
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
614614
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
615+
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA=
616+
github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog=
615617
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
616618
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
617619
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=

0 commit comments

Comments
 (0)