未验证 提交 0fd8808b 编写于 作者: J Jesse Glick

Merge branch 'master' into access-modifier

......@@ -89,6 +89,9 @@ import javax.annotation.Nullable;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.io.FileUtils;
/**
* Various utility methods that don't have more proper home.
*
......@@ -181,43 +184,54 @@ public class Util {
}
/**
* Loads the contents of a file into a string.
* Reads the entire contents of the text file at <code>logfile</code> into a
* string using the {@link Charset#defaultCharset() default charset} for
* decoding. If no such file exists, an empty string is returned.
* @param logfile The text file to read in its entirety.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
* @deprecated call {@link #loadFile(java.io.File, java.nio.charset.Charset)}
* instead to specify the charset to use for decoding (preferably
* {@link java.nio.charset.StandardCharsets#UTF_8}).
*/
@Nonnull
@Deprecated
public static String loadFile(@Nonnull File logfile) throws IOException {
return loadFile(logfile, Charset.defaultCharset());
}
/**
* Reads the entire contents of the text file at <code>logfile</code> into a
* string using <code>charset</code> for decoding. If no such file exists,
* an empty string is returned.
* @param logfile The text file to read in its entirety.
* @param charset The charset to use for decoding the bytes in <code>logfile</code>.
* @return The entire text content of <code>logfile</code>.
* @throws IOException If an error occurs while reading the file.
*/
@Nonnull
public static String loadFile(@Nonnull File logfile, @Nonnull Charset charset) throws IOException {
if(!logfile.exists())
return "";
StringBuilder str = new StringBuilder((int)logfile.length());
// We're not using Files.newBufferedReader() here because there is a
// difference in how an InputStreamReader constructed from a Charset and
// the reader returned by Files.newBufferedReader() handle malformed and
// unmappable byte sequences for the specified encoding; the latter is
// more picky and will throw a CharacterCodingException. See:
// https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
// Note: Until charset handling is resolved (e.g. by implementing
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), this method
// must be able to handle character encoding errors. As reported at
// https://issues.jenkins-ci.org/browse/JENKINS-49112 Run.getLog() calls
// loadFile() to fully read the generated log file. This file might
// contain unmappable and/or malformed byte sequences. We need to make
// sure that in such cases, no CharacterCodingException is thrown.
//
// As reported at https://issues.jenkins-ci.org/browse/JENKINS-49112
// Run.getLog() calls loadFile() to fully read the generated log file.
// Until charset handling is resolved (e.g. by implementing
// https://issues.jenkins-ci.org/browse/JENKINS-48923 ), malformed
// bytes will need to be tolerated.
try (InputStream rawIn = Files.newInputStream(fileToPath(logfile));
Reader r = new BufferedReader(new InputStreamReader(rawIn, charset))) {
char[] buf = new char[1024];
int len;
while ((len = r.read(buf, 0, buf.length)) > 0)
str.append(buf, 0, len);
// One approach that cannot be used is to call Files.newBufferedReader()
// because there is a difference in how an InputStreamReader constructed
// from a Charset and the reader returned by Files.newBufferedReader()
// handle malformed and unmappable byte sequences for the specified
// encoding; the latter is more picky and will throw an exception.
// See: https://issues.jenkins-ci.org/browse/JENKINS-49060?focusedCommentId=325989&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-325989
try {
return FileUtils.readFileToString(logfile, charset);
} catch (FileNotFoundException e) {
return "";
} catch (Exception e) {
throw new IOException("Failed to fully read " + logfile + " using charset " + charset.name(), e);
throw new IOException("Failed to fully read " + logfile, e);
}
return str.toString();
}
/**
......
/*
* The MIT License
*
* Copyright (c) 2017 Jenkins contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package hudson.security;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
/**
* Thrown if an account creation was attempted but failed due to invalid data being entered into a form.
*
* @author Philipp Nowak
*/
@Restricted(NoExternalUse.class)
public class AccountCreationFailedException extends Exception {
public AccountCreationFailedException(String message) {
super(message);
}
}
......@@ -289,6 +289,26 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
return u;
}
/**
* Creates a user account. Intended to be called from the setup wizard.
* Note that this method does not check whether it is actually called from
* the setup wizard. This requires the {@link Jenkins#ADMINISTER} permission.
*
* @param req the request to retrieve input data from
* @return the created user account, never null
* @throws AccountCreationFailedException if account creation failed due to invalid form input
*/
@Restricted(NoExternalUse.class)
public User createAccountFromSetupWizard(StaplerRequest req) throws IOException, AccountCreationFailedException {
checkPermission(Jenkins.ADMINISTER);
SignupInfo si = validateAccountCreationForm(req, false);
if (si.errorMessage != null) {
throw new AccountCreationFailedException(si.errorMessage);
} else {
return createAccount(si);
}
}
/**
* Creates a first admin user account.
*
......@@ -321,65 +341,102 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
}
/**
* @param req the request to get the form data from (is also used for redirection)
* @param rsp the response to use for forwarding if the creation fails
* @param validateCaptcha whether to attempt to validate a captcha in the request
* @param formView the view to redirect to if creation fails
*
* @return
* null if failed. The browser is already redirected to retry by the time this method returns.
* a valid {@link User} object if the user creation was successful.
*/
private User createAccount(StaplerRequest req, StaplerResponse rsp, boolean selfRegistration, String formView) throws ServletException, IOException {
private User createAccount(StaplerRequest req, StaplerResponse rsp, boolean validateCaptcha, String formView) throws ServletException, IOException {
SignupInfo si = validateAccountCreationForm(req, validateCaptcha);
if (si.errorMessage != null) {
// failed. ask the user to try again.
req.getView(this, formView).forward(req, rsp);
return null;
}
return createAccount(si);
}
/**
* @param req the request to process
* @param validateCaptcha whether to attempt to validate a captcha in the request
*
* @return a {@link SignupInfo#SignupInfo(StaplerRequest) SignupInfo from given request}, with {@link
* SignupInfo#errorMessage} set to a non-null value if any of the supported fields are invalid
*/
private SignupInfo validateAccountCreationForm(StaplerRequest req, boolean validateCaptcha) {
// form field validation
// this pattern needs to be generalized and moved to stapler
SignupInfo si = new SignupInfo(req);
if(selfRegistration && !validateCaptcha(si.captcha))
if (validateCaptcha && !validateCaptcha(si.captcha)) {
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_TextNotMatchWordInImage();
}
if(si.password1 != null && !si.password1.equals(si.password2))
if (si.password1 != null && !si.password1.equals(si.password2)) {
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_PasswordNotMatch();
}
if(!(si.password1 != null && si.password1.length() != 0))
if (!(si.password1 != null && si.password1.length() != 0)) {
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_PasswordRequired();
}
if(si.username==null || si.username.length()==0)
if (si.username == null || si.username.length() == 0) {
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_UserNameRequired();
else {
} else {
// do not create the user - we just want to check if the user already exists but is not a "login" user.
User user = User.getById(si.username, false);
User user = User.getById(si.username, false);
if (null != user)
// Allow sign up. SCM people has no such property.
if (user.getProperty(Details.class) != null)
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_UserNameAlreadyTaken();
}
if(si.fullname==null || si.fullname.length()==0)
if (si.fullname == null || si.fullname.length() == 0) {
si.fullname = si.username;
}
if(isMailerPluginPresent() && (si.email==null || !si.email.contains("@")))
if (isMailerPluginPresent() && (si.email == null || !si.email.contains("@"))) {
si.errorMessage = Messages.HudsonPrivateSecurityRealm_CreateAccount_InvalidEmailAddress();
}
if (! User.isIdOrFullnameAllowed(si.username)) {
if (!User.isIdOrFullnameAllowed(si.username)) {
si.errorMessage = hudson.model.Messages.User_IllegalUsername(si.username);
}
if (! User.isIdOrFullnameAllowed(si.fullname)) {
if (!User.isIdOrFullnameAllowed(si.fullname)) {
si.errorMessage = hudson.model.Messages.User_IllegalFullname(si.fullname);
}
req.setAttribute("data", si); // for error messages in the view
return si;
}
if(si.errorMessage!=null) {
// failed. ask the user to try again.
req.setAttribute("data",si);
req.getView(this, formView).forward(req,rsp);
return null;
/**
* Creates a new account from a valid signup info. A signup info is valid if its {@link SignupInfo#errorMessage}
* field is null.
*
* @param si the valid signup info to create an account from
* @return a valid {@link User} object created from given signup info
* @throws IllegalArgumentException if an invalid signup info is passed
*/
private User createAccount(SignupInfo si) throws IOException {
if (si.errorMessage != null) {
throw new IllegalArgumentException("invalid signup info passed to createAccount(si): " + si.errorMessage);
}
// register the user
User user = createAccount(si.username,si.password1);
User user = createAccount(si.username, si.password1);
user.setFullName(si.fullname);
if(isMailerPluginPresent()) {
if (isMailerPluginPresent()) {
try {
// legacy hack. mail support has moved out to a separate plugin
Class<?> up = Jenkins.getInstance().pluginManager.uberClassLoader.loadClass("hudson.tasks.Mailer$UserProperty");
Constructor<?> c = up.getDeclaredConstructor(String.class);
user.addProperty((UserProperty)c.newInstance(si.email));
user.addProperty((UserProperty) c.newInstance(si.email));
} catch (ReflectiveOperationException e) {
throw new RuntimeException(e);
}
......@@ -387,7 +444,7 @@ public class HudsonPrivateSecurityRealm extends AbstractPasswordBasedSecurityRea
user.save();
return user;
}
@Restricted(NoExternalUse.class)
public boolean isMailerPluginPresent() {
try {
......
......@@ -23,25 +23,23 @@
*/
package hudson.util;
import com.google.common.collect.*;
import edu.umd.cs.findbugs.annotations.CreatesObligation;
import hudson.Util;
import jenkins.util.io.LinesStream;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.Reader;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
/**
* Represents a text file.
......@@ -51,9 +49,10 @@ import java.util.Iterator;
* @author Kohsuke Kawaguchi
*/
public class TextFile {
public final File file;
public TextFile(File file) {
public final @Nonnull File file;
public TextFile(@Nonnull File file) {
this.file = file;
}
......@@ -82,36 +81,16 @@ public class TextFile {
}
/**
* Parse text file line by line.
* Creates a new {@link jenkins.util.io.LinesStream} of the file.
* <p>
* Note: The caller is responsible for closing the returned
* <code>LinesStream</code>.
* @throws IOException if the file cannot be converted to a
* {@link java.nio.file.Path} or if the file cannot be opened for reading
*/
public Iterable<String> lines() {
return new Iterable<String>() {
@Override
public Iterator<String> iterator() {
try {
final BufferedReader in = new BufferedReader(new InputStreamReader(
Files.newInputStream(file.toPath()),"UTF-8"));
return new AbstractIterator<String>() {
@Override
protected String computeNext() {
try {
String r = in.readLine();
if (r==null) {
in.close();
return endOfData();
}
return r;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
} catch (IOException | InvalidPathException e) {
throw new RuntimeException(e);
}
}
};
@CreatesObligation
public @Nonnull LinesStream lines() throws IOException {
return new LinesStream(Util.fileToPath(file));
}
/**
......
......@@ -39,6 +39,7 @@ import hudson.model.PageDecorator;
import hudson.model.UpdateCenter;
import hudson.model.UpdateSite;
import hudson.model.User;
import hudson.security.AccountCreationFailedException;
import hudson.security.FullControlOnceLoggedInAuthorizationStrategy;
import hudson.security.HudsonPrivateSecurityRealm;
import hudson.security.SecurityRealm;
......@@ -240,49 +241,54 @@ public class SetupWizard extends PageDecorator {
* Called during the initial setup to create an admin user
*/
@RequirePOST
public HttpResponse doCreateAdminUser(StaplerRequest req, StaplerResponse rsp) throws IOException, ServletException {
@Restricted(NoExternalUse.class)
public HttpResponse doCreateAdminUser(StaplerRequest req, StaplerResponse rsp) throws IOException {
Jenkins j = Jenkins.getInstance();
j.checkPermission(Jenkins.ADMINISTER);
// This will be set up by default. if not, something changed, ok to fail
HudsonPrivateSecurityRealm securityRealm = (HudsonPrivateSecurityRealm)j.getSecurityRealm();
HudsonPrivateSecurityRealm securityRealm = (HudsonPrivateSecurityRealm) j.getSecurityRealm();
User admin = securityRealm.getUser(SetupWizard.initialSetupAdminUserName);
try {
if(admin != null) {
if (admin != null) {
admin.delete(); // assume the new user may well be 'admin'
}
User u = securityRealm.createAccountByAdmin(req, rsp, "/jenkins/install/SetupWizard/setupWizardFirstUser.jelly", null);
if (u != null) {
if(admin != null) {
admin = null;
}
// Success! Delete the temporary password file:
try {
getInitialAdminPasswordFile().delete();
} catch (InterruptedException e) {
throw new IOException(e);
}
InstallUtil.proceedToNextStateFrom(InstallState.CREATE_ADMIN_USER);
// ... and then login
Authentication a = new UsernamePasswordAuthenticationToken(u.getId(),req.getParameter("password1"));
a = securityRealm.getSecurityComponents().manager.authenticate(a);
SecurityContextHolder.getContext().setAuthentication(a);
CrumbIssuer crumbIssuer = Jenkins.getInstance().getCrumbIssuer();
JSONObject data = new JSONObject();
if (crumbIssuer != null) {
data.accumulate("crumbRequestField", crumbIssuer.getCrumbRequestField()).accumulate("crumb", crumbIssuer.getCrumb(req));
}
return HttpResponses.okJSON(data);
} else {
return HttpResponses.okJSON();
User newUser = securityRealm.createAccountFromSetupWizard(req);
if (admin != null) {
admin = null;
}
// Success! Delete the temporary password file:
try {
getInitialAdminPasswordFile().delete();
} catch (InterruptedException e) {
throw new IOException(e);
}
InstallUtil.proceedToNextStateFrom(InstallState.CREATE_ADMIN_USER);
// ... and then login
Authentication auth = new UsernamePasswordAuthenticationToken(newUser.getId(), req.getParameter("password1"));
auth = securityRealm.getSecurityComponents().manager.authenticate(auth);
SecurityContextHolder.getContext().setAuthentication(auth);
CrumbIssuer crumbIssuer = Jenkins.getInstance().getCrumbIssuer();
JSONObject data = new JSONObject();
if (crumbIssuer != null) {
data.accumulate("crumbRequestField", crumbIssuer.getCrumbRequestField()).accumulate("crumb", crumbIssuer.getCrumb(req));
}
return HttpResponses.okJSON(data);
} catch (AccountCreationFailedException e) {
/*
Return Unprocessable Entity from WebDAV. While this is not technically in the HTTP/1.1 standard, browsers
seem to accept this. 400 Bad Request is technically inappropriate because that implies invalid *syntax*,
not incorrect data. The client only cares about it being >200 anyways.
*/
rsp.setStatus(422);
return HttpResponses.forwardToView(securityRealm, "/jenkins/install/SetupWizard/setupWizardFirstUser.jelly");
} finally {
if(admin != null) {
if (admin != null) {
admin.save(); // recreate this initial user if something failed
}
}
......
......@@ -3,6 +3,7 @@ package jenkins.security.s2m;
import hudson.CopyOnWrite;
import hudson.util.TextFile;
import jenkins.model.Jenkins;
import jenkins.util.io.LinesStream;
import java.io.BufferedReader;
import java.io.File;
......@@ -26,15 +27,42 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
protected abstract COL create();
protected abstract COL readOnly(COL base);
public synchronized void load() {
/**
* Loads the configuration from the configuration file.
* <p>
* This method is equivalent to {@link #load2()}, except that any
* {@link java.io.IOException} that occurs is wrapped as a
* {@link java.lang.RuntimeException}.
* <p>
* This method exists for source compatibility. Users should call
* {@link #load2()} instead.
* @deprecated use {@link #load2()} instead.
*/
@Deprecated
public void load() {
try {
load2();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Loads the configuration from the configuration file.
* @throws IOException if the configuration file could not be read.
* @since TODO
*/
public synchronized void load2() throws IOException {
COL result = create();
if (exists()) {
for (String line : lines()) {
if (line.startsWith("#")) continue; // comment
T r = parse(line);
if (r != null)
result.add(r);
try (LinesStream stream = lines()) {
for (String line : stream) {
if (line.startsWith("#")) continue; // comment
T r = parse(line);
if (r != null)
result.add(r);
}
}
}
......@@ -63,7 +91,7 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
Jenkins.getInstance().checkPermission(Jenkins.ADMINISTER);
write(newContent);
load();
load2();
}
public synchronized void append(String additional) throws IOException {
......@@ -79,8 +107,9 @@ abstract class ConfigFile<T,COL extends Collection<T>> extends TextFile {
// load upon the first use
if (parsed==null) {
synchronized (this) {
if (parsed==null)
if (parsed==null) {
load();
}
}
}
return parsed;
......
/*
* The MIT License
*
* Copyright 2018 Daniel Trebbien.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package jenkins.util.io;
import com.google.common.collect.AbstractIterator;
import edu.umd.cs.findbugs.annotations.CleanupObligation;
import edu.umd.cs.findbugs.annotations.DischargesObligation;
import java.io.BufferedReader;
import java.io.Closeable;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Iterator;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* Represents a stream over the lines of a text file.
* <p>
* Although <code>LinesStream</code> implements {@link java.lang.Iterable}, it
* is intended to be first used to initialize a resource in a try-with-resources
* statement and then iterated, as in:
* <pre>
* try (LinesStream stream = new LinesStream(...)) {
* for (String line : stream) {
* ...
* }
* }
* </pre>
* This pattern ensures that the underlying file handle is closed properly.
* <p>
* Like {@link java.nio.file.DirectoryStream}, <code>LinesStream</code> supports
* creating at most one <code>Iterator</code>. Invoking {@link #iterator()} to
* obtain a second or subsequent <code>Iterator</code> throws
* <code>IllegalStateException</code>.
*
* @since TODO
*/
@CleanupObligation
public class LinesStream implements Closeable, Iterable<String> {
private final @Nonnull BufferedReader in;
private transient @Nullable Iterator<String> iterator;
/**
* Opens the text file at <code>path</code> for reading using charset
* {@link java.nio.charset.StandardCharsets#UTF_8}.
* @param path Path to the file to open for reading.
* @throws IOException if the file at <code>path</code> cannot be opened for
* reading.
*/
public LinesStream(@Nonnull Path path) throws IOException {
in = Files.newBufferedReader(path); // uses UTF-8 by default
}
@DischargesObligation
@Override
public void close() throws IOException {
in.close();
}
@Override
public Iterator<String> iterator() {
if (iterator!=null)
throw new IllegalStateException("Only one Iterator can be created.");
iterator = new AbstractIterator<String>() {
@Override
protected String computeNext() {
try {
String r = in.readLine();
if (r==null) {
// Calling close() here helps ensure that the file
// handle is closed even when LinesStream is being used
// incorrectly, where it is iterated over without being
// used to initialize a resource of a try-with-resources
// statement.
in.close();
return endOfData();
}
return r;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
return iterator;
}
}
......@@ -28,7 +28,7 @@ THE SOFTWARE.
<parent>
<groupId>org.jenkins-ci</groupId>
<artifactId>jenkins</artifactId>
<version>1.39</version>
<version>1.40</version>
</parent>
<groupId>org.jenkins-ci.main</groupId>
......@@ -92,8 +92,6 @@ THE SOFTWARE.
<matrix-project.version>1.4.1</matrix-project.version>
<sorcerer.version>0.11</sorcerer.version>
<animal.sniffer.skip>${skipTests}</animal.sniffer.skip>
<findbugs-maven-plugin.version>3.0.4</findbugs-maven-plugin.version>
<findbugs.failOnError>true</findbugs.failOnError>
<access-modifier.version>1.13</access-modifier.version>
<access-modifier-annotation.version>${access-modifier.version}</access-modifier-annotation.version> <!-- differing only where needed for timestamped snapshots -->
<access-modifier-checker.version>${access-modifier.version}</access-modifier-checker.version>
......@@ -108,6 +106,9 @@ THE SOFTWARE.
<remoting.version>3.17</remoting.version>
<remoting.minimum.supported.version>2.60</remoting.minimum.supported.version>
<findbugs.effort>Max</findbugs.effort>
<findbugs.threshold>High</findbugs.threshold>
<findbugs.excludeFilterFile>../src/findbugs/findbugs-excludes.xml</findbugs.excludeFilterFile>
</properties>
<!-- Note that the 'repositories' and 'pluginRepositories' blocks below are actually copy-pasted
......@@ -492,28 +493,6 @@ THE SOFTWARE.
<artifactId>antlr-maven-plugin</artifactId>
<version>2.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>${findbugs-maven-plugin.version}</version>
<configuration>
<effort>Max</effort>
<threshold>High</threshold>
<!--Excludes file is located on the top level-->
<excludeFilterFile>../src/findbugs/findbugs-excludes.xml</excludeFilterFile>
<xmlOutput>true</xmlOutput>
<findbugsXmlOutput>false</findbugsXmlOutput>
</configuration>
<executions>
<execution>
<id>findbugs</id>
<goals>
<goal>check</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
......
......@@ -872,45 +872,37 @@ var createPluginSetupWizard = function(appendTarget) {
$c.slideDown();
}
};
var handleStaplerSubmit = function(data) {
if(data.status && data.status > 200) {
// Nothing we can really do here
setPanel(errorPanel, { errorMessage: data.statusText });
return;
}
try {
if(JSON.parse(data).status === 'ok') {
showStatePanel();
return;
}
} catch(e) {
// ignore JSON parsing issues, this may be HTML
var handleFirstUserResponseSuccess = function (data) {
if (data.status === 'ok') {
showStatePanel();
} else {
setPanel(errorPanel, {errorMessage: 'Error trying to create first user: ' + data.statusText});
}
// we get 200 OK
var responseText = data.responseText;
};
var handleFirstUserResponseError = function(res) {
// We're expecting a full HTML page to replace the form
// We can only replace the _whole_ iframe due to XSS rules
// https://stackoverflow.com/a/22913801/1117552
var responseText = res.responseText;
var $page = $(responseText);
var $errors = $page.find('.error');
if($errors.length > 0) {
var $main = $page.find('#main-panel').detach();
if($main.length > 0) {
responseText = responseText.replace(/body([^>]*)[>](.|[\r\n])+[<][/]body/,'body$1>'+$main.html()+'</body');
}
var doc = $('iframe[src]').contents()[0];
doc.open();
doc.write(responseText);
doc.close();
}
else {
showStatePanel();
var $main = $page.find('#main-panel').detach();
if($main.length > 0) {
responseText = responseText.replace(/body([^>]*)[>](.|[\r\n])+[<][/]body/,'body$1>'+$main.html()+'</body');
}
var doc = $('iframe#setup-first-user').contents()[0];
doc.open();
doc.write(responseText);
doc.close();
$('button').prop({disabled:false});
};
// call to submit the firstuser
var saveFirstUser = function() {
$('button').prop({disabled:true});
securityConfig.saveFirstUser($('iframe[src]').contents().find('form:not(.no-json)'), handleStaplerSubmit, handleStaplerSubmit);
var $form = $('iframe#setup-first-user').contents().find('form:not(.no-json)');
securityConfig.saveFirstUser($form, handleFirstUserResponseSuccess, handleFirstUserResponseError);
};
var skipFirstUser = function() {
......
......@@ -3,7 +3,7 @@
</div>
<div class="modal-body">
<div class="jumbotron welcome-panel security-panel">
<iframe src="{{baseUrl}}/setupWizard/setupWizardFirstUser"></iframe>
<iframe src="{{baseUrl}}/setupWizard/setupWizardFirstUser" id="setup-first-user"></iframe>
</div>
</div>
<div class="modal-footer">
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册