Skip to content
Merged

Ccs #11

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions config/configClient.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package config

import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"

"github.com/fiware/VCVerifier/logging"
)

const SERVICES_PATH = "service"

var ErrorCcsNoResponse = errors.New("no_response_from_ccs")
var ErrorCcsErrorResponse = errors.New("error_response_from_ccs")
var ErrorCcsEmptyResponse = errors.New("empty_response_from_ccs")

type HttpClient interface {
Get(url string) (resp *http.Response, err error)
}

type ConfigClient interface {
GetServices() (services []ConfiguredService, err error)
}

type HttpConfigClient struct {
client HttpClient
configEndpoint string
}

type ServicesResponse struct {
Total int `json:"total"`
PageNumber int `json:"pageNumber"`
PageSize int `json:"pageSize"`
Services []ConfiguredService `json:"services"`
}

type ConfiguredService struct {
Id string `json:"id"`
Credentials []Credential `json:"credentials"`
}

type Credential struct {
Type string `json:"type"`
TrustedParticipantsLists []string `json:"trustedParticipantsLists"`
TrustedIssuersLists []string `json:"trustedIssuersLists"`
}

func NewCCSHttpClient(configEndpoint string) (client ConfigClient, err error) {

// no need for a caching client here, since the repo handles the "caching"
httpClient := &http.Client{}
return HttpConfigClient{httpClient, getServiceUrl(configEndpoint)}, err
}

func (hcc HttpConfigClient) GetServices() (services []ConfiguredService, err error) {
var currentPage int = 0
var pageSize int = 100
var finished bool = false
services = []ConfiguredService{}

for !finished {
servicesResponse, err := hcc.getServicesPage(currentPage, pageSize)
if err != nil {
logging.Log().Warnf("Failed to receive services page %v with size %v. Err: %v", currentPage, pageSize, err)
return nil, err
}
services = append(services, servicesResponse.Services...)
// we check both, since its possible that druing the iterration new services where added to old pages(total != len(services)).
// those will be retrieved on next iterration, thus can be ignored
if servicesResponse.Total == 0 || len(servicesResponse.Services) < pageSize || servicesResponse.Total == len(services) {
finished = true
}
currentPage++
}
return services, err
}

func (hcc HttpConfigClient) getServicesPage(page int, pageSize int) (servicesResponse ServicesResponse, err error) {
logging.Log().Debugf("Retrieve services from %s for page %v and size %v.", hcc.configEndpoint, page, pageSize)
resp, err := hcc.client.Get(fmt.Sprintf("%s?pageSize=%v&page=%v", hcc.configEndpoint, pageSize, page))
if err != nil {
logging.Log().Warnf("Was not able to get the services from %s. Err: %v", hcc.configEndpoint, err)
return servicesResponse, err
}
if resp == nil {
logging.Log().Warnf("Was not able to get any response for from %s.", hcc.configEndpoint)
return servicesResponse, ErrorCcsNoResponse
}
if resp.StatusCode != 200 {
logging.Log().Warnf("Was not able to get the services from %s. Stauts: %v", hcc.configEndpoint, resp.StatusCode)
return servicesResponse, ErrorCcsErrorResponse
}
if resp.Body == nil {
logging.Log().Info("Received an empty body from the ccs.")
return servicesResponse, ErrorCcsEmptyResponse
}

err = json.NewDecoder(resp.Body).Decode(&servicesResponse)
if err != nil {
logging.Log().Warn("Was not able to decode the ccs-response.")
return servicesResponse, err
}
logging.Log().Debugf("Services response was: %s.", logging.PrettyPrintObject(servicesResponse))
return servicesResponse, err
}

func getServiceUrl(endpoint string) string {
if strings.HasSuffix(endpoint, "/") {
return endpoint + SERVICES_PATH
} else {
return endpoint + "/" + SERVICES_PATH
}
}
44 changes: 33 additions & 11 deletions verifier/credentialsConfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,29 +30,38 @@ type CredentialsConfig interface {

type ServiceBackedCredentialsConfig struct {
initialConfig *config.ConfigRepo
configEndpoint *url.URL
configClient *config.ConfigClient
scopeCache Cache
trustedParticipantsCache Cache
trustedIssuersCache Cache
}

func InitServiceBackedCredentialsConfig(repoConfig *config.ConfigRepo) (credentialsConfig CredentialsConfig, err error) {
var configClient config.ConfigClient
if repoConfig.ConfigEndpoint == "" {
logging.Log().Warn("No endpoint for the configuration service is configured. Only static configuration will be provided.")
}
serviceUrl, err := url.Parse(repoConfig.ConfigEndpoint)
if err != nil {
logging.Log().Errorf("The service endpoint %s is not a valid url. Err: %v", repoConfig.ConfigEndpoint, err)
return
} else {

_, err = url.Parse(repoConfig.ConfigEndpoint)
if err != nil {
logging.Log().Errorf("The service endpoint %s is not a valid url. Err: %v", repoConfig.ConfigEndpoint, err)
return
}
configClient, err = config.NewCCSHttpClient(repoConfig.ConfigEndpoint)
if err != nil {
logging.Log().Warnf("Was not able to instantiate the config client.")
}
}
var scopeCache Cache = cache.New(CACHE_EXPIRY*time.Second, 2*CACHE_EXPIRY*time.Second)
var trustedParticipantsCache Cache = cache.New(CACHE_EXPIRY*time.Second, 2*CACHE_EXPIRY*time.Second)
var trustedIssuersCache Cache = cache.New(CACHE_EXPIRY*time.Second, 2*CACHE_EXPIRY*time.Second)

scb := ServiceBackedCredentialsConfig{configEndpoint: serviceUrl, scopeCache: scopeCache, trustedParticipantsCache: trustedParticipantsCache, trustedIssuersCache: trustedIssuersCache, initialConfig: repoConfig}
scb := ServiceBackedCredentialsConfig{configClient: &configClient, scopeCache: scopeCache, trustedParticipantsCache: trustedParticipantsCache, trustedIssuersCache: trustedIssuersCache, initialConfig: repoConfig}

scb.fillStaticValues()
taskScheduler := chrono.NewDefaultTaskScheduler()
taskScheduler.ScheduleAtFixedRate(scb.fillCache, time.Duration(30)*time.Second)
if repoConfig.ConfigEndpoint != "" {
chrono.NewDefaultTaskScheduler().ScheduleAtFixedRate(scb.fillCache, time.Duration(30)*time.Second)
}

return scb, err
}
Expand All @@ -74,8 +83,21 @@ func (cc ServiceBackedCredentialsConfig) fillStaticValues() {
}

func (cc ServiceBackedCredentialsConfig) fillCache(ctx context.Context) {

// TODO: add fill from service
client := *(cc.configClient)
services, err := client.GetServices()
if err != nil {
logging.Log().Warnf("Was not able to update the credentials config from the external service. Will try again. Err: %v.", err)
return
}
for _, configuredService := range services {
scopes := []string{}
for _, credential := range configuredService.Credentials {
scopes = append(scopes, credential.Type)
cc.trustedParticipantsCache.Add(fmt.Sprintf(CACHE_KEY_TEMPLATE, configuredService.Id, credential.Type), credential.TrustedParticipantsLists, cache.NoExpiration)
cc.trustedIssuersCache.Add(fmt.Sprintf(CACHE_KEY_TEMPLATE, configuredService.Id, credential.Type), credential.TrustedIssuersLists, cache.NoExpiration)
}
cc.scopeCache.Add(configuredService.Id, scopes, cache.DefaultExpiration)
}
}

func (cc ServiceBackedCredentialsConfig) GetScope(serviceIdentifier string) (credentialTypes []string, err error) {
Expand Down