/*
* Copyright 2008-2012 Amazon Technologies, Inc.
*
* 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://aws.amazon.com/apache2.0
*
* This file 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.amazonaws.eclipse.ec2.ui.securitygroups;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import com.amazonaws.eclipse.ec2.ui.SwappableComposite;
/**
* Dialog to collect user input on a security group permission entry.
*/
public class EditSecurityGroupPermissionEntryDialog extends Dialog {
private final String securityGroupName;
private SwappableComposite swappableComposite;
private UserGroupPermissionComposite userGroupComposite;
private PortRangePermissionComposite portRangeComposite;
private Button userGroupPermissionButton;
private Button portRangePermissionButton;
private boolean isUserGroupPermission;
public EditSecurityGroupPermissionEntryDialog(Shell parentShell, String securityGroupName) {
super(parentShell);
this.securityGroupName = securityGroupName;
}
public UserGroupPermissionComposite getUserGroupPermissionComposite() {
return userGroupComposite;
}
public PortRangePermissionComposite getPortRangePermissionComposite() {
return portRangeComposite;
}
public boolean isUserGroupPermission() {
return isUserGroupPermission;
}
/*
* Dialog Interface
*/
/*
* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#createButtonBar(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createButtonBar(Composite parent) {
Control control = super.createButtonBar(parent);
updateOkButton();
return control;
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite)
*/
@Override
protected Control createDialogArea(Composite parent) {
Composite composite = createComposite(parent);
createLabel("Assign permissions by:", composite, 1);
portRangePermissionButton = createRadioButton("Protocol, port and network", composite, 2);
userGroupPermissionButton = createRadioButton("AWS user and group", composite, 2);
swappableComposite = new SwappableComposite(composite, SWT.NONE);
swappableComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
userGroupComposite = new UserGroupPermissionComposite(swappableComposite);
portRangeComposite = new PortRangePermissionComposite(swappableComposite);
SelectionListener listener = new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
public void widgetSelected(SelectionEvent e) {
if (e.getSource().equals(userGroupPermissionButton)) {
swappableComposite.setActiveComposite(userGroupComposite);
} else {
swappableComposite.setActiveComposite(portRangeComposite);
}
}
};
userGroupPermissionButton.addSelectionListener(listener);
portRangePermissionButton.addSelectionListener(listener);
return composite;
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#create()
*/
@Override
public void create() {
super.create();
Point p = portRangeComposite.computeSize(SWT.DEFAULT, SWT.DEFAULT);
Rectangle r = userGroupComposite.getParent().getClientArea();
if (r.width > p.x) p.x = r.width;
swappableComposite.setSize(p);
// Start off with the user / group permission style selected
portRangePermissionButton.setSelection(true);
swappableComposite.setActiveComposite(portRangeComposite);
getShell().layout();
getShell().setSize(getShell().computeSize(SWT.DEFAULT,SWT.DEFAULT));
}
/* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#okPressed()
*/
@Override
protected void okPressed() {
userGroupComposite.saveFieldValues();
portRangeComposite.saveFieldValues();
this.isUserGroupPermission = userGroupPermissionButton.getSelection();
super.okPressed();
}
/*
* Private Classes
*/
/**
* Composite with options for defining security group permissions
* by AWS user IDs and groups.
*/
class UserGroupPermissionComposite extends Composite {
private Text securityGroupText;
private Text userIdText;
private String securityGroup;
private String userId;
/**
* Creates a new composite with the specified parent.
*
* @param parent The parent for this composite.
*/
public UserGroupPermissionComposite(Composite parent) {
super(parent, SWT.NONE);
create();
}
public void saveFieldValues() {
securityGroup = securityGroupText.getText();
userId = userIdText.getText();
}
public String getSecurityGroup() {
return securityGroup;
}
public String getUserId() {
return userId;
}
public boolean isComplete() {
if (securityGroupText == null || securityGroupText.getText().length() == 0) return false;
if (userIdText == null || userIdText.getText().length() == 0) return false;
return true;
}
private void create() {
GridLayout gridLayout = new GridLayout(1, true);
gridLayout.marginWidth = 0;
setLayout(gridLayout);
createLabel("AWS User ID:", this, 1);
userIdText = createTextBox(this, 1);
createLabel("AWS Security Group:", this, 1);
securityGroupText = createTextBox(this, 1);
pack();
}
}
/**
* Composite with options for defining security group permissions
* by protocol, port and network mask.
*/
class PortRangePermissionComposite extends Composite {
private Combo protocolCombo;
private Text portText;
private Text networkText;
private String protocol;
private String network;
private int fromPort;
private int toPort;
private final Pattern networkMaskPattern = Pattern.compile("\\d+\\.\\d+\\.\\d+\\.\\d+/\\d+");
/**
* Creates new composite with the specified parent.
*
* @param parent The parent of this composite.
*/
public PortRangePermissionComposite(Composite parent) {
super (parent, SWT.NONE);
create();
}
public String getNetwork() {
return network;
}
public int getFromPort() {
return fromPort;
}
public int getToPort() {
return toPort;
}
public String getProtocol() {
return protocol.toLowerCase();
}
public void saveFieldValues() {
protocol = protocolCombo.getText();
network = networkText.getText();
Integer[] ports = extractPortRange();
if (ports != null) {
fromPort = ports[0];
toPort = ports[1];
}
}
/**
* Parses the user entered port value and extracts a port range returned
* as a two element list of integers. If invalid input is detected null
* is returned.
*
* @return An array of two elements where the first element is the
* starting port in the port range and the second is the ending
* port in the port range. If invalid input was entered null
* will be returned.
*/
private Integer[] extractPortRange() {
if (portText == null) return null;
String portInfo = portText.getText().trim();
int port1, port2;
if (portInfo.contains("-") && !portInfo.startsWith("-")) {
String[] strings = portInfo.split("-");
if (strings.length != 2) return null;
try {
port1 = Integer.parseInt(strings[0].trim());
port2 = Integer.parseInt(strings[1].trim());
} catch (NumberFormatException nfe) {
return null;
}
} else {
try {
port1 = Integer.parseInt(portInfo.trim());
port2 = port1;
} catch (NumberFormatException nfe) {
return null;
}
}
if (port2 < port1) return null;
return new Integer[] {port1, port2};
}
public boolean isComplete() {
if (extractPortRange() == null) return false;
if (networkText == null) return false;
Matcher matcher = networkMaskPattern.matcher(networkText.getText());
if (!matcher.matches()) return false;
return true;
}
private void create() {
GridLayout gridLayout = new GridLayout(1, true);
gridLayout.verticalSpacing = 2;
gridLayout.marginHeight = 2;
gridLayout.marginTop = 2;
gridLayout.marginWidth = 0;
setLayout(gridLayout);
createLabel("Protocol:", this, 1);
protocolCombo = new Combo(this, SWT.NONE | SWT.READ_ONLY);
protocolCombo.add("TCP");
protocolCombo.add("UDP");
protocolCombo.add("ICMP");
protocolCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
protocolCombo.select(0);
createLabel("Port or Port Range:", this, 1);
portText = createTextBox(this, 1);
createLabel("Network Mask:", this, 1);
networkText = createTextBox(this, 1);
networkText.setText("0.0.0.0/0");
pack();
}
}
private Button createRadioButton(String text, Composite parent, int columnSpan) {
Button b = new Button(parent, SWT.RADIO);
b.setText(text);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = columnSpan;
b.setLayoutData(gridData);
b.addSelectionListener(selectionListener);
return b;
}
/*
* Private Methods
*/
private Label createLabel(String text, Composite parent, int columnSpan) {
Label label = new Label(parent, SWT.NONE);
label.setText(text);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.verticalAlignment = GridData.VERTICAL_ALIGN_END;
gridData.horizontalSpan = columnSpan;
gridData.verticalIndent = 2;
label.setLayoutData(gridData);
return label;
}
private Text createTextBox(Composite parent, int columnSpan) {
Text text = new Text(parent, SWT.BORDER);
GridData gridData = new GridData(GridData.FILL_HORIZONTAL);
gridData.horizontalSpan = columnSpan;
gridData.verticalAlignment = GridData.VERTICAL_ALIGN_BEGINNING;
text.setLayoutData(gridData);
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
updateOkButton();
}
});
text.addSelectionListener(selectionListener);
return text;
}
private SelectionListener selectionListener = new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {}
public void widgetSelected(SelectionEvent e) {
updateOkButton();
}
};
private Composite createComposite(Composite parent) {
Composite composite = new Composite(parent, SWT.BORDER);
GridLayout gridLayout = new GridLayout(2, false);
gridLayout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
gridLayout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
gridLayout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
gridLayout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
gridLayout.marginHeight = 2;
composite.setLayout(gridLayout);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
return composite;
}
private void updateOkButton() {
if (userGroupComposite == null || portRangeComposite == null) return;
boolean b = false;
if (userGroupPermissionButton.getSelection()) {
b = userGroupComposite.isComplete();
} else {
b = portRangeComposite.isComplete();
}
Button okButton = getButton(IDialogConstants.OK_ID);
if (okButton != null) {
okButton.setEnabled(b);
}
}
}