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 }