X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=capifcore%2Finternal%2Fkeycloak%2Fkeycloak.go;h=a4506e02abc45f3dd9616c1a1bfc88a26993e1f4;hb=5493b0faf67fc5b58b575880db528eb2b663d45a;hp=16f65c81268366506bae4524dace8a8625dcf065;hpb=4308df0663b45eb9d95b3babdf519a06ee76c15a;p=nonrtric%2Fplt%2Fsme.git diff --git a/capifcore/internal/keycloak/keycloak.go b/capifcore/internal/keycloak/keycloak.go index 16f65c8..a4506e0 100644 --- a/capifcore/internal/keycloak/keycloak.go +++ b/capifcore/internal/keycloak/keycloak.go @@ -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 + } + +}