2 // ========================LICENSE_START=================================
5 // Copyright (C) 2022: 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 + "/auth/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" {
81 resp, err = getx509Token(keycloakUrl, clientId)
83 resp, err = getSecretToken(keycloakUrl, clientId)
88 res.WriteHeader(http.StatusInternalServerError)
89 res.Write([]byte(err.Error()))
90 panic("Something wrong with the credentials or url ")
93 defer resp.Body.Close()
94 body, err := ioutil.ReadAll(resp.Body)
95 json.Unmarshal([]byte(body), &jwt)
96 fmt.Printf("Token: %s\n", jwt.Access_token)
98 res.Header().Set("Authorization", "Bearer "+jwt.Access_token)
99 res.WriteHeader(http.StatusOK)
100 res.Write([]byte("Successfully retrieved JWT access token"))
103 func getJwtToken(keycloakUrl, clientId string) (*http.Response, error) {
104 var resp = &http.Response{}
106 client_assertion := getClientAssertion()
108 if jwt.Refresh_token != "" {
109 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
110 "client_assertion": {client_assertion}, "grant_type": {"refresh_token"},
111 "refresh_token": {jwt.Refresh_token}, "client_id": {clientId}, "scope": {scope}})
113 resp, err = http.PostForm(keycloakUrl, url.Values{"client_assertion_type": {client_assertion_type},
114 "client_assertion": {client_assertion}, "grant_type": {"client_credentials"},
115 "client_id": {clientId}, "scope": {scope}})
121 func getClientAssertion() string {
122 realm := "http://" + keycloakHost + ":" + keycloakPort + "/auth/realms/" + realmName
123 clientAssertion := generatejwt.CreateJWT("/certs/client.key", "", clientId, realm)
124 return clientAssertion
127 func getx509Token(keycloakUrl, clientId string) (*http.Response, error) {
128 var resp = &http.Response{}
131 client := getClient()
132 resp, err = client.PostForm(keycloakUrl, url.Values{"username": {""}, "password": {""}, "grant_type": {"password"}, "client_id": {clientId}, "scope": {scope}})
137 func getClient() *http.Client {
138 caCert, _ := ioutil.ReadFile("/certs/rootCA.crt")
139 caCertPool := x509.NewCertPool()
140 caCertPool.AppendCertsFromPEM(caCert)
142 cert, _ := tls.LoadX509KeyPair("/certs/client.crt", "/certs/client.key")
144 dialer := &net.Dialer{
145 Timeout: 30 * time.Second,
146 KeepAlive: 30 * time.Second,
150 client := &http.Client{
151 Transport: &http.Transport{
152 DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
153 fmt.Println("address original =", addr)
154 if addr == keycloakAlias+":"+keycloakPort {
155 addr = keycloakHost + ":" + keycloakPort
156 fmt.Println("address modified =", addr)
158 return dialer.DialContext(ctx, network, addr)
160 TLSClientConfig: &tls.Config{
162 Certificates: []tls.Certificate{cert},
169 func getSecretToken(keycloakUrl, clientId string) (*http.Response, error) {
170 var resp = &http.Response{}
173 secretName := clientId + "-secret"
174 clientSecret := getSecret(secretName)
175 resp, err = http.PostForm(keycloakUrl,
176 url.Values{"client_secret": {clientSecret}, "grant_type": {"client_credentials"}, "client_id": {clientId}})
181 func getSecret(secretName string) string {
182 clientset := connectToK8s()
183 res, err := clientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{})
185 fmt.Println(err.Error())
187 return string(res.Data["client_secret"])
190 func connectToK8s() *kubernetes.Clientset {
191 config, err := rest.InClusterConfig()
193 fmt.Println("failed to create K8s config")
196 clientset, err := kubernetes.NewForConfig(config)
198 fmt.Println("Failed to create K8s clientset")
204 func health(res http.ResponseWriter, req *http.Request) {
206 res.WriteHeader(http.StatusOK)
207 res.Write([]byte("healthy"))
209 res.WriteHeader(http.StatusInternalServerError)
210 res.Write([]byte("unhealthy"))
215 flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
216 flag.StringVar(&keycloakPort, "keycloakPort", "80", "Keycloak Port")
217 flag.StringVar(&keycloakAlias, "keycloakAlias", "keycloak.oran.org", "Keycloak URL Alias")
220 healthHandler := http.HandlerFunc(health)
221 http.Handle("/health", healthHandler)
222 tokenHandler := http.HandlerFunc(getToken)
223 http.Handle("/token", tokenHandler)
224 http.ListenAndServe(":8888", nil)
226 ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)