Added x509 and jwt rapps

Change-Id: Ic384fcad11dcb63fe4265d3dbcff5ea17f933cfc
diff --git a/rapps/rapps-keycloak-mgr.go b/rapps/rapps-keycloak-mgr.go
index 0d0a29c..82097ff 100644
--- a/rapps/rapps-keycloak-mgr.go
+++ b/rapps/rapps-keycloak-mgr.go
@@ -9,10 +9,12 @@
 	kubernetes "k8s.io/client-go/kubernetes"
 	"k8s.io/client-go/rest"
 	"net/http"
+	"strings"
+	"rapps/utils/pemtojwks"
 )
 
 const (
-  namespace = "istio-nonrtric"
+	namespace = "istio-nonrtric"
 )
 
 func createClient(res http.ResponseWriter, req *http.Request) {
@@ -25,7 +27,9 @@
 	if err != nil {
 		msg = err.Error()
 	}
-	createSecret(msg, clientName, realmName, role, namespace)
+	if realmName != "x509" && realmName != "jwt" {
+		createSecret(msg, clientName, realmName, role, namespace)
+	}
 	// create response binary data
 	data := []byte(msg) // slice of bytes
 	// write `data` to response
@@ -40,7 +44,9 @@
 
 	var msg string = "Removed keycloak " + clientName + " from " + realmName + " realm"
 	remove(realmName, clientName)
-	removeSecret(namespace, role)
+        if realmName != "x509" && realmName != "jwt" {
+	        removeSecret(namespace, role)
+        }
 	// create response binary data
 	data := []byte(msg) // slice of bytes
 	// write `data` to response
@@ -82,7 +88,21 @@
 		fmt.Println("Realm already exists", realmName)
 	}
 
-	newClient := gocloak.Client{
+	flowAlias := "x509 direct grant"
+	flowId := ""
+	flows, err := client.GetAuthenticationFlows(ctx, token.AccessToken, realmName)
+	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)
+	}
+
+	newClient1 := gocloak.Client{
 		ClientID:                  gocloak.StringP(clientName),
 		Enabled:                   gocloak.BoolP(true),
 		DirectAccessGrantsEnabled: gocloak.BoolP(true),
@@ -91,11 +111,54 @@
 		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"},
+		Attributes: &map[string]string{"use.refresh.tokens": "true",
+			"client_credentials.use_refresh_token": "true"},
 	}
+
+	newClient2 := 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},
+	}
+
+        jwksString := pemtojwks.CreateJWKS("/certs/client_pub.key", "public", "/certs/client.crt") 
+	newClient3 := 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, 
+		},
+        }
+
+	var newClient gocloak.Client
+	if strings.HasPrefix(clientName, "x509") {
+		newClient = newClient2
+	} else if strings.HasPrefix(clientName, "jwt") {
+		newClient = newClient3
+	} else {
+                newClient = newClient1
+        }
+
 	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)
@@ -119,6 +182,23 @@
 		fmt.Println("Service Account user", *user.Username)
 	}
 
+	if strings.HasPrefix(clientName, "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 err != nil {
+			fmt.Println(err)
+			panic("Oh no!, failed to create user :(")
+		} else {
+			fmt.Println("Created new user", realmUser)
+		}
+	}
+
 	clientRole, err := client.GetClientRole(ctx, token.AccessToken, realmName, clientId, clientRoleName)
 	if err != nil {
 		fmt.Println(err)
@@ -137,8 +217,8 @@
 	}
 
 	clientroleMapper := gocloak.ProtocolMapperRepresentation{
-		ID:             gocloak.StringP("clientroleapper"),
-		Name:           gocloak.StringP("clientroleapper"),
+		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{
@@ -160,6 +240,26 @@
 		fmt.Println("Client rolemapper added to client")
 	}
 
+	if strings.HasPrefix(clientName, "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)
+		}
+	}
+
 	_, err = client.RegenerateClientSecret(ctx, token.AccessToken, realmName, clientId)
 	if err != nil {
 		return "", err
@@ -190,7 +290,7 @@
 }
 
 func createSecret(clientSecret, clientName, realmName, role, namespace string) {
-	secretName := role +"-secret"
+	secretName := role + "-secret"
 	clientset := connectToK8s()
 	secrets := clientset.CoreV1().Secrets(namespace)
 	secret := &corev1.Secret{
@@ -198,8 +298,8 @@
 			Name:      secretName,
 			Namespace: namespace,
 			Labels: map[string]string{
-                                        "app" : secretName,
-                                },
+				"app": secretName,
+			},
 		},
 		Type:       "Opaque",
 		StringData: map[string]string{"client_secret": clientSecret, "client_id": clientName, "realm": realmName},
@@ -237,11 +337,29 @@
 			fmt.Println("Deleted client ", clientName)
 		}
 	}
+
+	userName := realmName + "user"
+	users, err := adminClient.GetUsers(ctx, token.AccessToken, realmName,
+		gocloak.GetUsersParams{
+			Username: gocloak.StringP(userName),
+		})
+	if err != nil {
+		panic("List users failed:" + err.Error())
+	}
+	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)
+		}
+	}
+
 }
 
 func removeSecret(namespace, role string) {
 	clientset := connectToK8s()
-	secretName := role +"-secret"
+	secretName := role + "-secret"
 	secrets := clientset.CoreV1().Secrets(namespace)
 	err := secrets.Delete(context.TODO(), secretName, metav1.DeleteOptions{})
 	if err != nil {