package com.microsoftopentechnologies.intellij.ui.libraries; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.module.Module; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.ui.ValidationInfo; import com.intellij.openapi.vfs.VirtualFile; import com.microsoftopentechnologies.azurecommons.wacommonutil.CerPfxUtil; import com.microsoftopentechnologies.azuremanagementutil.util.Base64; import com.microsoftopentechnologies.intellij.AzurePlugin; import com.microsoftopentechnologies.intellij.actions.LibraryConfigurationAction; import com.microsoftopentechnologies.intellij.ui.AzureAbstractPanel; import com.microsoftopentechnologies.intellij.ui.util.UIUtils; import com.microsoftopentechnologies.intellij.util.PluginUtil; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.*; import java.security.cert.X509Certificate; import java.text.DateFormat; import java.text.SimpleDateFormat; import static com.microsoftopentechnologies.intellij.ui.messages.AzureBundle.message; class LibraryPropertiesPanel implements AzureAbstractPanel { private static final int BUFF_SIZE = 1024; private JPanel rootPanel; private JCheckBox depCheck; private JPanel acsFilterPanel; private JTextField acsTxt; private JTextField relTxt; private TextFieldWithBrowseButton certTxt; private JButton newCertBtn; private JTextPane certInfoTxt; private JCheckBox embedCertCheck; private JCheckBox requiresHttpsCheck; private JLabel libraryVersion; private JLabel location; private AzureLibrary azureLibrary; private Module module; public LibraryPropertiesPanel(Module module, AzureLibrary azureLibrary) { this.module = module; this.azureLibrary = azureLibrary; init(); } public void init() { acsTxt.setText(message("acsTxt")); certTxt.getTextField().getDocument().addDocumentListener(createCertTxtListener()); Messages.configureMessagePaneUi(certInfoTxt, message("embedCertDefTxt")); FileChooserDescriptor fileChooserDescriptor = new FileChooserDescriptor(true, false, false, false, false, false) { @Override public boolean isFileVisible(VirtualFile file, boolean showHiddenFiles) { return file.isDirectory() || (file.getExtension() != null && (file.getExtension().equals("cer") || file.getExtension().equals(".CER"))); } @Override public boolean isFileSelectable(VirtualFile file) { return (file.getExtension() != null && (file.getExtension().equals("cer") || file.getExtension().equals(".CER"))); } }; fileChooserDescriptor.setTitle("Select Certificate"); // FileChooser.chooseFile(fileChooserDescriptor, null, null); certTxt.addActionListener(UIUtils.createFileChooserListener(certTxt, null, fileChooserDescriptor)); requiresHttpsCheck.addActionListener(createRequiredHttpsCheckListener()); } private DocumentListener createCertTxtListener() { return new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { handleUpdate(); } @Override public void removeUpdate(DocumentEvent e) { handleUpdate(); } @Override public void changedUpdate(DocumentEvent e) { handleUpdate(); } private void handleUpdate() { String certInfo = getCertInfo(certTxt.getText()); if (certInfo != null) certInfoTxt.setText(certInfo); else certInfoTxt.setText(""); } }; } private ActionListener createRequiredHttpsCheckListener() { return new ActionListener() { @Override public void actionPerformed(ActionEvent e) { if (requiresHttpsCheck.isSelected()) { //Do nothing } else { int choice = Messages.showYesNoDialog(message("requiresHttpsDlgMsg"), message("requiresHttpsDlgTitle"), Messages.getQuestionIcon()); if (choice == Messages.NO) { requiresHttpsCheck.setSelected(true); } } } }; } public JComponent prepare() { acsFilterPanel.setVisible(azureLibrary == LibraryConfigurationAction.ACS_FILTER); libraryVersion.setText(azureLibrary.getName()); location.setText((String.format("%s%s%s", AzurePlugin.pluginFolder, File.separator, azureLibrary.getLocation()))); rootPanel.revalidate(); return rootPanel; } public boolean onFinish() { if (azureLibrary == LibraryConfigurationAction.ACS_FILTER) { if (doValidate() != null) { return false; } configureDeployment(); } return true; } @Override public JComponent getPanel() { return prepare(); } @Override public String getDisplayName() { return null; } @Override public boolean doOKAction() { return false; } @Override public String getSelectedValue() { return null; } public boolean isExported() { return depCheck.isSelected(); } public ValidationInfo doValidate() { boolean isEdit = isEdit(); StringBuilder errorMessage = new StringBuilder(); // Display error if acs login page URL is null. Applicable for first time and edit scenarios. if(acsTxt.getText().isEmpty() || acsTxt.getText().equalsIgnoreCase(message("acsTxt"))) errorMessage.append(message("acsTxtErr")).append("\n"); // Display error if relying part realm is null. Applicable for first time and edit scenarios. if(relTxt.getText().isEmpty()) errorMessage.append(message("relTxtErr")).append("\n"); // if certificate location does not end with .cer then display error if(!certTxt.getText().isEmpty() && !certTxt.getText().toLowerCase().endsWith(".cer")) errorMessage.append(message("certTxtInvalidExt")).append("\n"); // Display error if cert location is empty for first time and for edit scenarios if // embedded cert option is not selected if((!isEdit && certTxt.getText().isEmpty()) || (isEdit && certTxt.getText().isEmpty() && !embedCertCheck.isSelected())) errorMessage.append(message("certTxtErr")).append("\n"); // For first time , if embedded cert option is selected , display error if file does not exist at source if (!isEdit && !certTxt.getText().isEmpty() && embedCertCheck.isSelected() == true) { if(!new File(CerPfxUtil.getCertificatePath(certTxt.getText())).exists()) { errorMessage.append(message("acsNoValidCert")).append("\n"); } } if (errorMessage.length() > 0) { return new ValidationInfo(errorMessage.toString()); } else { return null; } } @Override public String getHelpTopic() { return null; } /** * Method generates key using * Advanced Encryption Standard algorithm. * * @return String * @throws Exception */ private String generateKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance("AES"); keyGenerator.init(128); SecretKey secretKey = keyGenerator.generateKey(); byte[] keyInBytes = secretKey.getEncoded(); String key = Base64.encode(keyInBytes); return key; } /** * Method creates web.xml (deployment descriptor) * in WebContent\WEB-INF folder of dynamic web project * if does not present already. * * @return String */ private String createWebXml() { String path = null; try { File cmpntFileLoc = new File(String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("depDirLoc"))); String cmpntFile = String.format("%s%s%s", cmpntFileLoc, File.separator, message("depFileName")); if (!cmpntFileLoc.exists()) { cmpntFileLoc.mkdirs(); } AzurePlugin.copyResourceFile(message("resFileLoc"), cmpntFile); path = cmpntFile; } catch (Exception e) { PluginUtil.displayErrorDialogAndLog(message("acsErrTtl"), message("fileCrtErrMsg"), e); } return new File(path).getPath(); } private String getEmbeddedCertInfo() { String webinfLoc = String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("depDirLoc")); String certLoc = String.format("%s%s%s", webinfLoc, File.separator, message("acsCertLoc")); return getCertInfo(certLoc); } public static void copy(File source, final File destination) throws IOException { InputStream instream = null; if (source.isDirectory()) { if (!destination.exists()) { destination.mkdirs(); } String[] kid = source.list(); for (int i = 0; i < kid.length; i++) { copy(new File(source, kid[i]), new File(destination, kid[i])); } } else { //InputStream instream = null; OutputStream out = null; try { if (destination != null && destination.isFile() && !destination.getParentFile().exists()) destination.getParentFile().mkdirs(); instream = new FileInputStream(source); out = new FileOutputStream(destination); byte[] buf = new byte[BUFF_SIZE]; int len = instream.read(buf); while (len > 0) { out.write(buf, 0, len); len = instream.read(buf); } } finally { if (instream != null) { instream.close(); } if (out != null) { out.close(); } } } } public void removeEmbedCert() { String webinfLoc = String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("depDirLoc")); String certLoc = String.format("%s%s%s", webinfLoc, File.separator, message("acsCertLoc")); File destination = new File(certLoc); if (destination.exists()) destination.delete(); if (destination.getParentFile().exists() && destination.getParentFile().list().length == 0) destination.getParentFile().delete(); } private static String getCertInfo(String certURL) { X509Certificate acsCert = CerPfxUtil.getCert(certURL, null); if (acsCert != null) { DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); StringBuilder certInfo = new StringBuilder(); certInfo.append(String.format("%1$-10s", "Subject")).append(" : ").append(acsCert.getSubjectDN()).append("\n"); certInfo.append(String.format("%1$-11s", "Issuer")).append(" : ").append(acsCert.getIssuerDN()).append("\n"); certInfo.append(String.format("%1$-13s", "Valid")).append(" : ").append(dateFormat.format(acsCert.getNotBefore())). append(" to ").append(dateFormat.format(acsCert.getNotAfter())); return certInfo.toString(); } else { return null; } } /** * Method adds ACS filter and filter mapping tags in web.xml * and saves input values given on ACS library page. * In case of edit, populates previously set values. */ private void configureDeployment() { //edit library // if (isEdit()) { // IJavaProject proj1 = JavaCore.create(ACSFilterUtil.getSelectedProject()); // IClasspathEntry[] entries; // try { // entries = proj1.getRawClasspath(); // IClasspathEntry[] newentries = // new IClasspathEntry[entries.length]; // // for (int i = 0; i < entries.length; i++) { // if (entries[i].toString().contains(Messages.sdkContainer)) { // if (depCheck.getSelection()) { // IClasspathAttribute[] attr = // new IClasspathAttribute[1]; // attr[0] = JavaCore.newClasspathAttribute( // Messages.jstDep, // "/WEB-INF/lib"); // newentries[i] = JavaCore.newContainerEntry(entry, // null, attr, true); // } else { // newentries[i] = JavaCore.newContainerEntry(entry); // } // } else { // newentries[i] = entries[i]; // } // } // proj1.setRawClasspath(newentries, null); // } catch (Exception e) { // Activator.getDefault().log(e.getMessage(), e); // } // } ACSFilterHandler handler = null; try { String xmlPath = String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("xmlPath")); // if (proj.getFile(message("xmlPath")).exists()) { File webXml = new File(xmlPath); if (webXml.exists()) { handler = new ACSFilterHandler(xmlPath); handler.setAcsFilterParams(message("acsAttr"), acsTxt.getText()); handler.setAcsFilterParams(message("relAttr"), relTxt.getText()); if (!embedCertCheck.isSelected()) { handler.setAcsFilterParams(message("certAttr"), certTxt.getText()); if (getEmbeddedCertInfo() != null) removeEmbedCert(); } else { handler.removeParamsIfExists(message("certAttr")); if (!certTxt.getText().isEmpty()) { String webinfLoc = String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("depDirLoc")); String certLoc = String.format("%s%s%s", webinfLoc, File.separator, message("acsCertLoc")); File destination = new File(certLoc); if (!destination.getParentFile().exists()) destination.getParentFile().mkdir(); copy(new File(CerPfxUtil.getCertificatePath(certTxt.getText())), destination); } } handler.setAcsFilterParams(message("secretKeyAttr"), generateKey()); handler.setAcsFilterParams(message("allowHTTPAttr"), requiresHttpsCheck.isSelected() ? "false" : "true"); } else { int choice = Messages.showYesNoDialog(message("depDescMsg"), message("depDescTtl"), Messages.getQuestionIcon()); if (choice == Messages.YES) { String path = createWebXml(); //copy cert into WEB-INF/cert/_acs_signing.cer location if embed cert is selected if (embedCertCheck.isSelected()) { String webinfLoc = String.format("%s%s%s", PluginUtil.getModulePath(module), File.separator, message("depDirLoc")); String certLoc = String.format("%s%s%s", webinfLoc, File.separator, message("acsCertLoc")); File destination = new File(certLoc); if (!destination.getParentFile().exists()) destination.getParentFile().mkdir(); copy(new File(CerPfxUtil.getCertificatePath(certTxt.getText())), destination); } handler = new ACSFilterHandler(path); handler.setAcsFilterParams(message("acsAttr"), acsTxt.getText()); handler.setAcsFilterParams(message("relAttr"), relTxt.getText()); if (!embedCertCheck.isSelected()) { //Donot make entry if embed cert is selected handler.setAcsFilterParams(message("certAttr"), certTxt.getText()); if (getEmbeddedCertInfo() != null) removeEmbedCert(); } handler.setAcsFilterParams(message("secretKeyAttr"), generateKey()); handler.setAcsFilterParams(message("allowHTTPAttr"), requiresHttpsCheck.isSelected() ? "false" : "true"); } else { // finishVal = true; return; } } } catch (Exception e) { PluginUtil.displayErrorDialogAndLog(message("acsErrTtl"), message("acsErrMsg"), e); // finishVal = false; } try { handler.save(); } catch (Exception e) { PluginUtil.displayErrorDialogAndLog(message("acsErrTtl"), message("saveErrMsg"), e); // finishVal = false; } } /** * @return current window is edit or not */ private boolean isEdit() { return false; } public String getHelpId() { return "acs_config_dialog"; } }