package jenkins.model;
import hudson.Extension;
import hudson.Util;
import hudson.XmlFile;
import hudson.util.FormValidation;
import hudson.util.XStream2;
import net.sf.json.JSONObject;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.servlet.ServletContext;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;
import java.util.logging.Logger;
import static hudson.Util.fixNull;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
/**
* Stores the location of Jenkins (e-mail address and the HTTP URL.)
*
* @author Kohsuke Kawaguchi
* @since 1.494
*/
@Extension @Symbol("location")
public class JenkinsLocationConfiguration extends GlobalConfiguration {
/**
* @deprecated replaced by {@link #jenkinsUrl}
*/
@Deprecated
private transient String hudsonUrl;
private String adminAddress;
private String jenkinsUrl;
// just to suppress warnings
private transient String charset,useSsl;
public static @CheckForNull JenkinsLocationConfiguration get() {
return GlobalConfiguration.all().get(JenkinsLocationConfiguration.class);
}
public JenkinsLocationConfiguration() {
load();
}
@Override
public synchronized void load() {
// for backward compatibility, if we don't have our own data yet, then
// load from Mailer.
XmlFile file = getConfigFile();
if(!file.exists()) {
XStream2 xs = new XStream2();
xs.addCompatibilityAlias("hudson.tasks.Mailer$DescriptorImpl",JenkinsLocationConfiguration.class);
file = new XmlFile(xs,new File(Jenkins.getInstance().getRootDir(),"hudson.tasks.Mailer.xml"));
if (file.exists()) {
try {
file.unmarshal(this);
if (jenkinsUrl==null)
jenkinsUrl = hudsonUrl;
} catch (IOException e) {
LOGGER.log(Level.WARNING, "Failed to load "+file, e);
}
}
} else {
super.load();
}
updateSecureSessionFlag();
}
/**
* Gets the service administrator e-mail address.
* @return Admin address or "address not configured" stub
*/
public @Nonnull String getAdminAddress() {
String v = adminAddress;
if(v==null) v = Messages.Mailer_Address_Not_Configured();
return v;
}
/**
* Sets the e-mail address of Jenkins administrator.
* @param adminAddress Admin address. Use null to reset the value to default.
*/
public void setAdminAddress(@CheckForNull String adminAddress) {
String address = Util.nullify(adminAddress);
if(address != null && address.startsWith("\"") && address.endsWith("\"")) {
// some users apparently quote the whole thing. Don't know why
// anyone does this, but it's a machine's job to forgive human mistake
address = address.substring(1,address.length()-1);
}
this.adminAddress = address;
save();
}
public @CheckForNull String getUrl() {
return jenkinsUrl;
}
public void setUrl(@CheckForNull String jenkinsUrl) {
String url = Util.nullify(jenkinsUrl);
if(url!=null && !url.endsWith("/"))
url += '/';
this.jenkinsUrl = url;
save();
updateSecureSessionFlag();
}
/**
* If the Jenkins URL starts from "https", force the secure session flag
*
* @see <a href="https://www.owasp.org/index.php/SecureFlag">discussion of this topic in OWASP</a>
*/
private void updateSecureSessionFlag() {
try {
ServletContext context = Jenkins.getInstance().servletContext;
Method m;
try {
m = context.getClass().getMethod("getSessionCookieConfig");
} catch (NoSuchMethodException x) { // 3.0+
LOGGER.log(Level.FINE, "Failed to set secure cookie flag", x);
return;
}
Object sessionCookieConfig = m.invoke(context);
Class scc = Class.forName("javax.servlet.SessionCookieConfig");
Method setSecure = scc.getMethod("setSecure", boolean.class);
boolean v = fixNull(jenkinsUrl).startsWith("https");
setSecure.invoke(sessionCookieConfig, v);
} catch (InvocationTargetException e) {
if (e.getTargetException() instanceof IllegalStateException) {
// servlet 3.0 spec seems to prohibit this from getting set at runtime,
// though Winstone is happy to accept i. see JENKINS-25019
return;
}
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
} catch (Exception e) {
LOGGER.log(Level.WARNING, "Failed to set secure cookie flag", e);
}
}
@Override
public boolean configure(StaplerRequest req, JSONObject json) throws FormException {
req.bindJSON(this,json);
return true;
}
/**
* Checks the URL in <tt>global.jelly</tt>
*/
public FormValidation doCheckUrl(@QueryParameter String value) {
if(value.startsWith("http://localhost"))
return FormValidation.warning(Messages.Mailer_Localhost_Error());
return FormValidation.ok();
}
public FormValidation doCheckAdminAddress(@QueryParameter String value) {
try {
new InternetAddress(value);
return FormValidation.ok();
} catch (AddressException e) {
return FormValidation.error(e.getMessage());
}
}
private static final Logger LOGGER = Logger.getLogger(JenkinsLocationConfiguration.class.getName());
}