NONRTRIC-946: Servicemanager - mock kong and capif as library
[nonrtric/plt/sme.git] / capifcore / internal / keycloak / keycloak.go
index 16f65c8..a4506e0 100644 (file)
@@ -27,28 +27,46 @@ import (
        "net/http"
        "net/url"
 
+       log "github.com/sirupsen/logrus"
        "oransc.org/nonrtric/capifcore/internal/config"
+       "oransc.org/nonrtric/capifcore/internal/restclient"
 )
 
 //go:generate mockery --name AccessManagement
 type AccessManagement interface {
        // Get JWT token for a client.
        // Returns JWT token if client exits and credentials are correct otherwise returns error.
-       GetToken(clientId, clientPassword, scope string, realm string) (Jwttoken, error)
+       GetToken(realm string, data map[string][]string) (Jwttoken, error)
+       // Add new client in keycloak
+       AddClient(clientId string, realm string) error
+       // Returns information about client including secret
+       GetClientRepresentation(clientId string, realm string) (*Client, error)
+}
+
+type AdminUser struct {
+       User     string
+       Password string
 }
 
 type KeycloakManager struct {
        keycloakServerUrl string
+       admin             AdminUser
        realms            map[string]string
+       client            restclient.HTTPClient
 }
 
-func NewKeycloakManager(cfg *config.Config) *KeycloakManager {
+func NewKeycloakManager(cfg *config.Config, c restclient.HTTPClient) *KeycloakManager {
 
        keycloakUrl := "http://" + cfg.AuthorizationServer.Host + ":" + cfg.AuthorizationServer.Port
 
        return &KeycloakManager{
                keycloakServerUrl: keycloakUrl,
-               realms:            cfg.AuthorizationServer.Realms,
+               client:            c,
+               admin: AdminUser{
+                       User:     cfg.AuthorizationServer.AdminUser.User,
+                       Password: cfg.AuthorizationServer.AdminUser.Password,
+               },
+               realms: cfg.AuthorizationServer.Realms,
        }
 }
 
@@ -64,12 +82,15 @@ type Jwttoken struct {
        Scope            string `json:"scope"`
 }
 
-func (km *KeycloakManager) GetToken(clientId, clientPassword, scope string, realm string) (Jwttoken, error) {
+func (km *KeycloakManager) GetToken(realm string, data map[string][]string) (Jwttoken, error) {
        var jwt Jwttoken
-       getTokenUrl := km.keycloakServerUrl + "/realms/" + realm + "/protocol/openid-connect/token"
-
-       resp, err := http.PostForm(getTokenUrl,
-               url.Values{"grant_type": {"client_credentials"}, "client_id": {clientId}, "client_secret": {clientPassword}})
+       realmVal, ok := km.realms[realm]
+       if !ok {
+               log.Errorf("error realm does not exist\n")
+               return jwt, errors.New("realm does not exist")
+       }
+       getTokenUrl := km.keycloakServerUrl + "/realms/" + realmVal + "/protocol/openid-connect/token"
+       resp, err := http.PostForm(getTokenUrl, data)
 
        if err != nil {
                return jwt, err
@@ -81,6 +102,7 @@ func (km *KeycloakManager) GetToken(clientId, clientPassword, scope string, real
        if err != nil {
                return jwt, err
        }
+
        if resp.StatusCode != http.StatusOK {
                return jwt, errors.New(string(body))
        }
@@ -88,3 +110,92 @@ func (km *KeycloakManager) GetToken(clientId, clientPassword, scope string, real
        json.Unmarshal([]byte(body), &jwt)
        return jwt, nil
 }
+
+type Client struct {
+       AdminURL                     string  `json:"adminUrl,omitempty"`
+       AuthorizationServicesEnabled *bool   `json:"authorizationServicesEnabled,omitempty"`
+       BearerOnly                   bool    `json:"bearerOnly,omitempty"`
+       ClientID                     string  `json:"clientId,omitempty"`
+       Enabled                      bool    `json:"enabled,omitempty"`
+       ID                           *string `json:"id,omitempty"`
+       PublicClient                 bool    `json:"publicClient,omitempty"`
+       RootURL                      string  `json:"rootUrl,omitempty"`
+       Secret                       *string `json:"secret,omitempty"`
+       ServiceAccountsEnabled       bool    `json:"serviceAccountsEnabled,omitempty"`
+}
+
+func (km *KeycloakManager) AddClient(clientId string, realm string) error {
+
+       data := url.Values{"grant_type": {"password"}, "username": {km.admin.User}, "password": {km.admin.Password}, "client_id": {"admin-cli"}}
+       token, err := km.GetToken("master", data)
+       if err != nil {
+               log.Errorf("error wrong credentials or url %v\n", err)
+               return err
+       }
+
+       realmVal, ok := km.realms[realm]
+       if !ok {
+               log.Errorf("error realm does not exist\n")
+               return errors.New("realm does not exist")
+       }
+
+       createClientUrl := km.keycloakServerUrl + "/admin/realms/" + realmVal + "/clients"
+       newClient := map[string]interface{}{"clientId": clientId, "serviceAccountsEnabled": true}
+
+       body, err := json.Marshal(newClient)
+       if err != nil {
+               return err
+       }
+
+       var headers = map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + token.AccessToken}
+       if err := restclient.Post(createClientUrl, body, headers, km.client); err != nil {
+               log.Errorf("addClient - error with http request: %+v\n", err)
+               return err
+       }
+
+       log.Debug("Created new client")
+       return nil
+
+}
+
+func (km *KeycloakManager) GetClientRepresentation(clientId string, realm string) (*Client, error) {
+
+       data := url.Values{"grant_type": {"password"}, "username": {km.admin.User}, "password": {km.admin.Password}, "client_id": {"admin-cli"}}
+       token, err := km.GetToken("master", data)
+       if err != nil {
+               log.Errorf("error wrong credentials or url %v\n", err)
+               return nil, err
+       }
+
+       realmVal, ok := km.realms[realm]
+       if !ok {
+               log.Errorf("error realm does not exist\n")
+               return nil, errors.New("realm does not exist")
+       }
+
+       createClientUrl, _ := url.Parse(km.keycloakServerUrl + "/admin/realms/" + realmVal + "/clients")
+       q := createClientUrl.Query()
+       q.Add("clientId", clientId)
+       createClientUrl.RawQuery = q.Encode()
+
+       var headers = map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + token.AccessToken}
+
+       if resp, err := restclient.Get(createClientUrl.String(), headers, km.client); err == nil {
+               var client []Client
+
+               if err = json.Unmarshal(resp, &client); err != nil {
+                       log.Errorf("error unmarshal keycloak client object: %+v\n", err)
+                       return nil, err
+               }
+
+               if len(client) > 0 {
+                       return &client[0], nil
+               }
+               return nil, nil
+
+       } else {
+               log.Errorf("error with http request: %+v\n", err)
+               return nil, err
+       }
+
+}