blob: 1cad3ed19d62130c32ce8c7ebbf663726fee2b9a [file] [log] [blame]
// -
// ========================LICENSE_START=================================
// O-RAN-SC
// %%
// Copyright (C) 2022: Nordix Foundation
// %%
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================LICENSE_END===================================
//
package main
import (
"bytes"
"context"
"crypto/tls"
"crypto/x509"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/url"
"strings"
"time"
)
type Jwttoken struct {
Access_token string
Expires_in int
Refresh_expires_in int
Refresh_token string
Token_type string
Not_before_policy int
Session_state string
Scope string
}
var gatewayHost string
var gatewayPort string
var keycloakHost string
var keycloakPort string
var keycloakAlias string
var securityEnabled string
var useGateway string
var role string
var rapp string
var methods string
var realmName string
var clientId string
var healthy bool = true
var ttime time.Time
var jwt Jwttoken
const (
namespace = "istio-nonrtric"
scope = "openid profile"
)
func getToken() string {
if ttime.Before(time.Now()) {
client := getClient()
keycloakUrl := "https://" + keycloakAlias + ":" + keycloakPort + "/auth/realms/" + realmName + "/protocol/openid-connect/token"
resp, err := client.PostForm(keycloakUrl, url.Values{"username": {""}, "password": {""}, "grant_type": {"password"}, "client_id": {clientId}, "scope": {scope}})
if err != nil {
fmt.Println(err)
panic("Something wrong with the credentials or url ")
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
json.Unmarshal([]byte(body), &jwt)
ttime = time.Now()
ttime = ttime.Add(time.Second * time.Duration(jwt.Expires_in))
}
return jwt.Access_token
}
func getClient() *http.Client {
caCert, _ := ioutil.ReadFile("/certs/rootCA.crt")
caCertPool := x509.NewCertPool()
caCertPool.AppendCertsFromPEM(caCert)
cert, _ := tls.LoadX509KeyPair("/certs/client.crt", "/certs/client.key")
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}
client := &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
fmt.Println("address original =", addr)
if addr == keycloakAlias+":"+keycloakPort {
addr = keycloakHost + ":" + keycloakPort
fmt.Println("address modified =", addr)
}
return dialer.DialContext(ctx, network, addr)
},
TLSClientConfig: &tls.Config{
RootCAs: caCertPool,
Certificates: []tls.Certificate{cert},
},
},
}
return client
}
func MakeRequest(client *http.Client, prefix string, method string, ch chan string) {
var service = strings.Split(prefix, "/")[1]
var gatewayUrl = "http://" + gatewayHost + ":" + gatewayPort
var token = ""
var jsonValue []byte = []byte{}
var restUrl string = ""
if securityEnabled == "true" {
token = getToken()
} else {
useGateway = "N"
}
if strings.ToUpper(useGateway) != "Y" {
gatewayUrl = "http://" + service + "." + namespace + ":80"
prefix = ""
}
restUrl = gatewayUrl + prefix
req, err := http.NewRequest(method, restUrl, bytes.NewBuffer(jsonValue))
if err != nil {
fmt.Printf("Got error %s", err.Error())
}
req.Header.Set("Content-type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Got error %s", err.Error())
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
respString := string(body[:])
if respString == "RBAC: access denied" {
respString += " for " + service + " " + strings.ToLower(method) + " request"
}
fmt.Printf("Received response for %s %s request - %s\n", service, strings.ToLower(method), respString)
ch <- prefix + "," + method
}
func health(res http.ResponseWriter, req *http.Request) {
if healthy {
res.WriteHeader(http.StatusOK)
res.Write([]byte("healthy"))
} else {
res.WriteHeader(http.StatusInternalServerError)
res.Write([]byte("unhealthy"))
}
}
func main() {
ttime = time.Now()
time.Sleep(1 * time.Second)
flag.StringVar(&gatewayHost, "gatewayHost", "istio-ingressgateway.istio-system", "Gateway Host")
flag.StringVar(&gatewayPort, "gatewayPort", "80", "Gateway Port")
flag.StringVar(&keycloakHost, "keycloakHost", "istio-ingressgateway.istio-system", "Keycloak Host")
flag.StringVar(&keycloakPort, "keycloakPort", "443", "Keycloak Port")
flag.StringVar(&keycloakAlias, "keycloakAlias", "keycloak.est.tech", "Keycloak URL Alias")
flag.StringVar(&useGateway, "useGateway", "Y", "Connect to services through API gateway")
flag.StringVar(&securityEnabled, "securityEnabled", "true", "Security is required to use this application")
flag.StringVar(&realmName, "realm", "x509", "Keycloak realm")
flag.StringVar(&clientId, "client", "x509provider-cli", "Keycloak client")
flag.StringVar(&role, "role", "provider-viewer", "Role granted to application")
flag.StringVar(&rapp, "rapp", "rapp-x509-provider", "Name of rapp to invoke")
flag.StringVar(&methods, "methods", "GET", "Methods to access application")
flag.Parse()
healthHandler := http.HandlerFunc(health)
http.Handle("/health", healthHandler)
go func() {
http.ListenAndServe(":9000", nil)
}()
client := &http.Client{
Timeout: time.Second * 10,
}
ch := make(chan string)
var prefixArray []string = []string{"/" + rapp}
var methodArray []string = []string{methods}
for _, prefix := range prefixArray {
for _, method := range methodArray {
go MakeRequest(client, prefix, method, ch)
}
}
ioutil.WriteFile("init.txt", []byte("Initialization done."), 0644)
for r := range ch {
go func(resp string) {
time.Sleep(10 * time.Second)
elements := strings.Split(resp, ",")
prefix := elements[0]
method := elements[1]
MakeRequest(client, prefix, method, ch)
}(r)
}
}