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 {