Update keycloak version
[nonrtric.git] / service-exposure / rapps-keycloak-mgr.go
index 35e503d..6c72d87 100644 (file)
@@ -1,33 +1,36 @@
 // -
-//   ========================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
+//     ========================LICENSE_START=================================
+//     O-RAN-SC
+//     %%
+//     Copyright (C) 2022-2023: 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
 //
-//   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===================================
+//          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"
+       "encoding/json"
        "fmt"
-       "github.com/Nerzal/gocloak/v10"
+       "io/ioutil"
        corev1 "k8s.io/api/core/v1"
        metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
        kubernetes "k8s.io/client-go/kubernetes"
        "k8s.io/client-go/rest"
        "net/http"
+       "net/url"
        "rapps/utils/pemtojwks"
 )
 
@@ -35,6 +38,84 @@ const (
        namespace = "istio-nonrtric"
 )
 
+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
+}
+
+type RealmRepresentation struct {
+       Id          string `json:"id,omitempty"`
+       Realm       string `json:"realm,omitempty"`
+       DisplayName string `json:"displayName,omitempty"`
+       Enabled     bool   `json:"enabled"`
+}
+
+type Client struct {
+       ClientID                           string            `json:"clientId,omitempty"`
+       Enabled                            bool              `json:"enabled,omitempty"`
+       DirectAccessGrantsEnabled          bool              `json:"directAccessGrantsEnabled,omitempty"`
+       BearerOnly                         bool              `json:"bearerOnly,omitempty"`
+       PublicClient                       bool              `json:"publicClient,omitempty"`
+       ServiceAccountsEnabled             bool              `json:"serviceAccountsEnabled,omitempty"`
+       ClientAuthenticatorType            string            `json:"clientAuthenticatorType,omitempty"`
+       DefaultClientScopes                []string          `json:"defaultClientScopes,omitempty"`
+       Attributes                         map[string]string `json:"attributes,omitempty"`
+       AuthenticationFlowBindingOverrides map[string]string `json:"authenticationFlowBindingOverrides,omitempty"`
+}
+
+type Role struct {
+       Name string `json:"name,omitempty"`
+}
+
+type User struct {
+       ID       string `json:"id,omitempty"`
+       Username string `json:"username,omitempty"`
+       Email    string `json:"email,omitempty"`
+       Enabled  bool   `json:"enabled"`
+}
+
+type ProtocolMapperRepresentation struct {
+       Name           string            `json:"name,omitempty"`
+       Protocol       string            `json:"protocol,omitempty"`
+       ProtocolMapper string            `json:"protocolMapper,omitempty"`
+       Config         map[string]string `json:"config,omitempty"`
+}
+
+type RoleRepresentation struct {
+       ID         string `json:"id,omitempty"`
+       Name       string `json:"name,omitempty"`
+       Composite  bool   `json:"composite"`
+       ClientRole bool   `json:"clientRole"`
+}
+
+type AuthenticationFlowRepresentation struct {
+       Alias                   string   `json:"alias,omitempty"`
+       Description             string   `json:"description,omitempty"`
+       ProviderId              string   `json:"providerId,omitempty"`
+       TopLevel                bool     `json:"topLevel"`
+       BuiltIn                 bool     `json:"builtIn"`
+       AthenticationExecutions []string `json:"authenticationExecutions,omitempty"`
+}
+
+type Execution struct {
+       Provider string `json:"provider,omitempty"`
+}
+
+type AuthenticatorConfigRepresentation struct {
+       Alias  string            `json:"alias,omitempty"`
+       Config map[string]string `json:"config,omitempty"`
+}
+
+var keycloakUrl string = "http://keycloak:8080"
+var token Jwttoken
+var flowAlias string = "x509 direct grant"
+
 func createClient(res http.ResponseWriter, req *http.Request) {
        query := req.URL.Query()
        realmName := query.Get("realm")
@@ -47,7 +128,7 @@ func createClient(res http.ResponseWriter, req *http.Request) {
                msg = err.Error()
        }
        if authType == "client-secret" {
-               createSecret(msg, clientName, realmName, role, namespace)
+               createSecret(msg, clientName, realmName, namespace)
        }
        // create response binary data
        data := []byte(msg) // slice of bytes
@@ -59,13 +140,12 @@ func removeClient(res http.ResponseWriter, req *http.Request) {
        query := req.URL.Query()
        realmName := query.Get("realm")
        clientName := query.Get("name")
-       role := query.Get("role")
        authType := query.Get("authType")
 
        var msg string = "Removed keycloak " + clientName + " from " + realmName + " realm"
        remove(realmName, clientName)
        if authType == "client-secret" {
-               removeSecret(namespace, role)
+               removeSecret(namespace, clientName)
        }
        // create response binary data
        data := []byte(msg) // slice of bytes
@@ -81,220 +161,269 @@ func main() {
        http.ListenAndServe(":9000", nil)
 }
 
-func create(realmName, clientName, clientRoleName, authType string) (string, error) {
-       client := gocloak.NewClient("http://keycloak.default:8080")
-       ctx := context.Background()
-       token, err := client.LoginAdmin(ctx, "admin", "admin", "master")
+func getAdminToken() {
+       var resp = &http.Response{}
+       var err error
+       username := "admin"
+       password := "admin"
+       clientId := "admin-cli"
+       restUrl := keycloakUrl + "/realms/master/protocol/openid-connect/token"
+       resp, err = http.PostForm(restUrl,
+               url.Values{"username": {username}, "password": {password}, "grant_type": {"password"}, "client_id": {clientId}})
        if err != nil {
-               return "", err
+               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), &token)
+}
 
-       _, err = client.GetRealm(ctx, token.AccessToken, realmName)
-       if err != nil {
-               realmRepresentation := gocloak.RealmRepresentation{
-                       ID:          gocloak.StringP(realmName),
-                       Realm:       gocloak.StringP(realmName),
-                       DisplayName: gocloak.StringP(realmName),
-                       Enabled:     gocloak.BoolP(true),
-               }
-
-               realm, err := client.CreateRealm(ctx, token.AccessToken, realmRepresentation)
-               if err != nil {
-                       return "", err
-               } else {
-                       fmt.Println("Created realm", realm)
-               }
-       } else {
-               fmt.Println("Realm already exists", realmName)
-       }
+func sendRequest(method, url string, data []byte) (int, string) {
+       fmt.Printf("Sending %s request to %s\n", method, url)
+       req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
+       req.Header.Set("Content-Type", "application/json")
+       req.Header.Set("Authorization", "Bearer "+token.Access_token)
 
-       flowAlias := "x509 direct grant"
-       flowId := ""
-       flows, err := client.GetAuthenticationFlows(ctx, token.AccessToken, realmName)
+       client := &http.Client{}
+       resp, err := client.Do(req)
        if err != nil {
-               fmt.Println("Oh no!, failed to get flows :(")
-       } else {
-               for _, flow := range flows {
-                       if flow.Alias != nil && *flow.Alias == flowAlias {
-                               flowId = *flow.ID
-                       }
-               }
-               fmt.Println("Retrieved AuthenticationFlow id", flowId)
-       }
-
-       secretClient := gocloak.Client{
-               ClientID:                  gocloak.StringP(clientName),
-               Enabled:                   gocloak.BoolP(true),
-               DirectAccessGrantsEnabled: gocloak.BoolP(true),
-               BearerOnly:                gocloak.BoolP(false),
-               PublicClient:              gocloak.BoolP(false),
-               ServiceAccountsEnabled:    gocloak.BoolP(true),
-               ClientAuthenticatorType:   gocloak.StringP("client-secret"),
-               DefaultClientScopes:       &[]string{"email"},
-               Attributes: &map[string]string{"use.refresh.tokens": "true",
-                       "client_credentials.use_refresh_token": "true"},
-       }
-
-       x509Client := gocloak.Client{
-               ClientID:                  gocloak.StringP(clientName),
-               Enabled:                   gocloak.BoolP(true),
-               DirectAccessGrantsEnabled: gocloak.BoolP(true),
-               BearerOnly:                gocloak.BoolP(false),
-               PublicClient:              gocloak.BoolP(false),
-               ServiceAccountsEnabled:    gocloak.BoolP(true),
-               ClientAuthenticatorType:   gocloak.StringP("client-x509"),
-               DefaultClientScopes:       &[]string{"openid", "profile", "email"},
-               Attributes: &map[string]string{"use.refresh.tokens": "true",
-                       "client_credentials.use_refresh_token": "true",
-                       "x509.subjectdn":                       ".*client@mail.com.*",
-                       "x509.allow.regex.pattern.comparison":  "true"},
-               AuthenticationFlowBindingOverrides: &map[string]string{"direct_grant": flowId},
+               panic(err)
        }
+       defer resp.Body.Close()
+       body, _ := ioutil.ReadAll(resp.Body)
+       respString := string(body)
+       fmt.Println("response Status:", resp.Status)
+       return resp.StatusCode, respString
+}
 
-       jwksString := pemtojwks.CreateJWKS("/certs/client.crt")
-       jwtClient := gocloak.Client{
-               ClientID:                  gocloak.StringP(clientName),
-               Enabled:                   gocloak.BoolP(true),
-               DirectAccessGrantsEnabled: gocloak.BoolP(true),
-               BearerOnly:                gocloak.BoolP(false),
-               PublicClient:              gocloak.BoolP(false),
-               ServiceAccountsEnabled:    gocloak.BoolP(true),
-               ClientAuthenticatorType:   gocloak.StringP("client-jwt"),
-               DefaultClientScopes:       &[]string{"email"},
-               Attributes: &map[string]string{"token.endpoint.auth.signing.alg": "RS256",
-                       "use.jwks.string":                      "true",
-                       "jwks.string":                          jwksString,
-                       "use.refresh.tokens":                   "true",
-                       "client_credentials.use_refresh_token": "true",
-               },
+func create(realmName, clientName, clientRoleName, authType string) (string, error) {
+       getAdminToken()
+       var userId string = ""
+       var jsonValue []byte = []byte{}
+       restUrl := keycloakUrl + "/realms/" + realmName
+       statusCode, _ := sendRequest("GET", restUrl, nil)
+
+       if statusCode != 200 {
+               realmRepresentation := RealmRepresentation{
+                       Id:          realmName,
+                       Realm:       realmName,
+                       DisplayName: realmName,
+                       Enabled:     true,
+               }
+               restUrl := keycloakUrl + "/admin/realms"
+               jsonValue, _ := json.Marshal(realmRepresentation)
+               statusCode, _ = sendRequest("POST", restUrl, jsonValue)
        }
 
-       var newClient gocloak.Client
+       var flowId string = ""
        if authType == "client-x509" {
-               newClient = x509Client
-       } else if authType == "client-jwt" {
-               newClient = jwtClient
-       } else {
-               newClient = secretClient
+               flowId = getFlowId(realmName)
+               if flowId == "" {
+                       createx509Flow(realmName)
+                       flowId = getFlowId(realmName)
+               }
+               newUser := User{
+                       ID:       realmName + "user",
+                       Username: realmName + "user",
+                       Email:    "client@mail.com",
+                       Enabled:  true,
+               }
+               restUrl = keycloakUrl + "/admin/realms/" + realmName + "/users"
+               jsonValue, _ = json.Marshal(newUser)
+               statusCode, _ = sendRequest("POST", restUrl, jsonValue)
+               userId = getUserId(realmName, realmName+"user")
        }
 
-       clientId, err := client.CreateClient(ctx, token.AccessToken, realmName, newClient)
-       if err != nil {
-               fmt.Println("Failed to create client", err)
-               return "", err
-       } else {
-               fmt.Println("Created realm client", clientId)
-       }
+       newClient := getClient(authType, clientName, flowId)
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/clients"
+       jsonValue, _ = json.Marshal(newClient)
+       statusCode, _ = sendRequest("POST", restUrl, jsonValue)
 
-       newClientRole := gocloak.Role{
-               Name: gocloak.StringP(clientRoleName),
-       }
-       clientRoleName, err = client.CreateClientRole(ctx, token.AccessToken, realmName, clientId, newClientRole)
-       if err != nil {
-               return "", err
-       } else {
-               fmt.Println("Created client role", clientRoleName)
+       clientId, clientSecret := getClientInfo(realmName, clientName)
+
+       newClientRole := Role{
+               Name: clientRoleName,
        }
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/clients/" + clientId + "/roles"
+       jsonValue, _ = json.Marshal(newClientRole)
+       statusCode, _ = sendRequest("POST", restUrl, jsonValue)
 
-       user, err := client.GetClientServiceAccount(ctx, token.AccessToken, realmName, clientId)
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/clients/" + clientId + "/roles/" + clientRoleName
+       statusCode, data := sendRequest("GET", restUrl, nil)
+       roles := make(map[string]interface{})
+       err := json.Unmarshal([]byte(data), &roles)
        if err != nil {
                fmt.Println(err)
-               panic("Oh no!, failed to get client user :(")
-       } else {
-               fmt.Println("Service Account user", *user.Username)
        }
+       roleId := fmt.Sprintf("%v", roles["id"])
 
-       if authType == "client-x509" {
-               newUser := gocloak.User{
-                       ID:       gocloak.StringP(realmName + "user"),
-                       Username: gocloak.StringP(realmName + "user"),
-                       Email:    gocloak.StringP("client@mail.com"),
-                       Enabled:  gocloak.BoolP(true),
-               }
-
-               realmUser, err := client.CreateUser(ctx, token.AccessToken, realmName, newUser)
+       if authType != "client-x509" {
+               restUrl = keycloakUrl + "/admin/realms/" + realmName + "/clients/" + clientId + "/service-account-user"
+               statusCode, data = sendRequest("GET", restUrl, nil)
+               serviceAccount := make(map[string]interface{})
+               err = json.Unmarshal([]byte(data), &serviceAccount)
                if err != nil {
                        fmt.Println(err)
-                       panic("Oh no!, failed to create user :(")
-               } else {
-                       fmt.Println("Created new user", realmUser)
                }
+               userId = fmt.Sprintf("%v", serviceAccount["id"])
        }
 
-       clientRole, err := client.GetClientRole(ctx, token.AccessToken, realmName, clientId, clientRoleName)
-       if err != nil {
-               fmt.Println(err)
-               panic("Oh no!, failed to get client role :(")
-       } else {
-               fmt.Println("Retrieved client role", clientRoleName)
+       roleRepresentation := RoleRepresentation{
+               ID:         roleId,
+               Name:       clientRoleName,
+               Composite:  false,
+               ClientRole: true,
        }
 
-       clientRoles := []gocloak.Role{*clientRole}
-       err = client.AddClientRoleToUser(ctx, token.AccessToken, realmName, clientId, *user.ID, clientRoles)
-       if err != nil {
-               fmt.Println(err)
-               panic("Oh no!, failed to add client role to user :(")
-       } else {
-               fmt.Printf("Added %s to %s\n", *clientRole.Name, *user.Username)
-       }
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/users/" + userId + "/role-mappings/clients/" + clientId
+       jsonValue, _ = json.Marshal([]RoleRepresentation{roleRepresentation})
+       statusCode, data = sendRequest("POST", restUrl, jsonValue)
 
-       clientroleMapper := gocloak.ProtocolMapperRepresentation{
-               ID:             gocloak.StringP("Client Role " + clientName + " Mapper"),
-               Name:           gocloak.StringP("Client Role " + clientName + " Mapper"),
-               Protocol:       gocloak.StringP("openid-connect"),
-               ProtocolMapper: gocloak.StringP("oidc-usermodel-client-role-mapper"),
-               Config: &map[string]string{
+       clientroleMapper := ProtocolMapperRepresentation{
+               Name:           "Client Role " + clientName + " Mapper",
+               Protocol:       "openid-connect",
+               ProtocolMapper: "oidc-usermodel-client-role-mapper",
+               Config: map[string]string{
                        "access.token.claim":                   "true",
                        "aggregate.attrs":                      "",
                        "claim.name":                           "clientRole",
                        "id.token.claim":                       "true",
                        "jsonType.label":                       "String",
                        "multivalued":                          "true",
-                       "userinfo.token.claim":                 "true",
                        "usermodel.clientRoleMapping.clientId": clientName,
+                       "userinfo.token.claim":                 "false",
                },
        }
-       _, err = client.CreateClientProtocolMapper(ctx, token.AccessToken, realmName, clientId, clientroleMapper)
-       if err != nil {
-               fmt.Println(err)
-               panic("Oh no!, failed to add client roleampper to client :(")
+
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/clients/" + clientId + "/protocol-mappers/models"
+       jsonValue, _ = json.Marshal(clientroleMapper)
+       statusCode, _ = sendRequest("POST", restUrl, jsonValue)
+       return clientSecret, nil
+}
+
+func getClient(authType, clientName, flowId string) Client {
+       var newClient Client
+       newClient.ClientID = clientName
+       newClient.Enabled = true
+       newClient.DirectAccessGrantsEnabled = true
+       newClient.BearerOnly = false
+       newClient.PublicClient = false
+       newClient.ServiceAccountsEnabled = true
+       newClient.ClientAuthenticatorType = authType
+       newClient.DefaultClientScopes = []string{"email"}
+       if authType == "client-secret" {
+               newClient.Attributes = map[string]string{
+                       "use.refresh.tokens":                   "true",
+                       "client_credentials.use_refresh_token": "true"}
+       } else if authType == "client-x509" {
+               newClient.Attributes = map[string]string{
+                       "use.refresh.tokens":                   "true",
+                       "client_credentials.use_refresh_token": "true",
+                       "x509.subjectdn":                       ".*client@mail.com.*",
+                       "x509.allow.regex.pattern.comparison":  "true"}
+               newClient.AuthenticationFlowBindingOverrides = map[string]string{
+                       "direct_grant": flowId}
        } else {
-               fmt.Println("Client rolemapper added to client")
+               jwksString, publicKey, kid := pemtojwks.CreateJWKS("/certs/client.crt")
+               newClient.Attributes = map[string]string{
+                       "token.endpoint.auth.signing.alg":      "RS256",
+                       "jwt.credential.public.key":            publicKey,
+                       "jwt.credential.kid":                   kid,
+                       "use.jwks.url":                         "false",
+                       "jwks.url":                             jwksString,
+                       "use.refresh.tokens":                   "true",
+                       "client_credentials.use_refresh_token": "true",
+               }
        }
+       return newClient
+}
 
-       if authType == "client-x509" {
-               clientRole := *newClient.ClientID + "." + clientRoleName
-
-               clientroleMapper := gocloak.ProtocolMapperRepresentation{
-                       ID:             gocloak.StringP("Hardcoded " + clientName + " Mapper"),
-                       Name:           gocloak.StringP("Hardcoded " + clientName + " Mapper"),
-                       Protocol:       gocloak.StringP("openid-connect"),
-                       ProtocolMapper: gocloak.StringP("oidc-hardcoded-role-mapper"),
-                       Config: &map[string]string{
-                               "role": clientRole,
-                       },
-               }
-               _, err = client.CreateClientProtocolMapper(ctx, token.AccessToken, realmName, clientId, clientroleMapper)
-               if err != nil {
-                       return "", err
-               } else {
-                       fmt.Println("Created hardcoded-role-mapper for ", clientRole)
-               }
+func getClientInfo(realmName, clientName string) (string, string) {
+       restUrl := keycloakUrl + "/admin/realms/" + realmName + "/clients?clientId=" + clientName
+       _, data := sendRequest("GET", restUrl, nil)
+
+       clients := make([]map[string]interface{}, 0)
+       err := json.Unmarshal([]byte(data), &clients)
+       if err != nil {
+               fmt.Println(err)
        }
+       clientId := fmt.Sprintf("%v", clients[0]["id"])
+       clientSecret := fmt.Sprintf("%v", clients[0]["secret"])
+       return clientId, clientSecret
+}
 
-       _, err = client.RegenerateClientSecret(ctx, token.AccessToken, realmName, clientId)
+func createx509Flow(realmName string) {
+       var jsonValue []byte = []byte{}
+       authenticationFlowRepresentation := AuthenticationFlowRepresentation{
+               Alias:                   flowAlias,
+               Description:             "OpenID Connect Resource Owner Grant",
+               ProviderId:              "basic-flow",
+               TopLevel:                true,
+               BuiltIn:                 false,
+               AthenticationExecutions: []string{},
+       }
+       restUrl := keycloakUrl + "/admin/realms/" + realmName + "/authentication/flows"
+       jsonValue, _ = json.Marshal(authenticationFlowRepresentation)
+       sendRequest("POST", restUrl, jsonValue)
+
+       execution := Execution{
+               Provider: "direct-grant-auth-x509-username",
+       }
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/authentication/flows/" + flowAlias + "/executions/execution"
+       jsonValue, _ = json.Marshal(execution)
+       sendRequest("POST", restUrl, jsonValue)
+
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/authentication/flows/" + flowAlias + "/executions"
+       _, data := sendRequest("GET", restUrl, nil)
+       executionInfo := make([]map[string]interface{}, 0)
+       err := json.Unmarshal([]byte(data), &executionInfo)
        if err != nil {
-               return "", err
+               fmt.Println(err)
        }
+       executionId := fmt.Sprintf("%v", executionInfo[0]["id"])
+
+       authenticatorConfigRepresentation := AuthenticatorConfigRepresentation{
+               Alias: flowAlias + " config",
+               Config: map[string]string{
+                       "x509-cert-auth.canonical-dn-enabled":           "false",
+                       "x509-cert-auth.serialnumber-hex-enabled":       "false",
+                       "x509-cert-auth.ocsp-fail-open":                 "false",
+                       "x509-cert-auth.regular-expression":             "(.*?)(?:$)",
+                       "x509-cert-auth.crl-checking-enabled":           "false",
+                       "x509-cert-auth.certificate-policy-mode":        "All",
+                       "x509-cert-auth.timestamp-validation-enabled":   "false",
+                       "x509-cert-auth.confirmation-page-disallowed":   "false",
+                       "x509-cert-auth.mapper-selection":               "Username or Email",
+                       "x509-cert-auth.revalidate-certificate-enabled": "false",
+                       "x509-cert-auth.crldp-checking-enabled":         "false",
+                       "x509-cert-auth.mapping-source-selection":       "Subject's e-mail",
+                       "x509-cert-auth.ocsp-checking-enabled":          "false",
+               },
+       }
+       restUrl = keycloakUrl + "/admin/realms/" + realmName + "/authentication/executions/" + executionId + "/config"
+       jsonValue, _ = json.Marshal(authenticatorConfigRepresentation)
+       sendRequest("POST", restUrl, jsonValue)
+}
 
-       cred, err := client.GetClientSecret(ctx, token.AccessToken, realmName, clientId)
+func getFlowId(realmName string) string {
+       var flowId string = ""
+       restUrl := keycloakUrl + "/admin/realms/" + realmName + "/authentication/flows"
+       _, data := sendRequest("GET", restUrl, nil)
+       flows := make([]map[string]interface{}, 0)
+       err := json.Unmarshal([]byte(data), &flows)
        if err != nil {
-               return "", err
-       } else {
-               fmt.Println("Generated client secret", *cred.Value)
+               fmt.Println(err)
        }
 
-       return *cred.Value, nil
+       for i, _ := range flows {
+               id := fmt.Sprintf("%v", flows[i]["id"])
+               alias := fmt.Sprintf("%v", flows[i]["alias"])
+               if alias == flowAlias {
+                       flowId = id
+               }
+       }
+       return flowId
 }
 
 func connectToK8s() *kubernetes.Clientset {
@@ -311,8 +440,8 @@ func connectToK8s() *kubernetes.Clientset {
        return clientset
 }
 
-func createSecret(clientSecret, clientName, realmName, role, namespace string) {
-       secretName := role + "-secret"
+func createSecret(clientSecret, clientName, realmName, namespace string) {
+       secretName := clientName + "-secret"
        clientset := connectToK8s()
        secrets := clientset.CoreV1().Secrets(namespace)
        secret := &corev1.Secret{
@@ -336,52 +465,45 @@ func createSecret(clientSecret, clientName, realmName, role, namespace string) {
 }
 
 func remove(realmName, clientName string) {
-       adminClient := gocloak.NewClient("http://keycloak.default:8080")
-       ctx := context.Background()
-       token, err := adminClient.LoginAdmin(ctx, "admin", "admin", "master")
-       if err != nil {
-               fmt.Println(err)
-       }
+       getAdminToken()
+       clientId, _ := getClientInfo(realmName, clientName)
 
-       clients, err := adminClient.GetClients(ctx, token.AccessToken, realmName,
-               gocloak.GetClientsParams{
-                       ClientID: gocloak.StringP(clientName),
-               },
-       )
-       if err != nil {
-               panic("List clients failed:" + err.Error())
+       restUrl := keycloakUrl + "/admin/realms/" + realmName + "/clients/" + clientId
+       sendRequest("DELETE", restUrl, nil)
+
+       var userId string = ""
+       userName := realmName + "user"
+       userId = getUserId(realmName, userName)
+       if userId != "" {
+               restUrl = keycloakUrl + "/admin/realms/" + realmName + "/users/" + userId
+               sendRequest("DELETE", restUrl, nil)
        }
-       for _, client := range clients {
-               err = adminClient.DeleteClient(ctx, token.AccessToken, realmName, *client.ID)
-               if err != nil {
-                       fmt.Println(err)
-               } else {
-                       fmt.Println("Deleted client ", clientName)
-               }
+
+       flowId := getFlowId(realmName)
+       if flowId != "" {
+               restUrl = keycloakUrl + "/admin/realms/" + realmName + "/authentication/flows/" + flowId
+               sendRequest("DELETE", restUrl, nil)
        }
+}
 
-       userName := realmName + "user"
-       users, err := adminClient.GetUsers(ctx, token.AccessToken, realmName,
-               gocloak.GetUsersParams{
-                       Username: gocloak.StringP(userName),
-               })
+func getUserId(realmName, userName string) string {
+       var userId string = ""
+       restUrl := keycloakUrl + "/admin/realms/" + realmName + "/users?username=demouser"
+       _, data := sendRequest("GET", restUrl, nil)
+       user := make([]map[string]interface{}, 0)
+       err := json.Unmarshal([]byte(data), &user)
        if err != nil {
-               panic("List users failed:" + err.Error())
+               fmt.Println(err)
        }
-       for _, user := range users {
-               err = adminClient.DeleteUser(ctx, token.AccessToken, realmName, *user.ID)
-               if err != nil {
-                       fmt.Println(err)
-               } else {
-                       fmt.Println("Deleted user ", userName)
-               }
+       if len(user) > 0 {
+               userId = fmt.Sprintf("%v", user[0]["id"])
        }
-
+       return userId
 }
 
-func removeSecret(namespace, role string) {
+func removeSecret(namespace, clientName string) {
        clientset := connectToK8s()
-       secretName := role + "-secret"
+       secretName := clientName + "-secret"
        secrets := clientset.CoreV1().Secrets(namespace)
        err := secrets.Delete(context.TODO(), secretName, metav1.DeleteOptions{})
        if err != nil {