package com.geoxp.oss.servlet; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringReader; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.bouncycastle.util.encoders.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.geoxp.oss.CryptoHelper; import com.geoxp.oss.OSS; import com.geoxp.oss.OSSException; import com.google.inject.Singleton; @Singleton public class RemoveACLServlet extends HttpServlet { private static final Logger LOGGER = LoggerFactory.getLogger(RemoveACLServlet.class); @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (!OSS.isInitialized()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Open Secret Server not yet initialized."); return; } if (!OSS.hasSecureACLs()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Secure ACLs are not enabled."); return; } // // Extract token // String b64token = req.getParameter("token"); // // Decode it from base64 // byte[] token = Base64.decode(b64token); // // Extract wrapped init token and sealed AES key // byte[] wrappedtoken = CryptoHelper.decodeNetworkString(token, 0); byte[] sealedaeskey = CryptoHelper.decodeNetworkString(token, wrappedtoken.length + 4); // // Unseal AES key // byte[] aeskey = CryptoHelper.decryptRSA(OSS.getSessionRSAPrivateKey(), sealedaeskey); // // Unwrap init token // byte[] inittoken = CryptoHelper.unwrapAES(aeskey, wrappedtoken); // // Check OSS Token // OSS.OSSToken osstoken = null; try { osstoken = OSS.checkToken(inittoken); } catch (OSSException osse) { LOGGER.error("doPost", osse); resp.sendError(HttpServletResponse.SC_BAD_REQUEST, osse.getMessage()); return; } // // Check that ssh key can change ACLs // if (!OSS.checkACLSSHKey(osstoken.getKeyblob())) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "SSH Key is not allowed to access ACLs."); return; } // // Extract secretname and SSH key fingerprints // byte[] secretname = CryptoHelper.decodeNetworkString(osstoken.getSecret(), 0); Set<String> removefingerprints = new HashSet<String>(); int offset = secretname.length + 4; while (offset < osstoken.getSecret().length) { byte[] fpr = CryptoHelper.decodeNetworkString(osstoken.getSecret(), offset); offset += fpr.length + 4; String fingerprint = new String(fpr, "UTF-8").toLowerCase().replaceAll("[^a-f0-9]", ""); if (32 != fingerprint.length()) { resp.sendError(HttpServletResponse.SC_BAD_REQUEST, "Invalid fingerprint length."); return; } removefingerprints.add(fingerprint); } // // Read existing ACLs // File aclfile = null; try { aclfile = OSS.getKeyStore().getACLFile(new String(secretname, "UTF-8")); } catch (OSSException osse) { resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, osse.getMessage()); return; } Set<String> fingerprints = new HashSet<String>(); if (aclfile.exists()) { InputStream in = new FileInputStream(aclfile); byte[] buffer = new byte[1024]; ByteArrayOutputStream baos = new ByteArrayOutputStream(); while(true) { int len = in.read(buffer); if (len < 0) { break; } baos.write(buffer, 0, len); } in.close(); byte[] k = OSS.getMasterSecret(); String acls = new String(CryptoHelper.unwrapBlob(k, baos.toByteArray()), "UTF-8"); Arrays.fill(k, (byte) 0); BufferedReader br = new BufferedReader(new StringReader(acls)); while(true) { String line = br.readLine(); if (null == line) { break; } fingerprints.add(line); } br.close(); } // // Remove fingerprints // int oldsize = fingerprints.size(); for(String fingerprint: removefingerprints) { fingerprints.remove(fingerprint); } // // No fingerprints were removed, return immediately // if (oldsize == fingerprints.size()) { resp.setStatus(HttpServletResponse.SC_OK); return; } // // If the ACL is now empty, remove the ACL file // if (fingerprints.isEmpty() && aclfile.exists()) { aclfile.delete(); } else { // // Build new ACL list // StringBuilder sb = new StringBuilder(); for (String fingerprint: fingerprints) { sb.append(fingerprint.toLowerCase().replaceAll("[^0-9a-f]","")); sb.append("\n"); } // // Write ACL file // synchronized(OSS.getKeyStore()) { OutputStream os = new FileOutputStream(aclfile); os.write(CryptoHelper.wrapBlob(OSS.getMasterSecret(), sb.toString().getBytes("UTF-8"))); os.close(); } } resp.setStatus(HttpServletResponse.SC_OK); } }