github.com/kyma-incubator/compass/components/director@v0.0.0-20230623144113-d764f56ff805/internal/scopes_sync/service.go (about)

     1  package scopes
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  
     7  	"github.com/kyma-incubator/compass/components/director/pkg/model"
     8  
     9  	"github.com/kyma-incubator/compass/components/director/internal/domain/oauth20"
    10  	"github.com/kyma-incubator/compass/components/director/internal/repo"
    11  	"github.com/kyma-incubator/compass/components/director/pkg/log"
    12  	"github.com/kyma-incubator/compass/components/director/pkg/persistence"
    13  	"github.com/kyma-incubator/compass/components/director/pkg/str"
    14  	"github.com/ory/hydra-client-go/models"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // SyncService missing godoc
    19  type SyncService interface {
    20  	SynchronizeClientScopes(context.Context) error
    21  }
    22  
    23  // SystemAuthRepo missing godoc
    24  //go:generate mockery --name=SystemAuthRepo --output=automock --outpkg=automock --case=underscore --disable-version-string
    25  type SystemAuthRepo interface {
    26  	ListGlobalWithConditions(ctx context.Context, conditions repo.Conditions) ([]model.SystemAuth, error)
    27  }
    28  
    29  // OAuthService missing godoc
    30  //go:generate mockery --name=OAuthService --output=automock --outpkg=automock --case=underscore --disable-version-string
    31  type OAuthService interface {
    32  	ListClients() ([]*models.OAuth2Client, error)
    33  	UpdateClient(ctx context.Context, clientID string, objectType model.SystemAuthReferenceObjectType) error
    34  	GetClientDetails(objType model.SystemAuthReferenceObjectType) (*oauth20.ClientDetails, error)
    35  }
    36  
    37  type service struct {
    38  	oAuth20Svc OAuthService
    39  	transact   persistence.Transactioner
    40  	repo       SystemAuthRepo
    41  }
    42  
    43  // NewService missing godoc
    44  func NewService(oAuth20Svc OAuthService, transact persistence.Transactioner, repo SystemAuthRepo) SyncService {
    45  	return &service{
    46  		oAuth20Svc: oAuth20Svc,
    47  		transact:   transact,
    48  		repo:       repo,
    49  	}
    50  }
    51  
    52  // SynchronizeClientScopes missing godoc
    53  func (s *service) SynchronizeClientScopes(ctx context.Context) error {
    54  	hydraClients, err := s.listHydraClients()
    55  	if err != nil {
    56  		return err
    57  	}
    58  
    59  	auths, err := s.systemAuthsWithOAuth(ctx)
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	areAllClientsUpdated := true
    65  	for _, auth := range auths {
    66  		log.C(ctx).Infof("Synchronizing oauth client of system auth with ID %s", auth.ID)
    67  		if auth.Value == nil || auth.Value.Credential.Oauth == nil {
    68  			log.C(ctx).Infof("System auth with ID %s does not have oauth client for update", auth.ID)
    69  			continue
    70  		}
    71  
    72  		clientID := auth.Value.Credential.Oauth.ClientID
    73  
    74  		objType, err := auth.GetReferenceObjectType()
    75  		if err != nil {
    76  			areAllClientsUpdated = false
    77  			log.C(ctx).WithError(err).Errorf("Error while getting obj type of client with ID %s: %v", clientID, err)
    78  			continue
    79  		}
    80  
    81  		requiredClientDetails, err := s.oAuth20Svc.GetClientDetails(objType)
    82  		if err != nil {
    83  			areAllClientsUpdated = false
    84  			log.C(ctx).WithError(err).Errorf("Error while getting client credentials scopes for client with ID %s: %v", clientID, err)
    85  			continue
    86  		}
    87  
    88  		clientDetails, ok := hydraClients[clientID]
    89  		if !ok {
    90  			log.C(ctx).Errorf("Client with ID %s is not present in Hydra", clientID)
    91  			continue
    92  		}
    93  		if str.Matches(clientDetails.Scopes, requiredClientDetails.Scopes) && str.Matches(clientDetails.GrantTypes, requiredClientDetails.GrantTypes) {
    94  			log.C(ctx).Infof("Scopes and grant types for client with ID %s and type %s are in sync", clientID, objType)
    95  			continue
    96  		}
    97  
    98  		if err = s.oAuth20Svc.UpdateClient(ctx, clientID, objType); err != nil {
    99  			areAllClientsUpdated = false
   100  			log.C(ctx).WithError(err).Errorf("Error while updating scopes of client with ID %s: %v", clientID, err)
   101  		}
   102  	}
   103  	if !areAllClientsUpdated {
   104  		return errors.New("Not all clients were updated successfully")
   105  	}
   106  
   107  	log.C(ctx).Info("Finished synchronization of Hydra scopes")
   108  	return nil
   109  }
   110  
   111  func (s *service) listHydraClients() (map[string]*oauth20.ClientDetails, error) {
   112  	clients, err := s.oAuth20Svc.ListClients()
   113  	if err != nil {
   114  		return nil, errors.Wrap(err, "while listing clients from hydra")
   115  	}
   116  
   117  	clientsMap := make(map[string]*oauth20.ClientDetails)
   118  	for _, c := range clients {
   119  		clientsMap[c.ClientID] = &oauth20.ClientDetails{
   120  			Scopes:     strings.Split(c.Scope, " "),
   121  			GrantTypes: c.GrantTypes,
   122  		}
   123  	}
   124  	return clientsMap, nil
   125  }
   126  
   127  func (s *service) systemAuthsWithOAuth(ctx context.Context) ([]model.SystemAuth, error) {
   128  	tx, err := s.transact.Begin()
   129  	if err != nil {
   130  		return nil, errors.Wrap(err, "while opening database transaction")
   131  	}
   132  	defer s.transact.RollbackUnlessCommitted(ctx, tx)
   133  	ctx = persistence.SaveToContext(ctx, tx)
   134  
   135  	conditions := repo.Conditions{
   136  		repo.NewNotEqualCondition("(value -> 'Credential' -> 'Oauth')", "null"),
   137  	}
   138  	auths, err := s.repo.ListGlobalWithConditions(ctx, conditions)
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	if err := tx.Commit(); err != nil {
   144  		return nil, errors.Wrap(err, "while database transaction commit")
   145  	}
   146  
   147  	return auths, nil
   148  }