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

     1  package oauth20_test
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"testing"
     7  
     8  	"github.com/kyma-incubator/compass/components/director/internal/model"
     9  
    10  	pkgmodel "github.com/kyma-incubator/compass/components/director/pkg/model"
    11  
    12  	"github.com/kyma-incubator/compass/components/director/internal/domain/oauth20"
    13  	"github.com/kyma-incubator/compass/components/director/internal/domain/oauth20/automock"
    14  	"github.com/ory/hydra-client-go/client/admin"
    15  	"github.com/ory/hydra-client-go/models"
    16  	"github.com/stretchr/testify/assert"
    17  	"github.com/stretchr/testify/mock"
    18  	"github.com/stretchr/testify/require"
    19  )
    20  
    21  const (
    22  	publicEndpoint = "accessTokenURL"
    23  	clientID       = "clientid"
    24  	clientSecret   = "secret"
    25  	objType        = pkgmodel.IntegrationSystemReference
    26  )
    27  
    28  var (
    29  	scopes     = []string{"foo", "bar", "baz"}
    30  	grantTypes = []string{"client_credentials"}
    31  )
    32  
    33  func TestService_CreateClient(t *testing.T) {
    34  	// GIVEN
    35  	successResult := &model.OAuthCredentialDataInput{
    36  		ClientID:     clientID,
    37  		ClientSecret: clientSecret,
    38  		URL:          publicEndpoint,
    39  	}
    40  	testErr := errors.New("test err")
    41  
    42  	testCases := []struct {
    43  		Name                       string
    44  		ExpectedResult             *model.OAuthCredentialDataInput
    45  		ExpectedError              error
    46  		ClientDetailsCfgProviderFn func() *automock.ClientDetailsConfigProvider
    47  		UIDServiceFn               func() *automock.UIDService
    48  		HydraClient                func() *automock.OryHydraService
    49  		ObjectType                 pkgmodel.SystemAuthReferenceObjectType
    50  	}{
    51  		{
    52  			Name:           "Success",
    53  			ExpectedError:  nil,
    54  			ExpectedResult: successResult,
    55  			UIDServiceFn: func() *automock.UIDService {
    56  				uidSvc := &automock.UIDService{}
    57  				uidSvc.On("Generate").Return(clientID).Once()
    58  				return uidSvc
    59  			},
    60  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
    61  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
    62  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.integration_system").Return(scopes, nil).Once()
    63  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(grantTypes, nil).Once()
    64  				return clientDetailsCfgProvider
    65  			},
    66  			HydraClient: func() *automock.OryHydraService {
    67  				hydra := &automock.OryHydraService{}
    68  				hydra.On("CreateOAuth2Client", mock.Anything).Return(&admin.CreateOAuth2ClientCreated{Payload: &models.OAuth2Client{ClientSecret: clientSecret}}, nil).Once()
    69  				return hydra
    70  			},
    71  			ObjectType: objType,
    72  		},
    73  		{
    74  			Name:          "Error when client registration in hydra fails",
    75  			ExpectedError: testErr,
    76  			UIDServiceFn: func() *automock.UIDService {
    77  				uidSvc := &automock.UIDService{}
    78  				uidSvc.On("Generate").Return(clientID).Once()
    79  				return uidSvc
    80  			},
    81  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
    82  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
    83  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.integration_system").Return(scopes, nil).Once()
    84  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(grantTypes, nil).Once()
    85  				return clientDetailsCfgProvider
    86  			},
    87  			HydraClient: func() *automock.OryHydraService {
    88  				hydra := &automock.OryHydraService{}
    89  				hydra.On("CreateOAuth2Client", mock.Anything).Return(&admin.CreateOAuth2ClientCreated{}, testErr).Once()
    90  				return hydra
    91  			},
    92  			ObjectType: objType,
    93  		},
    94  		{
    95  			Name:          "Error when cannot get client credentials scopes",
    96  			ExpectedError: testErr,
    97  			UIDServiceFn: func() *automock.UIDService {
    98  				return &automock.UIDService{}
    99  			},
   100  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   101  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   102  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.application").Return(nil, testErr).Once()
   103  				return clientDetailsCfgProvider
   104  			},
   105  			HydraClient: func() *automock.OryHydraService {
   106  				return &automock.OryHydraService{}
   107  			},
   108  			ObjectType: pkgmodel.ApplicationReference,
   109  		},
   110  		{
   111  			Name:          "Error when cannot get client grant types",
   112  			ExpectedError: testErr,
   113  			UIDServiceFn: func() *automock.UIDService {
   114  				return &automock.UIDService{}
   115  			},
   116  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   117  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   118  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.application").Return(scopes, nil).Once()
   119  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(nil, testErr).Once()
   120  				return clientDetailsCfgProvider
   121  			},
   122  			HydraClient: func() *automock.OryHydraService {
   123  				return &automock.OryHydraService{}
   124  			},
   125  			ObjectType: pkgmodel.ApplicationReference,
   126  		},
   127  	}
   128  
   129  	for _, testCase := range testCases {
   130  		t.Run(testCase.Name, func(t *testing.T) {
   131  			ctx := context.TODO()
   132  			clientDetailsCfgProvider := testCase.ClientDetailsCfgProviderFn()
   133  			defer clientDetailsCfgProvider.AssertExpectations(t)
   134  			uidService := testCase.UIDServiceFn()
   135  			defer uidService.AssertExpectations(t)
   136  			hydraService := testCase.HydraClient()
   137  			defer hydraService.AssertExpectations(t)
   138  
   139  			svc := oauth20.NewService(clientDetailsCfgProvider, uidService, publicEndpoint, hydraService)
   140  
   141  			// WHEN
   142  			oauthData, err := svc.CreateClientCredentials(ctx, testCase.ObjectType)
   143  
   144  			// THEN
   145  			if testCase.ExpectedError == nil {
   146  				require.NoError(t, err)
   147  				assert.Equal(t, testCase.ExpectedResult, oauthData)
   148  			} else {
   149  				require.Error(t, err)
   150  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   151  			}
   152  		})
   153  	}
   154  }
   155  
   156  func TestService_UpdateClient(t *testing.T) {
   157  	// GIVEN
   158  	testErr := errors.New("test err")
   159  	testCases := []struct {
   160  		Name                       string
   161  		ExpectedError              error
   162  		ClientDetailsCfgProviderFn func() *automock.ClientDetailsConfigProvider
   163  		HydraClient                func() *automock.OryHydraService
   164  		ObjectType                 pkgmodel.SystemAuthReferenceObjectType
   165  	}{
   166  		{
   167  			Name:          "Success",
   168  			ExpectedError: nil,
   169  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   170  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   171  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.integration_system").Return(scopes, nil).Once()
   172  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(grantTypes, nil).Once()
   173  				return clientDetailsCfgProvider
   174  			},
   175  			HydraClient: func() *automock.OryHydraService {
   176  				hydra := &automock.OryHydraService{}
   177  				hydra.On("UpdateOAuth2Client", mock.Anything).Return(nil, nil).Once()
   178  				return hydra
   179  			},
   180  			ObjectType: objType,
   181  		},
   182  		{
   183  			Name:          "Error when client update in hydra fails",
   184  			ExpectedError: testErr,
   185  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   186  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   187  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.integration_system").Return(scopes, nil).Once()
   188  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(grantTypes, nil).Once()
   189  				return clientDetailsCfgProvider
   190  			},
   191  			HydraClient: func() *automock.OryHydraService {
   192  				hydra := &automock.OryHydraService{}
   193  				hydra.On("UpdateOAuth2Client", mock.Anything).Return(nil, testErr).Once()
   194  				return hydra
   195  			},
   196  			ObjectType: objType,
   197  		},
   198  		{
   199  			Name:          "Error when cannot get client credentials scopes",
   200  			ExpectedError: testErr,
   201  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   202  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   203  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.application").Return(nil, testErr).Once()
   204  				return clientDetailsCfgProvider
   205  			},
   206  			HydraClient: func() *automock.OryHydraService {
   207  				return &automock.OryHydraService{}
   208  			},
   209  			ObjectType: pkgmodel.ApplicationReference,
   210  		},
   211  		{
   212  			Name:          "Error when cannot get client grant types",
   213  			ExpectedError: testErr,
   214  			ClientDetailsCfgProviderFn: func() *automock.ClientDetailsConfigProvider {
   215  				clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   216  				clientDetailsCfgProvider.On("GetRequiredScopes", "scopesPerConsumerType.application").Return(scopes, nil).Once()
   217  				clientDetailsCfgProvider.On("GetRequiredGrantTypes", "clientCredentialsRegistrationGrantTypes").Return(nil, testErr).Once()
   218  				return clientDetailsCfgProvider
   219  			},
   220  			HydraClient: func() *automock.OryHydraService {
   221  				return &automock.OryHydraService{}
   222  			},
   223  			ObjectType: pkgmodel.ApplicationReference,
   224  		},
   225  	}
   226  
   227  	for _, testCase := range testCases {
   228  		t.Run(testCase.Name, func(t *testing.T) {
   229  			ctx := context.TODO()
   230  			clientDetailsCfgProvider := testCase.ClientDetailsCfgProviderFn()
   231  			defer clientDetailsCfgProvider.AssertExpectations(t)
   232  			uidService := &automock.UIDService{}
   233  			defer uidService.AssertExpectations(t)
   234  			hydraService := testCase.HydraClient()
   235  			defer hydraService.AssertExpectations(t)
   236  
   237  			svc := oauth20.NewService(clientDetailsCfgProvider, uidService, publicEndpoint, hydraService)
   238  
   239  			// WHEN
   240  			err := svc.UpdateClient(ctx, clientID, testCase.ObjectType)
   241  
   242  			// THEN
   243  			if testCase.ExpectedError == nil {
   244  				require.NoError(t, err)
   245  			} else {
   246  				require.Error(t, err)
   247  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   248  			}
   249  		})
   250  	}
   251  }
   252  
   253  func TestService_DeleteClientCredentials(t *testing.T) {
   254  	// GIVEN
   255  	id := "foo"
   256  	testErr := errors.New("test err")
   257  	testCases := []struct {
   258  		Name          string
   259  		ExpectedError error
   260  		HydraClient   func() *automock.OryHydraService
   261  	}{
   262  		{
   263  			Name:          "Success",
   264  			ExpectedError: nil,
   265  			HydraClient: func() *automock.OryHydraService {
   266  				hydra := &automock.OryHydraService{}
   267  				hydra.On("DeleteOAuth2Client", mock.Anything).Return(nil, nil).Once()
   268  				return hydra
   269  			},
   270  		},
   271  		{
   272  			Name:          "Fails when hydra cannot delete client",
   273  			ExpectedError: testErr,
   274  			HydraClient: func() *automock.OryHydraService {
   275  				hydra := &automock.OryHydraService{}
   276  				hydra.On("DeleteOAuth2Client", mock.Anything).Return(nil, testErr).Once()
   277  				return hydra
   278  			},
   279  		},
   280  	}
   281  
   282  	for _, testCase := range testCases {
   283  		t.Run(testCase.Name, func(t *testing.T) {
   284  			ctx := context.TODO()
   285  			hydraService := testCase.HydraClient()
   286  			defer hydraService.AssertExpectations(t)
   287  
   288  			svc := oauth20.NewService(nil, nil, publicEndpoint, hydraService)
   289  
   290  			// WHEN
   291  			err := svc.DeleteClientCredentials(ctx, id)
   292  
   293  			// THEN
   294  			if testCase.ExpectedError == nil {
   295  				require.NoError(t, err)
   296  			} else {
   297  				require.Error(t, err)
   298  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   299  			}
   300  		})
   301  	}
   302  }
   303  
   304  func TestService_DeleteMultipleClientCredentials(t *testing.T) {
   305  	// GIVEN
   306  	testErr := errors.New("test err")
   307  	testCases := []struct {
   308  		Name          string
   309  		ExpectedError error
   310  		HydraClient   func() *automock.OryHydraService
   311  		Auths         []pkgmodel.SystemAuth
   312  	}{
   313  		{
   314  			Name:          "Success",
   315  			ExpectedError: nil,
   316  			HydraClient: func() *automock.OryHydraService {
   317  				hydra := &automock.OryHydraService{}
   318  				hydra.On("DeleteOAuth2Client", mock.Anything).Return(nil, nil)
   319  				return hydra
   320  			},
   321  			Auths: []pkgmodel.SystemAuth{
   322  				{
   323  					Value: &model.Auth{
   324  						Credential: model.CredentialData{
   325  							Oauth: &model.OAuthCredentialData{
   326  								ClientID: clientID,
   327  							},
   328  						},
   329  					},
   330  				},
   331  			},
   332  		},
   333  		{
   334  			Name:          "Will not delete auth when value is nil",
   335  			ExpectedError: nil,
   336  			HydraClient: func() *automock.OryHydraService {
   337  				return &automock.OryHydraService{}
   338  			},
   339  			Auths: []pkgmodel.SystemAuth{
   340  				{
   341  					Value: nil,
   342  				},
   343  			},
   344  		},
   345  		{
   346  			Name:          "Will not delete auth when Oauth is nil",
   347  			ExpectedError: nil,
   348  			HydraClient: func() *automock.OryHydraService {
   349  				return &automock.OryHydraService{}
   350  			},
   351  			Auths: []pkgmodel.SystemAuth{
   352  				{
   353  					Value: &model.Auth{
   354  						Credential: model.CredentialData{
   355  							Oauth: nil,
   356  						},
   357  					},
   358  				},
   359  			},
   360  		},
   361  		{
   362  			Name:          "Fails when hydra cannot delete client",
   363  			ExpectedError: testErr,
   364  			HydraClient: func() *automock.OryHydraService {
   365  				hydra := &automock.OryHydraService{}
   366  				hydra.On("DeleteOAuth2Client", admin.NewDeleteOAuth2ClientParams().WithID(clientID)).Return(nil, testErr)
   367  				return hydra
   368  			},
   369  			Auths: []pkgmodel.SystemAuth{
   370  				{
   371  					Value: &model.Auth{
   372  						Credential: model.CredentialData{
   373  							Oauth: &model.OAuthCredentialData{
   374  								ClientID: clientID,
   375  							},
   376  						},
   377  					},
   378  				},
   379  			},
   380  		},
   381  	}
   382  
   383  	for _, testCase := range testCases {
   384  		t.Run(testCase.Name, func(t *testing.T) {
   385  			ctx := context.TODO()
   386  			hydraService := testCase.HydraClient()
   387  			defer hydraService.AssertExpectations(t)
   388  
   389  			svc := oauth20.NewService(nil, nil, publicEndpoint, hydraService)
   390  
   391  			// WHEN
   392  			err := svc.DeleteMultipleClientCredentials(ctx, testCase.Auths)
   393  
   394  			// THEN
   395  			if testCase.ExpectedError == nil {
   396  				require.NoError(t, err)
   397  			} else {
   398  				require.Error(t, err)
   399  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   400  			}
   401  		})
   402  	}
   403  }
   404  func TestService_ListClients(t *testing.T) {
   405  	// GIVEN
   406  	testErr := errors.New("test err")
   407  	testCases := []struct {
   408  		Name          string
   409  		ExpectedError error
   410  		HydraClient   func() *automock.OryHydraService
   411  	}{
   412  		{
   413  			Name:          "Success",
   414  			ExpectedError: nil,
   415  			HydraClient: func() *automock.OryHydraService {
   416  				hydra := &automock.OryHydraService{}
   417  				hydra.On("ListOAuth2Clients", mock.Anything).Return(&admin.ListOAuth2ClientsOK{Payload: []*models.OAuth2Client{{ClientSecret: clientSecret}}}, nil).Once()
   418  				return hydra
   419  			},
   420  		},
   421  		{
   422  			Name:          "Fails when hydra cannot list clients",
   423  			ExpectedError: testErr,
   424  			HydraClient: func() *automock.OryHydraService {
   425  				hydra := &automock.OryHydraService{}
   426  				hydra.On("ListOAuth2Clients", mock.Anything).Return(nil, testErr).Once()
   427  				return hydra
   428  			},
   429  		},
   430  	}
   431  
   432  	for _, testCase := range testCases {
   433  		t.Run(testCase.Name, func(t *testing.T) {
   434  			clientDetailsCfgProvider := &automock.ClientDetailsConfigProvider{}
   435  			defer clientDetailsCfgProvider.AssertExpectations(t)
   436  			uidService := &automock.UIDService{}
   437  			defer uidService.AssertExpectations(t)
   438  			hydraService := testCase.HydraClient()
   439  			defer hydraService.AssertExpectations(t)
   440  
   441  			svc := oauth20.NewService(clientDetailsCfgProvider, uidService, publicEndpoint, hydraService)
   442  
   443  			// WHEN
   444  			clients, err := svc.ListClients()
   445  
   446  			// THEN
   447  			if testCase.ExpectedError == nil {
   448  				require.NoError(t, err)
   449  				require.Len(t, clients, 1)
   450  			} else {
   451  				require.Error(t, err)
   452  				require.Len(t, clients, 0)
   453  				assert.Contains(t, err.Error(), testCase.ExpectedError.Error())
   454  			}
   455  		})
   456  	}
   457  }