Java tutorial
/** * Copyright (c) 2012 Aon eSolutions * * 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 org.aon.esolutions.appconfig.web.controller; import java.io.IOException; import java.security.Key; import java.security.KeyPair; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import org.aon.esolutions.appconfig.client.util.RSAEncryptUtil; import org.aon.esolutions.appconfig.model.Application; import org.aon.esolutions.appconfig.model.Environment; import org.aon.esolutions.appconfig.model.PrivateKeyHolder; import org.aon.esolutions.appconfig.repository.ApplicationRepository; import org.aon.esolutions.appconfig.repository.EnvironmentRepository; import org.aon.esolutions.appconfig.repository.PrivateKeyRepository; import org.aon.esolutions.appconfig.util.AvailableUsersAndRolesProvider; import org.aon.esolutions.appconfig.util.InheritanceUtil; import org.aon.esolutions.appconfig.util.UpdateUtility; import org.aon.esolutions.appconfig.util.XmlImporter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.neo4j.support.Neo4jTemplate; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.acls.model.AlreadyExistsException; import org.springframework.security.acls.model.NotFoundException; import org.springframework.stereotype.Controller; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.multipart.MultipartFile; import com.crygier.spring.util.web.MimeTypeViewResolver.ResponseMapping; @Controller @RequestMapping("/application/{applicationName}/environment") public class EnvironmentController { public static final Log logger = LogFactory.getLog(EnvironmentController.class); @Autowired private ApplicationRepository applicationRepository; @Autowired private EnvironmentRepository environmentRepository; @Autowired private PrivateKeyRepository privateKeyRepository; @Autowired private UpdateUtility updateUtility; @Autowired private InheritanceUtil inheritanceUtil; @Autowired private Neo4jTemplate template; @Autowired(required = false) private AvailableUsersAndRolesProvider usersAndRolesProvider; @RequestMapping(value = "/", method = RequestMethod.GET) @ResponseMapping("environmentDetails") public Set<Environment> getAllEnvironments(@PathVariable String applicationName) { return environmentRepository.getAllEnvironmentsForApplication(applicationName); } @RequestMapping(value = "/{environmentName}", method = RequestMethod.GET) @ResponseMapping("environmentDetails") public Environment getEnvironment(@PathVariable String applicationName, @PathVariable String environmentName) { Environment env = environmentRepository.getEnvironment(applicationName, environmentName); if (env == null) throw new NotFoundException("Can not find envioronment"); populatePrivateKey(env); RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); if (attributes != null) { attributes.setAttribute("allVariables", inheritanceUtil.getVariablesForEnvironment(env), RequestAttributes.SCOPE_REQUEST); if (usersAndRolesProvider != null) { attributes.setAttribute("availableUsers", usersAndRolesProvider.getAvailableUsers(), RequestAttributes.SCOPE_REQUEST); attributes.setAttribute("availableRoles", usersAndRolesProvider.getAvailableRoles(), RequestAttributes.SCOPE_REQUEST); } } return env; } @RequestMapping(value = "/{environmentName}", method = RequestMethod.POST) public Environment updateEnvironmentDetails(@PathVariable String applicationName, @PathVariable String environmentName, Environment updatedEnv) { Environment readEnv = updateUtility.getEnvironmentForWrite(applicationName, environmentName); readEnv.setName(updatedEnv.getName()); readEnv.setPermittedUsers(updatedEnv.getPermittedUsers()); readEnv.setPermittedRoles(updatedEnv.getPermittedRoles()); readEnv.setPermittedMachines(updatedEnv.getPermittedMachines()); readEnv.setVisibleToAll(updatedEnv.getVisibleToAll()); return updateUtility.saveEnvironment(readEnv); } @Transactional @RequestMapping(value = "/{environmentName}", method = RequestMethod.PUT) public Environment addEnvironment(@PathVariable String applicationName, @PathVariable String environmentName, @RequestParam("parentId") String parentId) throws Exception { try { getEnvironment(applicationName, environmentName); throw new AlreadyExistsException( "Environment " + environmentName + " already exists for Application " + applicationName); } catch (NotFoundException e) { // Good, it doesn't exist....lets go add one. } Application app = applicationRepository.findByName(applicationName); Environment parent = null; if (parentId != null) parent = environmentRepository.findOne(Long.parseLong(parentId)); Environment newEnv = new Environment(); newEnv.setName(environmentName); newEnv.setParent(parent); app.addEnvironment(newEnv); updateKeys(newEnv); newEnv = environmentRepository.save(newEnv); return newEnv; } @Transactional @RequestMapping(value = "/{environmentName}", method = RequestMethod.DELETE) public void deleteEnvironment(@PathVariable String applicationName, @PathVariable String environmentName) { Environment readEnv = updateUtility.getEnvironmentForWrite(applicationName, environmentName); if (readEnv.getChildren().isEmpty() == false) { template.fetch(readEnv.getChildren().iterator().next()); throw new IllegalStateException("Environment " + readEnv.getChildren().iterator().next().getName() + " is extending " + readEnv.getName() + ". Cannot delete " + readEnv.getName() + "."); } privateKeyRepository.delete(readEnv.getPrivateKeyHolder()); environmentRepository.delete(readEnv); } @Transactional @RequestMapping(value = "/{environmentName}/keys", method = RequestMethod.POST) public Map<String, String> updateKeys(@PathVariable String applicationName, @PathVariable String environmentName) throws Exception { Environment env = getEnvironment(applicationName, environmentName); Map<String, String> answer = updateKeys(env); environmentRepository.save(env); return answer; } @RequestMapping(value = "/{environmentName}/keys", method = RequestMethod.GET) public Map<String, String> getKeys(@PathVariable String applicationName, @PathVariable String environmentName) throws Exception { Environment env = getEnvironment(applicationName, environmentName); Map<String, String> answer = new HashMap<String, String>(); answer.put("public", env.getPublicKey()); answer.put("private", env.getPrivateKeyHolder().getPrivateKey()); return answer; } private Map<String, String> updateKeys(Environment env) throws Exception { Map<String, String> answer = new HashMap<String, String>(); if (env != null) { // First, get private key - Performs ACL Checking PrivateKeyHolder holder = null; if (env.getPrivateKeyHolder() != null) holder = privateKeyRepository.findOne(env.getPrivateKeyHolder().getId()); if (holder != null) { Key key = RSAEncryptUtil.getPrivateKeyFromString(holder.getPrivateKey()); for (String encryptedVariable : env.getEncryptedVariables()) { String encryptedValue = env.get(encryptedVariable); if (encryptedValue != null) { String decryptedValue = RSAEncryptUtil.decrypt(encryptedValue, key); env.put(encryptedVariable, decryptedValue); } } } else { holder = new PrivateKeyHolder(); env.setPrivateKeyHolder(holder); holder.setEnvironment(env); } // Generate the new keys KeyPair keyPair = RSAEncryptUtil.generateKey(); env.setPublicKey(RSAEncryptUtil.getKeyAsString(keyPair.getPublic())); holder.setPrivateKey(RSAEncryptUtil.getKeyAsString(keyPair.getPrivate())); // Re-encrypt with the new values for (String encryptedVariable : env.getEncryptedVariables()) { String decryptedValue = env.get(encryptedVariable); if (decryptedValue != null) { String encryptedValue = RSAEncryptUtil.encrypt(decryptedValue, keyPair.getPublic()); env.put(encryptedVariable, encryptedValue); } } updateUtility.savePrivateKeyHolder(holder); answer.put("publicKey", env.getPublicKey()); answer.put("privateKey", holder.getPrivateKey()); } return answer; } @Transactional @RequestMapping(value = "/{environmentName}/variable/{existingKey:.*}", method = RequestMethod.POST) public void updateVariable(@PathVariable String applicationName, @PathVariable String environmentName, @PathVariable String existingKey, @RequestParam("key") String updatedKey, @RequestParam("value") String updatedValue) { Environment env = getEnvironment(applicationName, environmentName); if (env != null) { env.remove(existingKey); env.put(updatedKey.trim(), updatedValue); env.getEncryptedVariables().remove(existingKey); environmentRepository.save(env); } } @Transactional @RequestMapping(value = "/{environmentName}/variable/{existingKey}/encrypt", method = RequestMethod.POST) public Map<String, String> encryptVariable(@PathVariable String applicationName, @PathVariable String environmentName, @PathVariable String existingKey) throws Exception { Environment env = getEnvironment(applicationName, environmentName); if (env != null) { String existingValue = env.get(existingKey); Key key = RSAEncryptUtil.getPublicKeyFromString(env.getPublicKey()); String encryptedValue = RSAEncryptUtil.encrypt(existingValue, key); env.put(existingKey, encryptedValue); env.addEncryptedVariable(existingKey); environmentRepository.save(env); Map<String, String> answer = new HashMap<String, String>(); answer.put("encryptedValue", encryptedValue); return answer; } return null; } @Transactional @RequestMapping(value = "/{environmentName}/variable/{existingKey}/decrypt", method = RequestMethod.POST) public Map<String, String> decryptVariable(@PathVariable String applicationName, @PathVariable String environmentName, @PathVariable String existingKey) throws Exception { Environment env = getEnvironment(applicationName, environmentName); if (env != null) { PrivateKeyHolder holder = privateKeyRepository.findOne(env.getPrivateKeyHolder().getId()); String existingValue = env.get(existingKey); Key key = RSAEncryptUtil.getPrivateKeyFromString(holder.getPrivateKey()); String decryptedValue = RSAEncryptUtil.decrypt(existingValue, key); env.put(existingKey, decryptedValue); env.getEncryptedVariables().remove(existingKey); if (env.getEncryptedVariables().isEmpty()) env.addEncryptedVariable("____dummy_key_bug_work_around___"); // bug workaround environmentRepository.save(env); Map<String, String> answer = new HashMap<String, String>(); answer.put("decryptedValue", decryptedValue); return answer; } return null; } @Transactional @RequestMapping(value = "/{environmentName}/variable/{existingKey:.*}", method = RequestMethod.DELETE) public void deleteVariable(@PathVariable String applicationName, @PathVariable String environmentName, @PathVariable String existingKey) { Environment env = getEnvironment(applicationName, environmentName); if (env != null) { env.remove(existingKey); env.getEncryptedVariables().remove(existingKey); environmentRepository.save(env); } } @Transactional @RequestMapping(value = "/{environmentName}/import", method = RequestMethod.POST) public void importProperties(@PathVariable String applicationName, @PathVariable String environmentName, @RequestParam(value = "file") MultipartFile multipartFile, @RequestParam(value = "importMode") String importMode) { if (multipartFile.getName().endsWith(".xml") || multipartFile.getOriginalFilename().endsWith(".xml")) { new XmlImporter(applicationRepository, environmentRepository, updateUtility) .importFromXml(multipartFile, importMode); return; } Environment env = updateUtility.getEnvironmentForWrite(applicationName, environmentName); if (env != null) { Properties props = new Properties(); try { props.load(multipartFile.getInputStream()); } catch (IOException e) { logger.error("Error importing properties", e); throw new IllegalArgumentException("Uploaded file does not look like a properties file"); } if ("full".equals(importMode)) { env.clearVariables(); } else if ("newOnly".equals(importMode)) { for (Entry<String, String> entry : env.getVariableEntries()) { props.remove(entry.getKey()); } } for (Object key : props.keySet()) { env.put((String) key, props.getProperty((String) key)); env.getEncryptedVariables().remove((String) key); } updateUtility.saveEnvironment(env); } } private void populatePrivateKey(Environment env) { try { PrivateKeyHolder holder = privateKeyRepository.findOne(env.getPrivateKeyHolder().getId()); env.setPrivateKeyHolder(holder); } catch (AccessDeniedException e) { // This is okay, they just can't see partial data } } }