/* * Copyright 2015 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.server.controller; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.exceptions.ConfigFileHasChangedException; import com.thoughtworks.go.config.validation.GoConfigValidity; import com.thoughtworks.go.domain.GoConfigRevision; import com.thoughtworks.go.server.controller.actions.JsonAction; import com.thoughtworks.go.server.controller.actions.RestfulAction; import com.thoughtworks.go.server.controller.actions.XmlAction; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.service.GoConfigService; import com.thoughtworks.go.server.service.SecurityService; import com.thoughtworks.go.server.util.UserHelper; import com.thoughtworks.go.server.web.JsonView; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletResponse; import java.util.LinkedHashMap; import java.util.Map; import static com.thoughtworks.go.server.controller.actions.JsonAction.jsonByValidity; @Controller public class GoConfigAdministrationController { private GoConfigService goConfigService; private SecurityService securityService; private static final org.apache.commons.logging.Log LOGGER = LogFactory.getLog(GoConfigAdministrationController.class); public GoConfigAdministrationController() { } @Autowired GoConfigAdministrationController(GoConfigService goConfigService, SecurityService securityService) { this.goConfigService = goConfigService; this.securityService = securityService; } @RequestMapping("/admin/restful/configuration/file/GET/xml") public void getCurrentConfigXml(@RequestParam(value = "md5", required = false) String md5, HttpServletResponse response) throws Exception { getXmlPartial(null, md5, goConfigService.fileSaver(false)).respond(response); } @RequestMapping("/admin/restful/configuration/file/GET/historical-xml") public void getConfigRevision(@RequestParam(value = "version", required = true) String version, HttpServletResponse response) throws Exception { GoConfigRevision configRevision = goConfigService.getConfigAtVersion(version); String md5 = configRevision.getMd5(); XmlAction.xmlFound(configRevision.getContent(), md5).respond(response); } private RestfulAction getXmlPartial(String groupName, String oldMd5, GoConfigService.XmlPartialSaver xmlPartialSaver) { if (!isTemplate(groupName) && !isCurrentUserAdminOfGroup(groupName)) { return XmlAction.xmlUnAuthorized(errorMessageForGroup(groupName)); } if (isTemplate(groupName) && !isCurrentUserAdmin()) { return XmlAction.xmlUnAuthorized(errorMessageForTemplates()); } String xml; try { xml = xmlPartialSaver.asXml(); } catch (Exception e) { return XmlAction.xmlNotFound(e.getMessage()); } String newMd5 = xmlPartialSaver.getMd5(); if (oldMd5 != null && !oldMd5.equals(newMd5)) { return XmlAction.xmlMd5Conflict(ConfigFileHasChangedException.CONFIG_CHANGED_PLEASE_REFRESH, newMd5); } return XmlAction.xmlFound(xml, newMd5); } private boolean isTemplate(String groupName) { return TemplatesConfig.PIPELINE_TEMPLATES_FAKE_GROUP_NAME.equals(groupName); } private String errorMessageForTemplates() { return String.format("User '%s' does not have permission to administer pipeline templates", getCurrentUsername()); } private String errorMessageForGroup(String groupName) { return String.format("User '%s' does not have permissions to administer pipeline group '%s'", getCurrentUsername(), groupName); } @RequestMapping("/admin/restful/configuration/file/POST/xml") public ModelAndView postFileAsXml(@RequestParam("xmlFile")String xmlFile, @RequestParam("md5")String md5, HttpServletResponse response) throws Exception { if (!isCurrentUserAdmin()) { return JsonAction.jsonUnauthorized().respond(response); } return postXmlPartial(null, goConfigService.fileSaver(false), xmlFile, "File changed successfully.", md5).respond(response); } private RestfulAction postXmlPartial(String groupName, GoConfigService.XmlPartialSaver xmlPartialSaver, String xmlPartial, String successMessage, String expectedMd5) { if (!isTemplate(groupName) && !isCurrentUserAdminOfGroup(groupName)) { return JsonAction.jsonUnauthorized(errorMessageForGroup(groupName)); } if (isTemplate(groupName) && !isCurrentUserAdmin()) { return JsonAction.jsonUnauthorized(); } GoConfigValidity configValidity = xmlPartialSaver.saveXml(xmlPartial, expectedMd5); if (configValidity.isValid()) { return JsonAction.jsonFound(JsonView.getSimpleAjaxResult("result", successMessage)); } else { Map<String, Object> jsonMap = new LinkedHashMap<>(); jsonMap.put("result", configValidity.errorMessage()); jsonMap.put("originalContent", xmlPartial); return jsonByValidity(jsonMap, configValidity); } } private boolean isCurrentUserAdmin() { return securityService.isUserAdmin(getCurrentUser()); } private boolean isCurrentUserAdminOfGroup(String groupName) { return securityService.isUserAdminOfGroup(getCurrentUsername(), groupName); } private CaseInsensitiveString getCurrentUsername() { return getCurrentUser().getUsername(); } private Username getCurrentUser() { return UserHelper.getUserName(); } }