/*
* 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.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.statushandlers.StatusManager;
import com.amazonaws.eclipse.core.AwsToolkitCore;
import com.amazonaws.eclipse.ec2.Ec2Plugin;
import com.amazonaws.eclipse.ec2.ui.SelectionTable;
import com.amazonaws.services.ec2.AmazonEC2;
import com.amazonaws.services.ec2.model.AuthorizeSecurityGroupIngressRequest;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
import com.amazonaws.services.ec2.model.IpPermission;
import com.amazonaws.services.ec2.model.RevokeSecurityGroupIngressRequest;
import com.amazonaws.services.ec2.model.SecurityGroup;
import com.amazonaws.services.ec2.model.UserIdGroupPair;
/**
* Selection table for users to select individual permissions in a security
* group.
*/
public class PermissionsComposite extends SelectionTable {
private PermissionsTableProvider permissionsTableProvider = new PermissionsTableProvider();
private Action addPermissionAction;
private Action removePermissionAction;
private SecurityGroupSelectionComposite securityGroupSelectionComposite;
/**
* Comparator to sort permissions.
*
* @author Jason Fulghum <fulghum@amazon.com>
*/
class IpPermissionComparator extends ViewerComparator {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if (!(e1 instanceof IpPermission && e2 instanceof IpPermission)) {
return 0;
}
IpPermission ipPermission1 = (IpPermission)e1;
IpPermission ipPermission2 = (IpPermission)e2;
int comparision = ipPermission1.getIpProtocol().compareTo(ipPermission2.getIpProtocol());
if (comparision == 0) {
comparision = ipPermission1.getFromPort() - ipPermission2.getFromPort();
}
return comparision;
}
}
/**
* Content and label provider for security group permission details.
*
* @author Jason Fulghum <fulghum@amazon.com>
*/
private class PermissionsTableProvider extends LabelProvider implements ITreeContentProvider, ITableLabelProvider {
private List<IpPermission> ipPermissions;
/*
* IStructuredContentProvider Interface
*/
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object)
*/
public Object[] getElements(Object inputElement) {
if (ipPermissions == null) {
return null;
}
return ipPermissions.toArray();
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@SuppressWarnings("unchecked")
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
if (newInput instanceof List) {
ipPermissions = (List<IpPermission>)newInput;
}
}
/*
* ITableLableProvider Interface
*/
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
*/
public Image getColumnImage(Object element, int columnIndex) {
return null;
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
*/
public String getColumnText(Object element, int columnIndex) {
if (!(element instanceof IpPermission)) {
return "???";
}
IpPermission ipPermission = (IpPermission)element;
switch (columnIndex) {
case 0:
return ipPermission.getIpProtocol();
case 1:
return formatPortRange(ipPermission);
case 2:
return formatUidGroupPairs(ipPermission);
case 3:
return formatIpRanges(ipPermission);
}
return "?";
}
private String formatIpRanges(IpPermission ipPermission) {
StringBuilder builder = new StringBuilder();
for (String s : ipPermission.getIpRanges()) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(s);
}
return builder.toString();
}
private String formatUidGroupPairs(IpPermission ipPermission) {
StringBuilder builder = new StringBuilder();
for (UserIdGroupPair s : ipPermission.getUserIdGroupPairs()) {
if (builder.length() > 0) {
builder.append(", ");
}
builder.append(s.getUserId() + ":" + s.getGroupName());
}
return builder.toString();
}
private String formatPortRange(IpPermission ipPermission) {
int fromPort = ipPermission.getFromPort();
int toPort = ipPermission.getToPort();
if (fromPort == toPort) {
return Integer.toString(fromPort);
} else {
return fromPort + " - " + toPort;
}
}
public Object[] getChildren(Object parentElement) {
return new Object[0];
}
public Object getParent(Object element) {
return null;
}
public boolean hasChildren(Object element) {
return false;
}
}
/**
* Creates a new PermissionsComposite with the specified parent.
*
* @param parent the parent of this new Composite.
*/
public PermissionsComposite(Composite parent) {
super(parent);
viewer.setContentProvider(permissionsTableProvider);
viewer.setLabelProvider(permissionsTableProvider);
viewer.setComparator(new IpPermissionComparator());
}
/**
* Refreshes the data in the permissions table
*/
public void refreshPermissions() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
SecurityGroup selectedSecurityGroup = securityGroupSelectionComposite.getSelectedSecurityGroup();
if (selectedSecurityGroup == null) {
setInput(new ArrayList<IpPermission>());
return;
}
String groupName = selectedSecurityGroup.getGroupName();
new RefreshPermissionsThread(groupName).start();
}
});
}
/**
* Sets the security group selection table that controls which security
* group's permissions are shown in this selection table.
*
* @param securityGroupSelectionComposite
* The security group selection table that controls which
* security group's permissions are shown in this selection
* table.
*/
public void setSecurityGroupComposite(
SecurityGroupSelectionComposite securityGroupSelectionComposite) {
this.securityGroupSelectionComposite = securityGroupSelectionComposite;
}
/**
* Returns the currently selected permission.
*
* @return The currently selected permission.
*/
public IpPermission getSelectedIpPermission() {
Object obj = this.getSelection();
return (IpPermission)obj;
}
/*
* SelectionTable Interface
*/
/* (non-Javadoc)
* @see com.amazonaws.eclipse.ec2.ui.SelectionTable#fillContextMenu(org.eclipse.jface.action.IMenuManager)
*/
@Override
protected void fillContextMenu(IMenuManager manager) {
if (securityGroupSelectionComposite.getSelectedSecurityGroup() == null) {
addPermissionAction.setEnabled(false);
} else {
addPermissionAction.setEnabled(true);
}
if (this.getSelection() == null) {
removePermissionAction.setEnabled(false);
} else {
removePermissionAction.setEnabled(true);
}
manager.add(addPermissionAction);
manager.add(removePermissionAction);
}
/* (non-Javadoc)
* @see com.amazonaws.eclipse.ec2.ui.SelectionTable#makeActions()
*/
@Override
protected void makeActions() {
addPermissionAction = new Action() {
public void run() {
String securityGroup = securityGroupSelectionComposite.getSelectedSecurityGroup().getGroupName();
EditSecurityGroupPermissionEntryDialog dialog = new EditSecurityGroupPermissionEntryDialog(Display.getCurrent().getActiveShell(), securityGroup);
if (dialog.open() != IDialogConstants.OK_ID) return;
new AuthorizePermissionsThread(securityGroup, dialog).start();
}
};
addPermissionAction.setText("Add Permissions...");
addPermissionAction.setToolTipText("Add new permissions to the selected security group");
addPermissionAction.setImageDescriptor(Ec2Plugin.getDefault().getImageRegistry().getDescriptor("add"));
removePermissionAction = new Action() {
public void run() {
String securityGroup = securityGroupSelectionComposite.getSelectedSecurityGroup().getGroupName();
new RevokePermissionsThread(securityGroup, getSelectedIpPermission()).start();
}
};
removePermissionAction.setText("Remove Permissions");
removePermissionAction.setToolTipText("Remove the selected permission from the selected security group");
removePermissionAction.setImageDescriptor(Ec2Plugin.getDefault().getImageRegistry().getDescriptor("remove"));
}
/* (non-Javadoc)
* @see com.amazonaws.eclipse.ec2.ui.SelectionTable#createColumns()
*/
@Override
protected void createColumns() {
newColumn("Protocol", 10);
newColumn("Port", 10);
newColumn("User:Group", 10);
newColumn("Source CIDR", 70);
}
/**
* Sets the input for this permissions composite, ensuring that the widgets
* are updated in the UI thread.
*
* @param ipPermissions
* The list of permissions to display in this permissions
* composite.
*/
private void setInput(final List<IpPermission> ipPermissions) {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
viewer.setInput(ipPermissions);
packColumns();
}
});
}
/*
* Private Threads for making EC2 service calls
*/
/**
* Thread for making an EC2 service call to list all permissions in an
* EC2 security group.
*/
private class RefreshPermissionsThread extends Thread {
private final String groupName;
/**
* Creates a new RefreshPermissionsThread ready to be started to query
* the permissions in the specified EC2 security group and update the
* permissions list widget.
*
* @param groupName
* The EC2 security group whose permissions are to be
* refreshed.
*/
public RefreshPermissionsThread(String groupName) {
this.groupName = groupName;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
try {
DescribeSecurityGroupsRequest request = new DescribeSecurityGroupsRequest();
request.withGroupNames(groupName);
DescribeSecurityGroupsResult response = getAwsEc2Client().describeSecurityGroups(request);
List<SecurityGroup> securityGroups = response.getSecurityGroups();
if (securityGroups.isEmpty()) return;
setInput(securityGroups.get(0).getIpPermissions());
} catch (Exception e) {
// Only log an error if the account info is valid and we
// actually expected this call to work
if (AwsToolkitCore.getDefault().getAccountInfo().isValid()) {
Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID,
"Unable to refresh security group permissions: " + e.getMessage(), e);
StatusManager.getManager().handle(status, StatusManager.LOG);
}
}
}
}
/**
* Thread for making an EC2 service call to authorize new permissions in an
* EC2 security group.
*/
private class AuthorizePermissionsThread extends Thread {
private final EditSecurityGroupPermissionEntryDialog dialog;
private final String securityGroup;
/**
* Creates a new AuthorizePermissionsThread ready to be run to add the
* permissions detailed in the specified permission entry dialog to the
* specified security group.
*
* @param securityGroup
* The security group in which to authorize the new
* permissions.
* @param dialog
* The permission entry dialog containing the user input on
* what permissions to authorize.
*/
public AuthorizePermissionsThread(String securityGroup, EditSecurityGroupPermissionEntryDialog dialog) {
this.securityGroup = securityGroup;
this.dialog = dialog;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
try {
if (dialog.isUserGroupPermission()) {
String groupName = dialog.getUserGroupPermissionComposite().getSecurityGroup();
String userId = dialog.getUserGroupPermissionComposite().getUserId();
AuthorizeSecurityGroupIngressRequest request = new AuthorizeSecurityGroupIngressRequest();
request.setGroupName(securityGroup);
request.setSourceSecurityGroupName(groupName);
request.setSourceSecurityGroupOwnerId(userId);
getAwsEc2Client().authorizeSecurityGroupIngress(request);
} else {
String protocol = dialog.getPortRangePermissionComposite().getProtocol();
int fromPort = dialog.getPortRangePermissionComposite().getFromPort();
int toPort = dialog.getPortRangePermissionComposite().getToPort();
String networkMask = dialog.getPortRangePermissionComposite().getNetwork();
AuthorizeSecurityGroupIngressRequest request = new AuthorizeSecurityGroupIngressRequest();
request.setGroupName(securityGroup);
request.setIpProtocol(protocol);
request.setFromPort(fromPort);
request.setToPort(toPort);
request.setCidrIp(networkMask);
getAwsEc2Client().authorizeSecurityGroupIngress(request);
}
} catch (Exception e) {
Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID,
"Unable to add permission to group: " + e.getMessage(), e);
StatusManager.getManager().handle(status, StatusManager.BLOCK | StatusManager.LOG);
}
refreshPermissions();
}
}
/**
* Thread for making an EC2 service call to revoke specified permissions in
* an EC2 security group.
*/
private class RevokePermissionsThread extends Thread {
private final IpPermission ipPermission;
private final String securityGroup;
/**
* Creates a new RevokePermissionsThread ready to be run to remove the
* specified permissions from the specified EC2 security group.
*
* @param securityGroup
* The group from which to revoke permissions.
* @param permission
* The permissions to revoke.
*/
public RevokePermissionsThread(String securityGroup, IpPermission permission) {
this.securityGroup = securityGroup;
this.ipPermission = permission;
}
/* (non-Javadoc)
* @see java.lang.Thread#run()
*/
@Override
public void run() {
try {
AmazonEC2 client = getAwsEc2Client();
if (ipPermission.getUserIdGroupPairs().isEmpty()) {
for (String ipRange : ipPermission.getIpRanges()) {
RevokeSecurityGroupIngressRequest request = new RevokeSecurityGroupIngressRequest();
request.setGroupName(securityGroup);
request.setIpProtocol(ipPermission.getIpProtocol());
request.setFromPort(ipPermission.getFromPort());
request.setToPort(ipPermission.getToPort());
request.setCidrIp(ipRange);
client.revokeSecurityGroupIngress(request);
}
} else {
for (UserIdGroupPair pair : ipPermission.getUserIdGroupPairs()) {
RevokeSecurityGroupIngressRequest request = new RevokeSecurityGroupIngressRequest();
request.setGroupName(securityGroup);
request.setSourceSecurityGroupName(pair.getGroupName());
request.setSourceSecurityGroupOwnerId(pair.getUserId());
getAwsEc2Client().revokeSecurityGroupIngress(request);
}
}
} catch (Exception e) {
Status status = new Status(Status.ERROR, Ec2Plugin.PLUGIN_ID,
"Unable to remove security group permissions: " + e.getMessage(), e);
StatusManager.getManager().handle(status, StatusManager.BLOCK | StatusManager.LOG);
}
refreshPermissions();
}
}
}