2 // ========================LICENSE_START=================================
5 // Copyright (C) 2023: Nordix Foundation
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
11 // http://www.apache.org/licenses/LICENSE-2.0
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 // ========================LICENSE_END===================================
30 log "github.com/sirupsen/logrus"
31 "oransc.org/nonrtric/capifcore/internal/config"
32 "oransc.org/nonrtric/capifcore/internal/restclient"
35 //go:generate mockery --name AccessManagement
36 type AccessManagement interface {
37 // Get JWT token for a client.
38 // Returns JWT token if client exits and credentials are correct otherwise returns error.
39 GetToken(realm string, data map[string][]string) (Jwttoken, error)
40 // Add new client in keycloak
41 AddClient(clientId string, realm string) error
44 type AdminUser struct {
49 type KeycloakManager struct {
50 keycloakServerUrl string
52 realms map[string]string
53 client restclient.HTTPClient
56 func NewKeycloakManager(cfg *config.Config, c restclient.HTTPClient) *KeycloakManager {
58 keycloakUrl := "http://" + cfg.AuthorizationServer.Host + ":" + cfg.AuthorizationServer.Port
60 return &KeycloakManager{
61 keycloakServerUrl: keycloakUrl,
64 User: cfg.AuthorizationServer.AdminUser.User,
65 Password: cfg.AuthorizationServer.AdminUser.Password,
67 realms: cfg.AuthorizationServer.Realms,
71 type Jwttoken struct {
72 AccessToken string `json:"access_token"`
73 IDToken string `json:"id_token"`
74 ExpiresIn int `json:"expires_in"`
75 RefreshExpiresIn int `json:"refresh_expires_in"`
76 RefreshToken string `json:"refresh_token"`
77 TokenType string `json:"token_type"`
78 NotBeforePolicy int `json:"not-before-policy"`
79 SessionState string `json:"session_state"`
80 Scope string `json:"scope"`
83 func (km *KeycloakManager) GetToken(realm string, data map[string][]string) (Jwttoken, error) {
85 getTokenUrl := km.keycloakServerUrl + "/realms/" + realm + "/protocol/openid-connect/token"
87 resp, err := http.PostForm(getTokenUrl, data)
93 defer resp.Body.Close()
94 body, err := io.ReadAll(resp.Body)
99 if resp.StatusCode != http.StatusOK {
100 return jwt, errors.New(string(body))
103 json.Unmarshal([]byte(body), &jwt)
108 AdminURL string `json:"adminUrl,omitempty"`
109 BearerOnly bool `json:"bearerOnly,omitempty"`
110 ClientID string `json:"clientId,omitempty"`
111 Enabled bool `json:"enabled,omitempty"`
112 PublicClient bool `json:"publicClient,omitempty"`
113 RootURL string `json:"rootUrl,omitempty"`
114 ServiceAccountsEnabled bool `json:"serviceAccountsEnabled,omitempty"`
117 func (km *KeycloakManager) AddClient(clientId string, realm string) error {
118 data := url.Values{"grant_type": {"password"}, "username": {km.admin.User}, "password": {km.admin.Password}, "client_id": {"admin-cli"}}
119 token, err := km.GetToken("master", data)
121 log.Errorf("error wrong credentials or url %v\n", err)
125 createClientUrl := km.keycloakServerUrl + "/admin/realms/" + realm + "/clients"
129 ServiceAccountsEnabled: true,
134 body, _ := json.Marshal(newClient)
135 var headers = map[string]string{"Content-Type": "application/json", "Authorization": "Bearer " + token.AccessToken}
136 if error := restclient.Post(createClientUrl, body, headers, km.client); error != nil {
137 log.Errorf("error with http request: %+v\n", err)
141 log.Info("Created new client")