3
3
import com .cloudbees .plugins .credentials .CredentialsMatcher ;
4
4
import com .cloudbees .plugins .credentials .CredentialsMatchers ;
5
5
import com .cloudbees .plugins .credentials .CredentialsProvider ;
6
+ import com .cloudbees .plugins .credentials .CredentialsScope ;
7
+ import com .cloudbees .plugins .credentials .SystemCredentialsProvider ;
6
8
import com .cloudbees .plugins .credentials .common .StandardCredentials ;
7
9
import com .cloudbees .plugins .credentials .common .StandardListBoxModel ;
8
10
import edu .umd .cs .findbugs .annotations .CheckForNull ;
11
13
import hudson .Util ;
12
14
import hudson .model .AbstractDescribableImpl ;
13
15
import hudson .model .Descriptor ;
16
+ import hudson .model .Item ;
17
+ import hudson .model .ItemGroup ;
14
18
import hudson .security .ACL ;
15
19
import hudson .security .AccessControlled ;
16
20
import hudson .util .FormValidation ;
20
24
import java .net .MalformedURLException ;
21
25
import java .net .URL ;
22
26
import java .security .SecureRandom ;
27
+ import java .util .Collections ;
28
+ import java .util .List ;
23
29
import java .util .logging .Level ;
24
30
import java .util .logging .Logger ;
25
31
import jenkins .model .Jenkins ;
29
35
import org .gitlab4j .api .GitLabApi ;
30
36
import org .gitlab4j .api .GitLabApiException ;
31
37
import org .gitlab4j .api .models .User ;
38
+ import org .jenkinsci .plugins .plaincredentials .StringCredentials ;
39
+ import org .jenkinsci .plugins .plaincredentials .impl .StringCredentialsImpl ;
32
40
import org .kohsuke .accmod .Restricted ;
33
41
import org .kohsuke .accmod .restrictions .DoNotUse ;
34
42
import org .kohsuke .accmod .restrictions .NoExternalUse ;
@@ -126,8 +134,22 @@ public class GitLabServer extends AbstractDescribableImpl<GitLabServer> {
126
134
127
135
/**
128
136
* The secret token used while setting up hook url in the GitLab server
137
+ * @Deprecated Use webhookSecretCredentialsId instead
129
138
*/
130
- private Secret secretToken ;
139
+ private transient Secret secretToken ;
140
+
141
+ /**
142
+ * The credentials id of the webhook secret token used while setting up hook url in the GitLab server
143
+ */
144
+ @ NonNull
145
+ private String webhookSecretCredentialsId ;
146
+
147
+
148
+ /**
149
+ * The credentials matcher for StringCredentials
150
+ */
151
+ public static final CredentialsMatcher WEBHOOK_SECRET_CREDENTIALS_MATCHER = CredentialsMatchers
152
+ .instanceOf (StringCredentials .class );
131
153
132
154
/**
133
155
* {@code true} if and only if Jenkins should trigger a build immediately on a
@@ -159,6 +181,7 @@ public GitLabServer(@NonNull String serverUrl, @NonNull String name,
159
181
? getRandomName ()
160
182
: StringUtils .trim (name );
161
183
this .credentialsId = credentialsId ;
184
+ this .webhookSecretCredentialsId = "" ;
162
185
}
163
186
164
187
/**
@@ -287,16 +310,53 @@ public String getHooksRootUrl() {
287
310
return Util .ensureEndsWith (Util .fixEmptyAndTrim (hooksRootUrl ), "/" );
288
311
}
289
312
290
- @ DataBoundSetter
313
+ @ DataBoundSetter @ Deprecated
291
314
public void setSecretToken (Secret token ) {
292
315
this .secretToken = token ;
293
316
}
294
317
295
- // TODO: Use some UI element to trigger (what is the best way?)
296
- private void generateSecretToken () {
297
- byte [] random = new byte [16 ]; // 16x8=128bit worth of randomness, since we use md5 digest as the API token
298
- RANDOM .nextBytes (random );
299
- this .secretToken = Secret .decrypt (Util .toHexString (random ));
318
+ @ DataBoundSetter
319
+ public void setWebhookSecretCredentialsId (String token ) {
320
+ this .webhookSecretCredentialsId = token ;
321
+ }
322
+
323
+ public String getWebhookSecretCredentialsId () {
324
+ return webhookSecretCredentialsId ;
325
+ }
326
+
327
+ /**
328
+ * Looks up for StringCredentials
329
+ *
330
+ * @return {@link StringCredentials}
331
+ */
332
+ public StringCredentials getWebhookSecretCredentials (AccessControlled context ) {
333
+ Jenkins jenkins = Jenkins .get ();
334
+ if (context == null ) {
335
+ jenkins .checkPermission (CredentialsProvider .USE_OWN );
336
+ return StringUtils .isBlank (webhookSecretCredentialsId ) ? null : CredentialsMatchers .firstOrNull ( lookupCredentials (
337
+ StringCredentials .class ,
338
+ jenkins ,
339
+ ACL .SYSTEM ,
340
+ fromUri (defaultIfBlank (serverUrl , GITLAB_SERVER_URL )).build ()
341
+ ), withId (webhookSecretCredentialsId ));
342
+ } else {
343
+ context .checkPermission (CredentialsProvider .USE_OWN );
344
+ if (context instanceof ItemGroup ) {
345
+ return StringUtils .isBlank (webhookSecretCredentialsId ) ? null : CredentialsMatchers .firstOrNull ( lookupCredentials (
346
+ StringCredentials .class ,
347
+ (ItemGroup ) context ,
348
+ ACL .SYSTEM ,
349
+ fromUri (defaultIfBlank (serverUrl , GITLAB_SERVER_URL )).build ()
350
+ ), withId (webhookSecretCredentialsId ));
351
+ } else {
352
+ return StringUtils .isBlank (webhookSecretCredentialsId ) ? null : CredentialsMatchers .firstOrNull ( lookupCredentials (
353
+ StringCredentials .class ,
354
+ (Item ) context ,
355
+ ACL .SYSTEM ,
356
+ fromUri (defaultIfBlank (serverUrl , GITLAB_SERVER_URL )).build ()
357
+ ), withId (webhookSecretCredentialsId ));
358
+ }
359
+ }
300
360
}
301
361
302
362
/**
@@ -307,15 +367,63 @@ public DescriptorImpl getDescriptor() {
307
367
return (DescriptorImpl ) super .getDescriptor ();
308
368
}
309
369
370
+ @ Deprecated
310
371
public Secret getSecretToken () {
311
372
return secretToken ;
312
373
}
313
374
375
+ private StringCredentials getWebhookSecretCredentials (String webhookSecretCredentialsId ) {
376
+ Jenkins jenkins = Jenkins .get ();
377
+ jenkins .checkPermission (Jenkins .ADMINISTER );
378
+ return StringUtils .isBlank (webhookSecretCredentialsId ) ? null : CredentialsMatchers .firstOrNull (
379
+ lookupCredentials (StringCredentials .class , jenkins ),
380
+ withId (webhookSecretCredentialsId )
381
+ );
382
+ }
383
+
314
384
public String getSecretTokenAsPlainText () {
315
- if (this .secretToken == null ) {
385
+ StringCredentials credentials = getWebhookSecretCredentials (webhookSecretCredentialsId );
386
+ String secretToken = "" ;
387
+ if (credentials != null ) {
388
+ secretToken = credentials .getSecret ().getPlainText ();
389
+ } else {
316
390
return null ;
317
391
}
318
- return this .secretToken .getPlainText ();
392
+ return secretToken ;
393
+ }
394
+
395
+ private Object readResolve () {
396
+ if (StringUtils .isBlank (webhookSecretCredentialsId ) && secretToken != null ) {
397
+ migrateWebhookSecretCredentials ();
398
+ }
399
+ return this ;
400
+ }
401
+
402
+ /**
403
+ * Migrate webhook secret token to Jenkins credentials
404
+ */
405
+ private void migrateWebhookSecretCredentials () {
406
+ final List <StringCredentials > credentials =
407
+ CredentialsProvider .lookupCredentials (StringCredentials .class , Jenkins .get (), ACL .SYSTEM , Collections .emptyList ());
408
+ for (final StringCredentials cred : credentials ) {
409
+ if (StringUtils .equals (secretToken .getPlainText (), Secret .toString (cred .getSecret ()))) {
410
+ // If a credential has the same secret, use it.
411
+ webhookSecretCredentialsId = cred .getId ();
412
+ break ;
413
+ }
414
+ }
415
+ if (StringUtils .isBlank (webhookSecretCredentialsId )) {
416
+ // If we couldn't find any existing credentials, create new credential
417
+ final StringCredentials newCredentials =
418
+ new StringCredentialsImpl (
419
+ CredentialsScope .GLOBAL ,
420
+ null ,
421
+ "Migrated from gitlab-branch-source-plugin webhook secret" ,
422
+ secretToken );
423
+ SystemCredentialsProvider .getInstance ().getCredentials ().add (newCredentials );
424
+ webhookSecretCredentialsId = newCredentials .getId ();
425
+ }
426
+ secretToken = null ;
319
427
}
320
428
321
429
/**
@@ -485,13 +593,11 @@ public FormValidation doTestConnection(@QueryParameter String serverUrl,
485
593
try {
486
594
User user = gitLabApi .getUserApi ().getCurrentUser ();
487
595
LOGGER .log (Level .FINEST , String
488
- .format ("Connection established with the GitLab Server for %s" ,
489
- user .getUsername ()));
596
+ .format ("Connection established with the GitLab Server for %s" , user .getUsername ()));
490
597
return FormValidation
491
598
.ok (String .format ("Credentials verified for user %s" , user .getUsername ()));
492
599
} catch (GitLabApiException e ) {
493
- LOGGER .log (Level .SEVERE ,
494
- "Failed to connect with GitLab Server - %s" , e .getMessage ());
600
+ LOGGER .log (Level .SEVERE , "Failed to connect with GitLab Server - %s" , e .getMessage ());
495
601
return FormValidation .error (e ,
496
602
Messages .GitLabServer_failedValidation (Util .escape (e .getMessage ())));
497
603
}
@@ -522,6 +628,30 @@ public ListBoxModel doFillCredentialsIdItems(@QueryParameter String serverUrl,
522
628
CREDENTIALS_MATCHER );
523
629
}
524
630
631
+ /**
632
+ * Stapler form completion.
633
+ *
634
+ * @param webhookSecretCredentialsId the webhook secret credentials Id
635
+ * @return the available credentials.
636
+ */
637
+ @ Restricted (NoExternalUse .class ) // stapler
638
+ @ SuppressWarnings ("unused" )
639
+ public ListBoxModel doFillWebhookSecretCredentialsIdItems (@ QueryParameter String serverUrl ,
640
+ @ QueryParameter String webhookSecretCredentialsId ) {
641
+ Jenkins jenkins = Jenkins .get ();
642
+ if (!jenkins .hasPermission (Jenkins .ADMINISTER )) {
643
+ return new StandardListBoxModel ().includeCurrentValue (webhookSecretCredentialsId );
644
+ }
645
+ return new StandardListBoxModel ()
646
+ .includeEmptyValue ()
647
+ .includeMatchingAs (ACL .SYSTEM ,
648
+ jenkins ,
649
+ StringCredentials .class ,
650
+ fromUri (serverUrl ).build (),
651
+ WEBHOOK_SECRET_CREDENTIALS_MATCHER
652
+ );
653
+ }
654
+
525
655
private PersonalAccessToken getCredentials (String serverUrl , String credentialsId ) {
526
656
Jenkins jenkins = Jenkins .get ();
527
657
jenkins .checkPermission (Jenkins .ADMINISTER );
0 commit comments