/* (c) 2017 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.rest.security;
import java.io.IOException;
import java.util.Map;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.geoserver.rest.catalog.NamedMap;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.rest.RestBaseController;
import org.geoserver.rest.RestException;
import org.geoserver.rest.util.MediaTypeExtensions;
import org.geoserver.security.GeoServerSecurityManager;
import org.geotools.util.logging.Logging;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* Master password controller
*/
@RestController
@RequestMapping(path = RestBaseController.ROOT_PATH + "/security/masterpw")
public class MasterPasswordController extends RestBaseController {
private static final Logger LOGGER = Logging.getLogger(MasterPasswordController.class);
static final String MP_CURRENT_KEY = "oldMasterPassword";
static final String MP_NEW_KEY = "newMasterPassword";
static final String XML_ROOT_ELEM = "masterPassword";
GeoServerSecurityManager getManager() {
return GeoServerExtensions.bean(GeoServerSecurityManager.class);
}
@GetMapping(produces = {
MediaType.APPLICATION_JSON_VALUE,
MediaTypeExtensions.TEXT_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE,
MediaType.TEXT_XML_VALUE })
public NamedMap<String, String> masterPasswordGet() throws IOException {
if (!getManager().checkAuthenticationForAdminRole()) {
throw new RestException("Amdinistrative privelges required", HttpStatus.FORBIDDEN);
}
char[] masterpw = getManager().getMasterPasswordForREST();
NamedMap<String, String> m = new NamedMap<>(XML_ROOT_ELEM);
m.put(MP_CURRENT_KEY, new String(masterpw));
getManager().disposePassword(masterpw);
return m;
}
@PutMapping(consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaTypeExtensions.TEXT_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE,
MediaType.TEXT_XML_VALUE })
public void masterPasswordPut(@RequestBody Map<String, String> putMap) throws IOException {
if (!getManager().checkAuthenticationForAdminRole()) {
// yes, for backwards compat, it's really METHOD_NOT_ALLOWED
throw new RestException("Amdinistrative privelges required",
HttpStatus.METHOD_NOT_ALLOWED);
}
String providerName;
try {
providerName = getManager().loadMasterPasswordConfig().getProviderName();
if (getManager().loadMasterPassswordProviderConfig(providerName).isReadOnly()) {
throw new RestException("Master password provider does not allow writes",
HttpStatus.METHOD_NOT_ALLOWED);
}
} catch (IOException e) {
throw new RestException("Master password provider does not allow writes",
HttpStatus.METHOD_NOT_ALLOWED);
}
String current = putMap.get(MP_CURRENT_KEY);
String newpass = putMap.get(MP_NEW_KEY);
if (!StringUtils.isNotBlank(current))
throw new RestException("no master password", HttpStatus.BAD_REQUEST);
if (!StringUtils.isNotBlank(newpass))
throw new RestException("no master password", HttpStatus.BAD_REQUEST);
char[] currentArray = current.trim().toCharArray();
char[] newpassArray = newpass.trim().toCharArray();
GeoServerSecurityManager m = getManager();
try {
m.saveMasterPasswordConfig(m.loadMasterPasswordConfig(), currentArray, newpassArray,
newpassArray);
} catch (Exception e) {
throw new RestException("Cannot change master password",
HttpStatus.UNPROCESSABLE_ENTITY, e);
} finally {
m.disposePassword(currentArray);
m.disposePassword(newpassArray);
}
}
}