diff --git a/src/main/java/org/bukkit/craftbukkit/CraftBanEntry.java b/src/main/java/org/bukkit/craftbukkit/CraftBanEntry.java
new file mode 100644
index 0000000000..39ece74854
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/CraftBanEntry.java
@@ -0,0 +1,86 @@
+package org.bukkit.craftbukkit;
+
+import java.util.Date;
+
+import net.minecraft.server.BanEntry;
+import net.minecraft.server.BanList;
+
+public final class CraftBanEntry implements org.bukkit.BanEntry {
+    private final BanList list;
+    private final String name;
+    private Date created;
+    private String source;
+    private Date expiration;
+    private String reason;
+
+    public CraftBanEntry(BanEntry entry, BanList list) {
+        this.list = list;
+        this.name = entry.getName();
+        this.created = entry.getCreated() != null ? new Date(entry.getCreated().getTime()) : null;
+        this.source = entry.getSource();
+        this.expiration = entry.getExpires() != null ? new Date(entry.getExpires().getTime()) : null;
+        this.reason = entry.getReason();
+    }
+
+    @Override
+    public String getTarget() {
+        return this.name;
+    }
+
+    @Override
+    public Date getCreated() {
+        return this.created == null ? null : (Date) this.created.clone();
+    }
+
+    @Override
+    public void setCreated(Date created) {
+        this.created = created;
+    }
+
+    @Override
+    public String getSource() {
+        return this.source;
+    }
+
+    @Override
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    @Override
+    public Date getExpiration() {
+        return this.expiration == null ? null : (Date) this.expiration.clone();
+    }
+
+    @Override
+    public void setExpiration(Date expiration) {
+        if (expiration != null && expiration.getTime() == new Date(0, 0, 0, 0, 0, 0).getTime()) {
+            expiration = null; // Forces "forever"
+        }
+
+        this.expiration = expiration;
+    }
+
+    @Override
+    public String getReason() {
+        return this.reason;
+    }
+
+    @Override
+    public void setReason(String reason) {
+        this.reason = reason;
+    }
+
+    @Override
+    public void save() {
+        BanEntry entry = new BanEntry(this.name);
+        entry.setCreated(this.created);
+        entry.setSource(this.source);
+        entry.setExpires(this.expiration);
+        entry.setReason(this.reason);
+
+        this.list.add(entry);
+        this.list.save();
+    }
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftBanList.java b/src/main/java/org/bukkit/craftbukkit/CraftBanList.java
new file mode 100644
index 0000000000..e4abd0530d
--- /dev/null
+++ b/src/main/java/org/bukkit/craftbukkit/CraftBanList.java
@@ -0,0 +1,70 @@
+package org.bukkit.craftbukkit;
+
+import java.util.Collection;
+import java.util.Date;
+import java.util.Set;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.Validate;
+
+import com.google.common.collect.ImmutableSet;
+
+import net.minecraft.server.BanEntry;
+import net.minecraft.server.BanList;
+
+public class CraftBanList implements org.bukkit.BanList {
+    private final BanList list;
+
+    public CraftBanList(BanList list){
+        this.list = list;
+    }
+
+    @Override
+    public org.bukkit.BanEntry getBanEntry(String target) {
+        Validate.notNull(target, "Target cannot be null");
+
+        if (!list.getEntries().containsKey(target)) {
+            return null;
+        }
+
+        return new CraftBanEntry((BanEntry) list.getEntries().get(target), list);
+    }
+
+    @Override
+    public org.bukkit.BanEntry addBan(String target, String reason, Date expires, String source) {
+        Validate.notNull(target, "Ban target cannot be null");
+
+        BanEntry entry = new BanEntry(target);
+        entry.setSource(StringUtils.isBlank(source) ? entry.getSource() : source); // Use default if null/empty
+        entry.setExpires(expires); // Null values are interpreted as "forever"
+        entry.setReason(StringUtils.isBlank(reason) ? entry.getReason() : reason); // Use default if null/empty
+
+        list.add(entry);
+        list.save();
+        return new CraftBanEntry(entry, list);
+    }
+
+    @Override
+    public Set<org.bukkit.BanEntry> getBanEntries() {
+        ImmutableSet.Builder<org.bukkit.BanEntry> builder = ImmutableSet.builder();
+        for (BanEntry entry : (Collection<BanEntry>) list.getEntries().values()) {
+            builder.add(new CraftBanEntry(entry, list));
+        }
+        return builder.build();
+    }
+
+    @Override
+    public boolean isBanned(String target) {
+        Validate.notNull(target, "Target cannot be null");
+
+        return list.isBanned(target);
+    }
+
+    @Override
+    public void pardon(String target) {
+        Validate.notNull(target, "Target cannot be null");
+
+        list.remove(target);
+    }
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
index 2d730a7bd8..36bcfef321 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftOfflinePlayer.java
@@ -10,6 +10,7 @@ import net.minecraft.server.EntityPlayer;
 import net.minecraft.server.NBTTagCompound;
 import net.minecraft.server.WorldNBTStorage;
 
+import org.bukkit.BanList;
 import org.bukkit.Bukkit;
 import org.bukkit.Location;
 import org.bukkit.OfflinePlayer;
@@ -59,18 +60,15 @@ public class CraftOfflinePlayer implements OfflinePlayer, ConfigurationSerializa
     }
 
     public boolean isBanned() {
-        return server.getHandle().getNameBans().isBanned(name.toLowerCase());
+        return server.getBanList(BanList.Type.NAME).isBanned(getName());
     }
 
     public void setBanned(boolean value) {
         if (value) {
-            BanEntry entry = new BanEntry(name.toLowerCase());
-            server.getHandle().getNameBans().add(entry);
+            server.getBanList(BanList.Type.NAME).addBan(getName(), null, null, null);
         } else {
-            server.getHandle().getNameBans().remove(name.toLowerCase());
+            server.getBanList(BanList.Type.NAME).pardon(getName());
         }
-
-        server.getHandle().getNameBans().save();
     }
 
     public boolean isWhitelisted() {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index d27ab8c132..17c8039b78 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -56,6 +56,7 @@ import net.minecraft.util.io.netty.buffer.ByteBufOutputStream;
 import net.minecraft.util.io.netty.buffer.Unpooled;
 import net.minecraft.util.io.netty.handler.codec.base64.Base64;
 
+import org.bukkit.BanList;
 import org.bukkit.Bukkit;
 import org.bukkit.ChatColor;
 import org.bukkit.GameMode;
@@ -129,12 +130,11 @@ import org.bukkit.plugin.messaging.StandardMessenger;
 import org.bukkit.scheduler.BukkitWorker;
 import org.bukkit.util.StringUtil;
 import org.bukkit.util.permissions.DefaultPermissions;
-
 import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.SafeConstructor;
 import org.yaml.snakeyaml.error.MarkedYAMLException;
-
 import org.apache.commons.lang.Validate;
+
 import com.avaje.ebean.config.DataSourceConfig;
 import com.avaje.ebean.config.ServerConfig;
 import com.avaje.ebean.config.dbplatform.SQLitePlatform;
@@ -1139,20 +1139,19 @@ public final class CraftServer implements Server {
 
     @SuppressWarnings("unchecked")
     public Set<String> getIPBans() {
-        return playerList.getIPBans().getEntries().keySet();
+        return new HashSet<String>(playerList.getIPBans().getEntries().keySet());
     }
 
     public void banIP(String address) {
         Validate.notNull(address, "Address cannot be null.");
 
-        BanEntry entry = new BanEntry(address);
-        playerList.getIPBans().add(entry);
-        playerList.getIPBans().save();
+        this.getBanList(org.bukkit.BanList.Type.IP).addBan(address, null, null, null);
     }
 
     public void unbanIP(String address) {
-        playerList.getIPBans().remove(address);
-        playerList.getIPBans().save();
+        Validate.notNull(address, "Address cannot be null.");
+
+        this.getBanList(org.bukkit.BanList.Type.IP).pardon(address);
     }
 
     public Set<OfflinePlayer> getBannedPlayers() {
@@ -1165,6 +1164,19 @@ public final class CraftServer implements Server {
         return result;
     }
 
+    @Override
+    public BanList getBanList(BanList.Type type){
+        Validate.notNull(type, "Type cannot be null");
+
+        switch(type){
+        case IP:
+            return new CraftBanList(playerList.getIPBans());
+        case NAME:
+        default: // Fall through as a player name list for safety
+            return new CraftBanList(playerList.getNameBans());
+        }
+    }
+
     public void setWhitelist(boolean value) {
         playerList.hasWhitelist = value;
         console.getPropertyManager().a("white-list", value);
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 9935e7a4c2..60b0435ebd 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -22,6 +22,7 @@ import org.apache.commons.lang.Validate;
 import org.apache.commons.lang.NotImplementedException;
 import org.bukkit.*;
 import org.bukkit.Achievement;
+import org.bukkit.BanList;
 import org.bukkit.Statistic;
 import org.bukkit.Material;
 import org.bukkit.Statistic.Type;
@@ -709,19 +710,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
 
     @Override
     public boolean isBanned() {
-        return server.getHandle().getNameBans().isBanned(getName().toLowerCase());
+        return server.getBanList(BanList.Type.NAME).isBanned(getName());
     }
 
     @Override
     public void setBanned(boolean value) {
         if (value) {
-            BanEntry entry = new BanEntry(getName().toLowerCase());
-            server.getHandle().getNameBans().add(entry);
+            server.getBanList(BanList.Type.NAME).addBan(getName(), null, null, null);
         } else {
-            server.getHandle().getNameBans().remove(getName().toLowerCase());
+            server.getBanList(BanList.Type.NAME).pardon(getName());
         }
-
-        server.getHandle().getNameBans().save();
     }
 
     @Override