/*
* SoapUI, Copyright (C) 2004-2016 SmartBear Software
*
* Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent
* versions of the EUPL (the "Licence");
* You may not use this work except in compliance with the Licence.
* You may obtain a copy of the Licence at:
*
* http://ec.europa.eu/idabc/eupl
*
* Unless required by applicable law or agreed to in writing, software distributed under the Licence is
* distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the Licence for the specific language governing permissions and limitations
* under the Licence.
*/
package com.eviware.soapui.support.editor.inspectors.auth;
import com.eviware.soapui.analytics.Analytics;
import com.eviware.soapui.analytics.SoapUIActions;
import com.eviware.soapui.config.CredentialsConfig;
import com.eviware.soapui.impl.rest.OAuth1Profile;
import com.eviware.soapui.impl.rest.OAuth1ProfileContainer;
import com.eviware.soapui.impl.rest.OAuth1ProfileListener;
import com.eviware.soapui.impl.rest.OAuth2Profile;
import com.eviware.soapui.impl.rest.OAuth2ProfileContainer;
import com.eviware.soapui.impl.rest.OAuth2ProfileListener;
import com.eviware.soapui.impl.rest.RestRequest;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.support.actions.ShowOnlineHelpAction;
import com.eviware.soapui.impl.wsdl.WsdlRequest;
import com.eviware.soapui.impl.wsdl.support.HelpUrls;
import com.eviware.soapui.support.UISupport;
import com.eviware.soapui.support.editor.EditorView;
import com.eviware.soapui.support.editor.inspectors.AbstractXmlInspector;
import com.eviware.soapui.support.editor.views.xml.raw.RawXmlEditorFactory;
import com.eviware.soapui.support.editor.xml.XmlDocument;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.RowSpec;
import javax.swing.BorderFactory;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ProfileSelectionForm<T extends AbstractHttpRequest> extends AbstractXmlInspector {
public static final String PROFILE_COMBO_BOX = "Authorization:";
public static final String BASIC_FORM_LABEL = "Legacy form";
public static final String WSS_FORM_LABEL = "WSS form";
public static final String OPTIONS_SEPARATOR = "------------------";
public static final String DELETE_PROFILE_DIALOG_TITLE = "Delete Profile";
public static final String RENAME_PROFILE_DIALOG_TITLE = "Rename Profile";
public static final String EMPTY_PANEL = "EmptyPanel";
static final ImageIcon AUTH_ENABLED_ICON = UISupport.createImageIcon("/lock.png");
private static final String OAUTH_2_FORM_LABEL = "OAuth 2 form";
private static final String OAUTH_1_FORM_LABEL = "OAuth 1 form";
private static final ImageIcon AUTH_NOT_ENABLED_ICON = null;
private static final Map<String, ShowOnlineHelpAction> helpActions = new HashMap<String, ShowOnlineHelpAction>();
private final JPanel outerPanel = new JPanel(new BorderLayout());
private final JPanel cardPanel = new JPanel(new CardLayout());
private T request;
private JComboBox profileSelectionComboBox;
private CellConstraints cc = new CellConstraints();
private BasicAuthenticationForm<T> authenticationForm;
private OAuth2Form oAuth2Form;
private OAuth1Form oAuth1Form;
private JButton helpButton;
private ProfileListener profileListener;
private WSSAuthenticationForm wssAuthenticationForm;
protected ProfileSelectionForm(T request) {
super(AuthInspectorFactory.INSPECTOR_ID, "Authentication and Security-related settings",
true, AuthInspectorFactory.INSPECTOR_ID);
this.request = request;
buildUI();
profileListener = new ProfileListener();
getOAuth2ProfileContainer().addOAuth2ProfileListener(profileListener);
getOAuth1ProfileContainer().addOAuth1ProfileListener(profileListener);
}
protected static boolean isReservedProfileName(String newName) {
return getBasicAuthenticationTypes().contains(newName) || newName.equals(OPTIONS_SEPARATOR);
}
protected static ArrayList<String> getBasicAuthenticationTypes() {
ArrayList<String> options = new ArrayList<String>();
options.add(AbstractHttpRequest.BASIC_AUTH_PROFILE);
options.add(CredentialsConfig.AuthType.NTLM.toString());
options.add(CredentialsConfig.AuthType.SPNEGO_KERBEROS.toString());
return options;
}
@Override
public JComponent getComponent() {
profileSelectionComboBox.setSelectedItem(request.getSelectedAuthProfile());
return outerPanel;
}
@Override
public boolean isEnabledFor(EditorView<XmlDocument> view) {
return !view.getViewId().equals(RawXmlEditorFactory.VIEW_ID);
}
@Override
public void release() {
super.release();
if (oAuth2Form != null) {
oAuth2Form.release();
}
if (oAuth1Form != null) {
oAuth1Form.release();
}
getOAuth2ProfileContainer().removeOAuth2ProfileListener(profileListener);
getOAuth1ProfileContainer().removeOAuth1ProfileListener(profileListener);
}
protected void buildUI() {
JPanel innerPanel = new JPanel(new BorderLayout());
innerPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
JPanel comboBoxPanel = createAuthorizationLabelAndComboBox();
innerPanel.add(comboBoxPanel, BorderLayout.PAGE_START);
cardPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
cardPanel.add(createEmptyPanel(), EMPTY_PANEL);
innerPanel.add(cardPanel, BorderLayout.CENTER);
authenticationForm = new BasicAuthenticationForm<T>(request);
cardPanel.add(authenticationForm.getComponent(), BASIC_FORM_LABEL);
if (isSoapRequest(request)) {
wssAuthenticationForm = new WSSAuthenticationForm((WsdlRequest) request);
cardPanel.add(wssAuthenticationForm.getComponent(), WSS_FORM_LABEL);
}
outerPanel.add(new JScrollPane(innerPanel), BorderLayout.CENTER);
}
private JPanel createEmptyPanel() {
JPanel panelWithText = new JPanel(new BorderLayout());
String helpText = "<html>\n" +
"<body>" +
"</div>" +
"<div style=\"text-align:center\"><b>Not Yet Configured</b>" +
"<br>Authorization has not been set for protected services." +
"<br>Use the <i>Authorization</i> drop down to configure." +
"</div>" +
"</body>" +
"</html>";
JLabel label = new JLabel(helpText);
label.setHorizontalAlignment(SwingConstants.CENTER);
panelWithText.add(label, BorderLayout.CENTER);
panelWithText.setBorder(BorderFactory.createCompoundBorder(BorderFactory.createLineBorder(AbstractAuthenticationForm.CARD_BORDER_COLOR),
BorderFactory.createEmptyBorder(10, 10, 10, 10)));
panelWithText.setBackground(AbstractAuthenticationForm.CARD_BACKGROUND_COLOR);
return panelWithText;
}
private boolean isSoapRequest(T request) {
return request instanceof WsdlRequest;
}
private JPanel createAuthorizationLabelAndComboBox() {
FormLayout formLayout = new FormLayout("5px:none,left:pref,40px,left:default,5px:grow(1.0)");
JPanel comboBoxPanel = new JPanel(formLayout);
comboBoxPanel.setBorder(BorderFactory.createEmptyBorder(0, 10, 0, 10));
JLabel authorizationLabel = new JLabel(PROFILE_COMBO_BOX);
authorizationLabel.setBorder(BorderFactory.createEmptyBorder(3, 0, 0, 0));
formLayout.appendRow(new RowSpec("top:pref"));
comboBoxPanel.add(authorizationLabel, cc.xy(2, 1));
createProfileSelectionComboBox();
comboBoxPanel.add(profileSelectionComboBox, cc.xy(4, 1));
JPanel wrapperPanel = new JPanel(new BorderLayout(5, 5));
wrapperPanel.add(comboBoxPanel, BorderLayout.LINE_START);
helpButton = UISupport.createFormButton(helpActions.get(EMPTY_PANEL));
wrapperPanel.add(helpButton, BorderLayout.AFTER_LINE_ENDS);
return wrapperPanel;
}
private void createProfileSelectionComboBox() {
String[] existingProfiles = createOptionsForAuthorizationCombo(request.getSelectedAuthProfile());
profileSelectionComboBox = new JComboBox(existingProfiles);
profileSelectionComboBox.setName(PROFILE_COMBO_BOX);
profileSelectionComboBox.addItemListener(new ProfileSelectionListener());
}
private void setAuthenticationTypeAndShowCard(String selectedOption) {
if (getAddEditOptions().contains(selectedOption)) {
performAddEditOperation(request.getSelectedAuthProfile(), selectedOption);
return;
}
if (getBasicAuthenticationTypes().contains(selectedOption)) {
setIcon(AUTH_ENABLED_ICON);
setTitle(AuthInspectorFactory.INSPECTOR_ID + " (" + selectedOption + ")");
request.setSelectedAuthProfileAndAuthType(selectedOption, request.getBasicAuthType(selectedOption));
if (isSoapRequest(request)) {
wssAuthenticationForm.setButtonGroupVisibility(selectedOption.equals(AbstractHttpRequest.BASIC_AUTH_PROFILE));
changeAuthorizationType(WSS_FORM_LABEL, selectedOption);
} else {
authenticationForm.setButtonGroupVisibility(selectedOption.equals(AbstractHttpRequest.BASIC_AUTH_PROFILE));
changeAuthorizationType(BASIC_FORM_LABEL, selectedOption);
}
} else if (isRestRequest(request) && getOAuth2ProfileContainer().getOAuth2ProfileNameList().contains(selectedOption)) {
setTitle(AuthInspectorFactory.INSPECTOR_ID + " (" + selectedOption + ")");
request.setSelectedAuthProfileAndAuthType(selectedOption, CredentialsConfig.AuthType.O_AUTH_2_0);
oAuth2Form = new OAuth2Form(getOAuth2ProfileContainer().getProfileByName(selectedOption), this);
cardPanel.add(oAuth2Form.getComponent(), OAUTH_2_FORM_LABEL);
changeAuthorizationType(OAUTH_2_FORM_LABEL, selectedOption);
Analytics.trackAction(SoapUIActions.ASSIGN_O_AUTH.getActionName(), "OAuth2Flow",
oAuth2Form.getProfile().getOAuth2Flow().name());
} else if (isRestRequest(request) && getOAuth1ProfileContainer().getOAuth1ProfileNameList().contains(selectedOption)) {
setTitle(AuthInspectorFactory.INSPECTOR_ID + " (" + selectedOption + ")");
request.setSelectedAuthProfileAndAuthType(selectedOption, CredentialsConfig.AuthType.O_AUTH_1_0);
oAuth1Form = new OAuth1Form(getOAuth1ProfileContainer().getProfileByName(selectedOption), this);
cardPanel.add(oAuth1Form.getComponent(), OAUTH_1_FORM_LABEL);
changeAuthorizationType(OAUTH_1_FORM_LABEL, selectedOption);
} else if (selectedOption.equals(OPTIONS_SEPARATOR)) {
profileSelectionComboBox.setSelectedIndex(0);
} else //selectedItem : No Authorization
{
setIcon(AUTH_NOT_ENABLED_ICON);
setTitle(AuthInspectorFactory.INSPECTOR_ID);
request.setSelectedAuthProfileAndAuthType(selectedOption, CredentialsConfig.AuthType.NO_AUTHORIZATION);
changeAuthorizationType(EMPTY_PANEL, selectedOption);
}
}
private void performAddEditOperation(final String currentProfile, String selectedOption) {
AddEditOptions addEditOption = getAddEditOptionForDescription(selectedOption);
switch (addEditOption) {
case ADD:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new AuthorizationSelectionDialog<T>(request, getBasicAuthenticationTypes());
refreshProfileSelectionComboBox(request.getSelectedAuthProfile());
}
});
break;
case DELETE:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
deleteCurrentProfile(currentProfile);
}
});
break;
case RENAME:
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
renameCurrentProfile(currentProfile);
}
});
break;
default:
break;
}
}
private void renameCurrentProfile(String profileOldName) {
String newName = UISupport.prompt("Specify name of Profile", RENAME_PROFILE_DIALOG_TITLE, profileOldName);
if (newName == null || profileOldName.equals(newName)) {
profileSelectionComboBox.setSelectedItem(profileOldName);
return;
}
if (newName.trim().equals("")) {
UISupport.showErrorMessage("New name can't be empty.");
profileSelectionComboBox.setSelectedItem(profileOldName);
return;
}
if (isReservedProfileName(newName)) {
UISupport.showErrorMessage("'" + newName + "' is a reserved profile name.");
profileSelectionComboBox.setSelectedItem(profileOldName);
return;
}
if (getOAuth2ProfileContainer().getOAuth2ProfileNameList().contains(newName)) {
UISupport.showErrorMessage("There is already a profile named '" + newName + "'");
profileSelectionComboBox.setSelectedItem(profileOldName);
return;
}
getOAuth2ProfileContainer().renameProfile(profileOldName, newName);
}
private void deleteCurrentProfile(String profileName) {
boolean confirmedDeletion = UISupport.confirm("Do you really want to delete profile '" + profileName + "' ?",
DELETE_PROFILE_DIALOG_TITLE);
if (!confirmedDeletion) {
refreshProfileSelectionComboBox(profileName);
return;
}
if (isRestRequest(request) && getOAuth2ProfileContainer().getOAuth2ProfileNameList().contains(profileName)) {
getOAuth2ProfileContainer().removeProfile(profileName);
} else if (isRestRequest(request) && getOAuth1ProfileContainer().getOAuth1ProfileNameList().contains(profileName)) {
getOAuth1ProfileContainer().removeProfile(profileName);
} else if (getBasicAuthenticationTypes().contains(profileName)) {
request.removeBasicAuthenticationProfile(profileName);
}
refreshProfileSelectionComboBox(CredentialsConfig.AuthType.NO_AUTHORIZATION.toString());
}
private void refreshProfileSelectionComboBox(String selectedProfile) {
DefaultComboBoxModel model = new DefaultComboBoxModel(createOptionsForAuthorizationCombo(selectedProfile));
model.setSelectedItem(OPTIONS_SEPARATOR);
profileSelectionComboBox.setModel(model);
profileSelectionComboBox.removeItemListener(profileSelectionComboBox.getItemListeners()[0]);
profileSelectionComboBox.addItemListener(new ProfileSelectionListener());
profileSelectionComboBox.setSelectedItem(selectedProfile);
}
private void changeAuthorizationType(String cardName, String selectedOption) {
showCard(cardName);
String helpKey = cardName;
if (cardName.equals(BASIC_FORM_LABEL) || cardName.equals(WSS_FORM_LABEL)) {
helpKey = selectedOption;
}
helpButton.setAction(helpActions.get(helpKey));
}
private void showCard(String cardName) {
CardLayout layout = (CardLayout) cardPanel.getLayout();
layout.show(cardPanel, cardName);
}
private OAuth2ProfileContainer getOAuth2ProfileContainer() {
return request.getProject().getOAuth2ProfileContainer();
}
private OAuth1ProfileContainer getOAuth1ProfileContainer() {
return request.getProject().getOAuth1ProfileContainer();
}
private String[] createOptionsForAuthorizationCombo(String selectedAuthProfile) {
ArrayList<String> options = new ArrayList<String>();
options.add(CredentialsConfig.AuthType.NO_AUTHORIZATION.toString());
Set<String> basicAuthenticationProfiles = request.getBasicAuthenticationProfiles();
options.addAll(basicAuthenticationProfiles);
ArrayList<String> addEditOptions = getAddEditOptions();
ArrayList<String> oAuth2Profiles = null;
ArrayList<String> oAuth1Profiles = null;
if (isRestRequest(request)) {
oAuth2Profiles = getOAuth2ProfileContainer().getOAuth2ProfileNameList();
oAuth1Profiles = getOAuth1ProfileContainer().getOAuth1ProfileNameList();
options.addAll(oAuth2Profiles);
options.addAll(oAuth1Profiles);
}
if (isSoapRequest(request)) {
if (basicAuthenticationProfiles.size() >= getBasicAuthenticationTypes().size()) {
addEditOptions.remove(AddEditOptions.ADD.getDescription());
}
}
if (oAuth2Profiles == null || !oAuth2Profiles.contains(selectedAuthProfile)) {
addEditOptions.remove(AddEditOptions.RENAME.getDescription());
}
if (options.size() <= 1 || CredentialsConfig.AuthType.NO_AUTHORIZATION.toString().equals(selectedAuthProfile)) {
addEditOptions.remove(AddEditOptions.DELETE.getDescription());
}
if (!addEditOptions.isEmpty()) {
options.add(OPTIONS_SEPARATOR);
options.addAll(addEditOptions);
}
return options.toArray(new String[options.size()]);
}
private boolean isRestRequest(T request) {
return request instanceof RestRequest;
}
private ArrayList<String> getAddEditOptions() {
ArrayList<String> addEditOptions = new ArrayList<String>();
addEditOptions.add(AddEditOptions.ADD.getDescription());
addEditOptions.add(AddEditOptions.RENAME.getDescription());
addEditOptions.add(AddEditOptions.DELETE.getDescription());
return addEditOptions;
}
private AddEditOptions getAddEditOptionForDescription(String description) {
for (AddEditOptions option : AddEditOptions.values()) {
if (option.getDescription().equals(description)) {
return option;
}
}
return null;
}
public enum AddEditOptions {
ADD("Add New Authorization..."),
RENAME("Rename current..."),
DELETE("Delete current");
private String description;
AddEditOptions(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
private class ProfileSelectionListener implements ItemListener {
@Override
public void itemStateChanged(ItemEvent e) {
if (e.getStateChange() == ItemEvent.SELECTED) {
String selectedProfile = (String) e.getItem();
setAuthenticationTypeAndShowCard(selectedProfile);
if (!getAddEditOptions().contains(selectedProfile) && !selectedProfile.equals(OPTIONS_SEPARATOR)) {
DefaultComboBoxModel profileComboBoXModel = new DefaultComboBoxModel(
createOptionsForAuthorizationCombo(selectedProfile));
profileComboBoXModel.setSelectedItem(selectedProfile);
profileSelectionComboBox.setModel(profileComboBoXModel);
}
}
}
}
private class ProfileListener implements OAuth2ProfileListener, OAuth1ProfileListener {
@Override
public void profileAdded(OAuth2Profile profile) {
refreshProfileSelectionComboBox(request.getSelectedAuthProfile());
}
@Override
public void profileRemoved(String profileName) {
refreshProfileSelectionComboBox(request.getSelectedAuthProfile());
}
@Override
public void profileRenamed(String profileOldName, String newName) {
refreshProfileSelectionComboBox(request.getSelectedAuthProfile());
}
@Override
public void profileAdded(OAuth1Profile profile) {
refreshProfileSelectionComboBox(request.getSelectedAuthProfile());
}
}
static {
helpActions.put(EMPTY_PANEL, new ShowOnlineHelpAction(null, HelpUrls.AUTHORIZATION));
helpActions.put(AbstractHttpRequest.BASIC_AUTH_PROFILE, new ShowOnlineHelpAction(null, HelpUrls.AUTHORIZATION_BASIC));
helpActions.put(CredentialsConfig.AuthType.NTLM.toString(), new ShowOnlineHelpAction(null, HelpUrls.AUTHORIZATION_NTLM));
helpActions.put(CredentialsConfig.AuthType.SPNEGO_KERBEROS.toString(), new ShowOnlineHelpAction(null, HelpUrls.AUTHORIZATION_SPNEGO_KERBEROS));
helpActions.put(OAUTH_2_FORM_LABEL, new ShowOnlineHelpAction(null, HelpUrls.AUTHORIZATION_OAUTH2));
}
}