3 // ========================LICENSE_START=================================
6 // Copyright (C) 2022-2023: Nordix Foundation
8 // Licensed under the Apache License, Version 2.0 (the "License");
9 // you may not use this file except in compliance with the License.
10 // You may obtain a copy of the License at
12 // http://www.apache.org/licenses/LICENSE-2.0
14 // Unless required by applicable law or agreed to in writing, software
15 // distributed under the License is distributed on an "AS IS" BASIS,
16 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 // See the License for the specific language governing permissions and
18 // limitations under the License.
19 // ========================LICENSE_END===================================
30 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31 kubernetes "k8s.io/client-go/kubernetes"
32 "k8s.io/client-go/rest"
36 "rapps/utils/generatejwt"
40 type Jwttoken struct {
43 Refresh_expires_in int
51 var keycloakHost string
52 var keycloakPort string
53 var keycloakAlias string
57 var authenticator string
61 var healthy bool = true
66 client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
69 func getToken(res http.ResponseWriter, req *http.Request) {
70 var resp = &http.Response{}
72 authenticator = req.Header.Get("authenticator")
73 clientId = req.Header.Get("client")
74 realmName = req.Header.Get("realm")
75 namespace = req.Header.Get("ns")
76 tlsCrt = req.Header.Get("tlsCrt")
77 tlsKey = req.Header.Get("tlsKey")
78 caCrt = req.Header.Get("caCrt")
79 keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/realms/" + realmName + "/protocol/openid-connect/token"
80 fmt.Printf("Making token request to %s\n", keycloakUrl)
81 res.Header().Set("Content-type", "application/json")
82 res.Header().Set("Authorization", "")
84 if authenticator == "client-jwt" {
85 resp, err = getJwtToken(keycloakUrl, clientId)
86 } else if authenticator == "client-x509" {
88 keycloakUrl := "https://" + keycloakAlias + ":" + keycloakPort + "/realms/" + realmName + "/protocol/openid-connect/token"
89 resp, err = getx509Token(keycloakUrl, clientId, tlsCrt, tlsKey, caCrt)
91 resp, err = getSecretToken(keycloakUrl, clientId)
96 res.WriteHeader(http.StatusInternalServerError)
97 res.Write([]byte(err.Error()))
98 panic("Something wrong with the credentials or url ")
101 defer resp.Body.Close()
102 body, err := ioutil.ReadAll(resp.Body)
103 json.Unmarshal([]byte(body), &jwt)
104 fmt.Printf("Token: %s\n", jwt.Access_token)
106 res.Header().Set("Authorization", "Bearer "+jwt.Access_token)
107 res.WriteHeader(http.StatusOK)
108 res.Write([]byte("Successfully retrieved JWT access token"))
111 func getJwtToken(keycloakUrl, clientId string) (*http.Response, error) {
112 var resp = &http.Response{}
114 client_assertion := getClientAssertion()
116 if jwt.Refresh_token != "" {
117 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
118 "client_assertion": {client_assertion}, "grant_type": {"refresh_token"},
119 "refresh_token": {jwt.Refresh_token}, "client_id": {clientId}, "scope": {scope}})
121 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
122 "client_assertion": {client_assertion}, "grant_type": {"client_credentials"},
123 "client_id": {clientId}, "scope": {scope}})
129 func getClientAssertion() string {
130 aud := "https://keycloak:8443/realms/" + realmName
131 clientAssertion := generatejwt.CreateJWT(tlsKey, "", clientId, aud)
132 return clientAssertion
135 func getx509Token(keycloakUrl, clientId, tlsCrt, tlsKey, caCrt string) (*http.Response, error) {
136 var resp = &http.Response{}
139 client := getClient()
140 resp, err = client.PostForm(keycloakUrl, url.Values{"username": {""}, "password": {""}, "grant_type": {"password"}, "client_id": {clientId}, "scope": {scope}})
145 func getClient() *http.Client {
146 caCert, _ := ioutil.ReadFile(caCrt)
147 caCertPool := x509.NewCertPool()
148 caCertPool.AppendCertsFromPEM(caCert)
150 cert, _ := tls.LoadX509KeyPair(tlsCrt, tlsKey)
152 dialer := &net.Dialer{
153 Timeout: 30 * time.Second,
154 KeepAlive: 30 * time.Second,
158 client := &http.Client{
159 Transport: &http.Transport{
160 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
161 fmt.Println("address original =", addr)
162 if addr == keycloakAlias+":"+keycloakPort {
163 addr = keycloakHost + ":" + keycloakPort
164 fmt.Println("address modified =", addr)
166 return dialer.DialContext(ctx, network, addr)
168 TLSClientConfig: &tls.Config{
170 Certificates: []tls.Certificate{cert},
177 func getSecretToken(keycloakUrl, clientId string) (*http.Response, error) {
178 var resp = &http.Response{}
181 secretName := clientId + "-secret"
182 clientSecret := getSecret(secretName)
183 resp, err = http.PostForm(keycloakUrl,
184 url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
189 func getSecret(secretName string) string {
190 clientset := connectToK8s()
191 res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
193 fmt.Println(err.Error())
195 return string(res.Data["client_secret"])
198 func connectToK8s() *kubernetes.Clientset {
199 config, err := rest.InClusterConfig()
201 fmt.Println("failed to create K8s config")
204 clientset, err := kubernetes.NewForConfig(config)
206 fmt.Println("Failed to create K8s clientset")
212 func health(res http.ResponseWriter, req *http.Request) {
214 res.WriteHeader(http.StatusOK)
215 res.Write([]byte("healthy"))
217 res.WriteHeader(http.StatusInternalServerError)
218 res.Write([]byte("unhealthy"))
223 flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
224 flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
225 flag.StringVar(&keycloakAlias, "keycloakAlias", "keycloak.est.tech", "Keycloak URL Alias")
228 healthHandler := http.HandlerFunc(health)
229 http.Handle("/health", healthHandler)
230 tokenHandler := http.HandlerFunc(getToken)
231 http.Handle("/token", tokenHandler)
232 http.ListenAndServe(":8888", nil)
234 ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)