2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022-2023: Nordix Foundation
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // ========================LICENSE_END===================================
29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
30 kubernetes "k8s.io/client-go/kubernetes"
31 "k8s.io/client-go/rest"
34 "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
58 var healthy bool = true
63 client_assertion_type = "urn:ietf:params:oauth:client-assertion-type:jwt-bearer"
66 func getToken(res http.ResponseWriter, req *http.Request) {
67 var resp = &http.Response{}
69 authenticator = req.Header.Get("authenticator")
70 clientId = req.Header.Get("client")
71 realmName = req.Header.Get("realm")
72 namespace = req.Header.Get("ns")
73 keycloakUrl := "http://" + keycloakHost + ":" + keycloakPort + "/realms/" + realmName + "/protocol/openid-connect/token"
74 fmt.Printf("Making token request to %s\n", keycloakUrl)
75 res.Header().Set("Content-type", "application/json")
76 res.Header().Set("Authorization", "")
78 if authenticator == "client-jwt" {
79 resp, err = getJwtToken(keycloakUrl, clientId)
80 } else if authenticator == "client-x509" {
82 keycloakUrl := "https://" + keycloakAlias + ":" + keycloakPort + "/realms/" + realmName + "/protocol/openid-connect/token"
83 resp, err = getx509Token(keycloakUrl, clientId)
85 resp, err = getSecretToken(keycloakUrl, clientId)
90 res.WriteHeader(http.StatusInternalServerError)
91 res.Write([]byte(err.Error()))
92 panic("Something wrong with the credentials or url ")
95 defer resp.Body.Close()
96 body, err := ioutil.ReadAll(resp.Body)
97 json.Unmarshal([]byte(body), &jwt)
98 fmt.Printf("Token: %s\n", jwt.Access_token)
100 res.Header().Set("Authorization", "Bearer "+jwt.Access_token)
101 res.WriteHeader(http.StatusOK)
102 res.Write([]byte("Successfully retrieved JWT access token"))
105 func getJwtToken(keycloakUrl, clientId string) (*http.Response, error) {
106 var resp = &http.Response{}
108 client_assertion := getClientAssertion()
110 if jwt.Refresh_token != "" {
111 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
112 "client_assertion": {client_assertion}, "grant_type": {"refresh_token"},
113 "refresh_token": {jwt.Refresh_token}, "client_id": {clientId}, "scope": {scope}})
115 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
116 "client_assertion": {client_assertion}, "grant_type": {"client_credentials"},
117 "client_id": {clientId}, "scope": {scope}})
123 func getClientAssertion() string {
124 //aud := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName
125 //aud := "http://keycloak/auth/realms/" + realmName
126 aud := "https://keycloak:8443/realms/" + realmName
127 clientAssertion := generatejwt.CreateJWT("/certs/client.key", "", clientId, aud)
128 return clientAssertion
131 func getx509Token(keycloakUrl, clientId string) (*http.Response, error) {
132 var resp = &http.Response{}
135 client := getClient()
136 resp, err = client.PostForm(keycloakUrl, url.Values{"username": {""}, "password": {""}, "grant_type": {"password"}, "client_id": {clientId}, "scope": {scope}})
141 func getClient() *http.Client {
142 caCert, _ := ioutil.ReadFile("/certs/rootCA.crt")
143 caCertPool := x509.NewCertPool()
144 caCertPool.AppendCertsFromPEM(caCert)
146 cert, _ := tls.LoadX509KeyPair("/certs/client.crt", "/certs/client.key")
148 dialer := &net.Dialer{
149 Timeout: 30 * time.Second,
150 KeepAlive: 30 * time.Second,
154 client := &http.Client{
155 Transport: &http.Transport{
156 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
157 fmt.Println("address original =", addr)
158 if addr == keycloakAlias+":"+keycloakPort {
159 addr = keycloakHost + ":" + keycloakPort
160 fmt.Println("address modified =", addr)
162 return dialer.DialContext(ctx, network, addr)
164 TLSClientConfig: &tls.Config{
166 Certificates: []tls.Certificate{cert},
173 func getSecretToken(keycloakUrl, clientId string) (*http.Response, error) {
174 var resp = &http.Response{}
177 secretName := clientId + "-secret"
178 clientSecret := getSecret(secretName)
179 resp, err = http.PostForm(keycloakUrl,
180 url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
185 func getSecret(secretName string) string {
186 clientset := connectToK8s()
187 res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
189 fmt.Println(err.Error())
191 return string(res.Data["client_secret"])
194 func connectToK8s() *kubernetes.Clientset {
195 config, err := rest.InClusterConfig()
197 fmt.Println("failed to create K8s config")
200 clientset, err := kubernetes.NewForConfig(config)
202 fmt.Println("Failed to create K8s clientset")
208 func health(res http.ResponseWriter, req *http.Request) {
210 res.WriteHeader(http.StatusOK)
211 res.Write([]byte("healthy"))
213 res.WriteHeader(http.StatusInternalServerError)
214 res.Write([]byte("unhealthy"))
219 flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
220 flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
221 flag.StringVar(&keycloakAlias, "keycloakAlias", "keycloak.est.tech", "Keycloak URL Alias")
224 healthHandler := http.HandlerFunc(health)
225 http.Handle("/health", healthHandler)
226 tokenHandler := http.HandlerFunc(getToken)
227 http.Handle("/token", tokenHandler)
228 http.ListenAndServe(":8888", nil)
230 ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)