Skip to content

Commit 9049e8c

Browse files
timjajanfaracik
andauthored
New credentials dialog (#992)
Co-authored-by: Jan Faracik <43062514+janfaracik@users.noreply.github.com> Co-authored-by: Jan <janf@kainos.com>
1 parent ad001ed commit 9049e8c

33 files changed

+803
-551
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
<changelist>999999-SNAPSHOT</changelist>
6969
<gitHubRepo>jenkinsci/${project.artifactId}-plugin</gitHubRepo>
7070
<!-- https://www.jenkins.io/doc/developer/plugin-development/choosing-jenkins-baseline/ -->
71-
<jenkins.baseline>2.504</jenkins.baseline>
71+
<jenkins.baseline>2.528</jenkins.baseline>
7272
<jenkins.version>${jenkins.baseline}.3</jenkins.version>
7373
<ban-junit4-imports.skip>false</ban-junit4-imports.skip>
7474
<hpi.compatibleSinceVersion>1372</hpi.compatibleSinceVersion>

src/main/java/com/cloudbees/plugins/credentials/CredentialsDescriptor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,4 +605,10 @@ public String toCheckUrl() {
605605
}
606606
}
607607

608+
/**
609+
* @return the description of this credential descriptor.
610+
*/
611+
public String getDescription() {
612+
return null;
613+
}
608614
}

src/main/java/com/cloudbees/plugins/credentials/CredentialsSelectHelper.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,17 @@
4343
import java.util.ArrayList;
4444
import java.util.Collection;
4545
import java.util.HashSet;
46+
import java.util.LinkedHashMap;
4647
import java.util.List;
4748
import java.util.Locale;
4849
import java.util.Map;
50+
import java.util.Objects;
4951
import java.util.Set;
5052
import java.util.TreeMap;
5153
import java.util.logging.Level;
5254
import java.util.logging.Logger;
55+
import java.util.stream.Collectors;
56+
import java.util.stream.StreamSupport;
5357

5458
import jakarta.servlet.ServletException;
5559
import jenkins.model.Jenkins;
@@ -121,6 +125,26 @@ public ModelObject resolveContext(Object context) {
121125
return context instanceof ModelObject mo ? mo : CredentialsDescriptor.findContextInPath(ModelObject.class);
122126
}
123127

128+
/**
129+
* @return modifiable store actions for the context provided.
130+
*/
131+
@Restricted(NoExternalUse.class)
132+
public Map<String, List<CredentialsStoreAction.DomainWrapper>> getModifiableStoreActions(ModelObject context) {
133+
return StreamSupport.stream(CredentialsProvider.lookupStores(context).spliterator(), false)
134+
.filter(s -> s.hasPermission(CredentialsProvider.CREATE))
135+
.map(CredentialsStore::getStoreAction)
136+
.filter(Objects::nonNull)
137+
.collect(Collectors.toMap(
138+
CredentialsStoreAction::getFullDisplayName,
139+
store -> new ArrayList<>(store.getDomains().values()),
140+
(left, right) -> {
141+
left.addAll(right);
142+
return left;
143+
},
144+
LinkedHashMap::new
145+
));
146+
}
147+
124148
/**
125149
* Returns the {@link StoreItem} instances for the current Stapler request.
126150
*

src/main/java/com/cloudbees/plugins/credentials/CredentialsStoreAction.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
import org.kohsuke.stapler.AncestorInPath;
8989
import org.kohsuke.stapler.HttpResponse;
9090
import org.kohsuke.stapler.QueryParameter;
91+
import org.kohsuke.stapler.Stapler;
9192
import org.kohsuke.stapler.StaplerRequest2;
9293
import org.kohsuke.stapler.StaplerResponse2;
9394
import org.kohsuke.stapler.WebMethod;
@@ -571,6 +572,31 @@ public Domain getDomain() {
571572
return domain;
572573
}
573574

575+
/**
576+
* Used to get the path for the action for new credentials.
577+
* Stapler can't figure out the right URL from the dialog, so it needs injecting to it.
578+
* @return
579+
*/
580+
@SuppressWarnings("unused")
581+
@Restricted(NoExternalUse.class)
582+
public String getRelativePath() {
583+
String relativePath = Stapler.getCurrentRequest2().getParameter("relativePath");
584+
if (relativePath == null) {
585+
return null;
586+
}
587+
// Validate the relative path as a security hardening
588+
// There is no known attack vector here, but just in case as it does control what the form action is.
589+
if (!relativePath.startsWith("/")) {
590+
return null;
591+
}
592+
// Prevent protocol-relative URLs
593+
if (relativePath.startsWith("//")) {
594+
return null;
595+
}
596+
597+
return relativePath;
598+
}
599+
574600
/**
575601
* Expose the parent {@link CredentialsStoreAction}.
576602
*
@@ -730,9 +756,12 @@ public CredentialsWrapper getCredential(String id) {
730756
public HttpResponse doCreateCredentials(StaplerRequest2 req) throws ServletException, IOException {
731757
getStore().checkPermission(CREATE);
732758
String requestContentType = req.getContentType();
759+
760+
String acceptHeader = req.getHeader("Accept");
733761
if (requestContentType == null) {
734762
throw new Failure("No Content-Type header set");
735763
}
764+
boolean jsonResponse = acceptHeader != null && acceptHeader.contains("application/json");
736765

737766
if (requestContentType.startsWith("application/xml") || requestContentType.startsWith("text/xml")) {
738767
final StringWriter out = new StringWriter();
@@ -753,7 +782,20 @@ public HttpResponse doCreateCredentials(StaplerRequest2 req) throws ServletExcep
753782
} else {
754783
JSONObject data = req.getSubmittedForm();
755784
Credentials credentials = Descriptor.bindJSON(req, Credentials.class, data.getJSONObject("credentials"));
756-
getStore().addCredentials(domain, credentials);
785+
boolean credentialsWereAdded = getStore().addCredentials(domain, credentials);
786+
787+
if (jsonResponse) {
788+
if (credentialsWereAdded) {
789+
return HttpResponses.okJSON(new JSONObject()
790+
.element("message", "Credentials created")
791+
.element("notificationType", "SUCCESS"));
792+
} else {
793+
return HttpResponses.okJSON(new JSONObject()
794+
.element("message", "Credentials with specified ID already exist")
795+
// TODO: or domain does not exist at all?
796+
.element("notificationType", "ERROR"));
797+
}
798+
}
757799
return HttpResponses.redirectTo("../../domain/" + getUrlName());
758800
}
759801
}

src/main/java/com/cloudbees/plugins/credentials/impl/CertificateCredentialsImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,11 @@ public String getDisplayName() {
232232
return Messages.CertificateCredentialsImpl_DisplayName();
233233
}
234234

235+
@Override
236+
public String getDescription() {
237+
return Messages.CertificateCredentialsImpl_description();
238+
}
239+
235240
/**
236241
* {@inheritDoc}
237242
*/

src/main/java/com/cloudbees/plugins/credentials/impl/UsernamePasswordCredentialsImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,11 @@ public String getDisplayName() {
134134
return Messages.UsernamePasswordCredentialsImpl_DisplayName();
135135
}
136136

137+
@Override
138+
public String getDescription() {
139+
return Messages.UsernamePasswordCredentialsImpl_description();
140+
}
141+
137142
/**
138143
* {@inheritDoc}
139144
*/

src/main/resources/com/cloudbees/plugins/credentials/CredentialsSelectHelper/WrappedCredentialsStore/credential.jelly

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/main/resources/com/cloudbees/plugins/credentials/CredentialsSelectHelper/WrappedCredentialsStore/credential_fr.properties

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/main/resources/com/cloudbees/plugins/credentials/CredentialsSelectHelper/WrappedCredentialsStore/credential_it.properties

Lines changed: 0 additions & 23 deletions
This file was deleted.

src/main/resources/com/cloudbees/plugins/credentials/CredentialsSelectHelper/WrappedCredentialsStore/credential_ja.properties

Lines changed: 0 additions & 23 deletions
This file was deleted.

0 commit comments

Comments
 (0)