/* * Copyright 2013 Hewlett-Packard Development Company, L.P * * 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 com.hp.alm.ali.idea.action.attachment; import com.hp.alm.ali.idea.cfg.AliProjectConfiguration; import com.hp.alm.ali.idea.cfg.AlmRememberedInputs; import com.hp.alm.ali.idea.entity.EntityRef; import com.hp.alm.ali.rest.client.AliRestClient; import com.hp.alm.ali.rest.client.RestClient; import com.hp.alm.ali.rest.client.ResultInfo; import com.hp.alm.ali.rest.client.exception.AuthenticationFailureException; import com.intellij.ide.passwordSafe.MasterPasswordUnavailableException; import com.intellij.ide.passwordSafe.PasswordSafe; import com.intellij.ide.passwordSafe.PasswordSafeException; import com.intellij.ide.passwordSafe.impl.PasswordSafeImpl; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ModalityState; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Ref; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.AuthData; import com.intellij.vcsUtil.AuthDialog; import org.apache.commons.io.FileUtils; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.regex.Matcher; import java.util.regex.Pattern; public class AttachmentAgmLinkDownloadTask extends AttachmentDownloadTask { private static Logger logger = Logger.getInstance(AttachmentAgmLinkDownloadTask.class); private static Pattern pattern = Pattern.compile("(https?://[^/]+/qcbin)/rest/domains/([^/]+)/projects/([^/]+)/(.*)"); private Project project; private String username; private File targetFile; private final Runnable onFinished; public AttachmentAgmLinkDownloadTask(Project project, File file, String sourceFilename, int size, EntityRef entity, Runnable onFinished) { super(project, createTempFile(), sourceFilename, size, entity, null); this.project = project; this.targetFile = file; this.onFinished = onFinished; AliProjectConfiguration configuration = project.getComponent(AliProjectConfiguration.class); username = configuration.getUsername().replace("@", "_"); } public void run(ProgressIndicator indicator) { super.run(indicator); if (!file.exists()) { // download cancelled return; } try { String url = FileUtils.readFileToString(file, "UTF-8"); // link file (no longer needed) file.delete(); Matcher matcher = pattern.matcher(url); if (matcher.matches()) { final String location = matcher.group(1); AliRestClient almRestClient; String password = null; boolean persistDisk = false; AuthData authData = getAuthData(location); boolean hasAuthData = (authData != null); if (hasAuthData) { username = authData.getLogin(); password = authData.getPassword(); } while (true) { if (!hasAuthData) { AuthDialog dialog = getAuthDialog(location); if (dialog == null) { return; } username = dialog.getUsername(); password = dialog.getPassword(); persistDisk = dialog.isRememberPassword(); } almRestClient = AliRestClient.create(location, matcher.group(2), matcher.group(3), username, password, RestClient.SessionStrategy.AUTO_LOGIN); try { almRestClient.login(); if (!hasAuthData) { saveAuthData(location, username, password, persistDisk); } break; } catch (AuthenticationFailureException e) { // wrong password hasAuthData = false; } } FileOutputStream fos = new FileOutputStream(targetFile); ResultInfo info = ResultInfo.create(fos); if (almRestClient.get(info, matcher.group(4)) == 200) { fos.close(); } else { // remove the file if not successful targetFile.delete(); } try { almRestClient.logout(); } catch (Exception e) { logger.warn("Logout failed", e); } if (onFinished != null) { onFinished.run(); } } else { logger.warn("Unexpected URL format: " + url); } } catch (IOException e) { throw new RuntimeException(e); } } private AuthDialog getAuthDialog(final String location) { final Ref<AuthDialog> dialog = Ref.create(); ApplicationManager.getApplication().invokeAndWait(new Runnable() { @Override public void run() { dialog.set(new AuthDialog(project, "ALM credentials", "Enter credentials for " + location, username, null, true)); dialog.get().show(); } }, ModalityState.any()); if (dialog.get().isOK()) { return dialog.get(); } else { return null; } } private void saveAuthData(String location, String username, String password, boolean persistDisk) { AlmRememberedInputs.getInstance().addUrl(location, username); String key = makeKey(username, location); PasswordSafeImpl passwordSafe = (PasswordSafeImpl) PasswordSafe.getInstance(); try { passwordSafe.getMemoryProvider().storePassword(project, AttachmentAgmLinkDownloadTask.class, key, password); if (persistDisk) { passwordSafe.getMasterKeyProvider().storePassword(project, AttachmentAgmLinkDownloadTask.class, key, password); } } catch (MasterPasswordUnavailableException e) { logger.error("Couldn't remember password for " + key, e); } catch (PasswordSafeException e) { logger.error("Couldn't remember password for " + key, e); } } private AuthData getAuthData(String url) { String userName = AlmRememberedInputs.getInstance().getUserNameForUrl(url); String key = makeKey(userName, url); final PasswordSafe passwordSafe = PasswordSafe.getInstance(); try { String password = passwordSafe.getPassword(project, AttachmentAgmLinkDownloadTask.class, key); return new AuthData(StringUtil.notNullize(userName), password); } catch (PasswordSafeException e) { logger.error("Couldn't get the password for key [" + key + "]", e); return null; } } private String makeKey(String username, String url) { return username + "@" + url; } private static File createTempFile() { try { File tempFile = File.createTempFile("agmlink", ""); tempFile.deleteOnExit(); return tempFile; } catch (IOException e) { throw new RuntimeException(e); } } }