/* (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.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
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.geoserver.security.GeoServerUserGroupService;
import org.geoserver.security.impl.GeoServerRole;
import org.geoserver.security.impl.GeoServerUser;
import org.geoserver.security.validation.PasswordPolicyException;
import org.geoserver.security.validation.UserGroupStoreValidationWrapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.core.context.SecurityContextHolder;
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;
@RestController
@RequestMapping(path = RestBaseController.ROOT_PATH + "/security/self/password")
public class UserPasswordController extends RestBaseController {
static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.rest");
static final String UP_NEW_PW = "newPassword";
static final String XML_ROOT_ELEM = "userPassword";
@GetMapping()
public void passwordGet() {
throw new RestException("You can not request the password!", HttpStatus.METHOD_NOT_ALLOWED);
}
@PutMapping(consumes = {
MediaType.APPLICATION_JSON_VALUE,
MediaType.APPLICATION_XML_VALUE,
MediaType.TEXT_XML_VALUE,
MediaTypeExtensions.TEXT_JSON_VALUE})
public void passwordPut(@RequestBody Map<String, String> putMap) {
if (!getManager().checkAuthenticationForRole(
SecurityContextHolder.getContext().getAuthentication(),
GeoServerRole.AUTHENTICATED_ROLE))
// yes, for backwards compat, it's really METHOD_NOT_ALLOWED
throw new RestException("Amdinistrative privelges required",
HttpStatus.METHOD_NOT_ALLOWED);
try {
// Look for the service that handles the current user
String userName = SecurityContextHolder.getContext().getAuthentication().getName();
GeoServerUserGroupService ugService = null;
for (GeoServerUserGroupService service : getManager().loadUserGroupServices()) {
if (service.getUserByUsername(userName) != null) {
ugService = service;
break;
}
}
if (ugService == null) {
throw new RestException("Cannot calculate if PUT is allowed (service not found)",
HttpStatus.UNPROCESSABLE_ENTITY);
}
} catch (IOException e) {
throw new RestException("Cannot calculate if PUT is allowed (" + e.getMessage() + ")",
HttpStatus.UNPROCESSABLE_ENTITY, e);
}
String newpass = putMap.get(UP_NEW_PW);
if (StringUtils.isBlank(newpass))
throw new RestException("Missing '" + UP_NEW_PW + "'", HttpStatus.BAD_REQUEST);
GeoServerUser user = null;
GeoServerUserGroupService ugService = null;
try {
// Look for the authentication service
String userName = SecurityContextHolder.getContext().getAuthentication().getName();
for (GeoServerUserGroupService service : getManager().loadUserGroupServices()) {
user = service.getUserByUsername(userName);
if (user != null) {
ugService = service;
break;
}
}
} catch (IOException e) {
throw new RestException("Cannot retrieve user service", HttpStatus.FAILED_DEPENDENCY,
e);
}
if (ugService == null) {
throw new RestException("User service not found", HttpStatus.FAILED_DEPENDENCY);
}
// Check again if the provider allows updates
if (!ugService.canCreateStore()) {
throw new RestException("User service does not support changing pw",
HttpStatus.FAILED_DEPENDENCY);
}
try {
UserGroupStoreValidationWrapper ugStore = new UserGroupStoreValidationWrapper(
ugService.createStore());
user.setPassword(newpass);
ugStore.updateUser(user);
ugStore.store();
ugService.load();
LOGGER.log(Level.INFO, "Changed password for user {0}", user.getUsername());
} catch (IOException e) {
throw new RestException("Internal IO error", HttpStatus.INTERNAL_SERVER_ERROR, e);
} catch (PasswordPolicyException e) {
throw new RestException("Bad password", HttpStatus.UNPROCESSABLE_ENTITY, e);
}
}
GeoServerSecurityManager getManager() {
return GeoServerExtensions.bean(GeoServerSecurityManager.class);
}
}