diff --git src/java/org/apache/hadoop/ipc/Server.java src/java/org/apache/hadoop/ipc/Server.java
index 8905698..4fc93c4 100644
--- src/java/org/apache/hadoop/ipc/Server.java
+++ src/java/org/apache/hadoop/ipc/Server.java
@@ -893,8 +893,9 @@ public abstract class Server {
       }
       
       // TODO: Get the user name from the GSS API for Kerberbos-based security
-      // Create the user subject
-      user = SecurityUtil.getSubject(header.getUgi());
+      // Create the user subject; however use the groups as defined on the
+      // server-side, don't trust the user groups provided by the client
+      user = SecurityUtil.getSubject(header.getUgi().getUserName());
     }
     
     private void processData() throws  IOException, InterruptedException {
diff --git src/java/org/apache/hadoop/security/GroupMappingServiceImpl.java src/java/org/apache/hadoop/security/GroupMappingServiceImpl.java
new file mode 100644
index 0000000..172a07a
--- /dev/null
+++ src/java/org/apache/hadoop/security/GroupMappingServiceImpl.java
@@ -0,0 +1,36 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.security;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * An abstraction for the implementation of a user-to-groups mapping service
+ * used by {@link Groups}.
+ */
+abstract class GroupMappingServiceImpl {
+  
+  /**
+   * Get all various {@link Group} memberships of a given {@link User}.
+   * @param user <code>User</code> name
+   * @return <code>Group</code> memberships of <code>user</code>
+   * @throws IOException
+   */
+  public abstract List<String> getGroups(String user) throws IOException;
+}
diff --git src/java/org/apache/hadoop/security/Groups.java src/java/org/apache/hadoop/security/Groups.java
new file mode 100644
index 0000000..d4ab302
--- /dev/null
+++ src/java/org/apache/hadoop/security/Groups.java
@@ -0,0 +1,123 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.security;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.util.ReflectionUtils;
+
+/**
+ * A user-to-groups mapping service.
+ * 
+ * {@link Groups} allows for server to get the various {@link Group} memberships
+ * of a given {@link User} via the {@link #getGroups(String)} call, thus ensuring 
+ * a consistent user-to-groups mapping and protects against vagaries of different 
+ * mappings on servers and clients in a Hadoop cluster. 
+ */
+public class Groups {
+  private static final Log LOG = LogFactory.getLog(Groups.class);
+  
+  private final GroupMappingServiceImpl impl;
+  
+  private final Map<String, CachedGroups> userToGroupsMap = 
+    new ConcurrentHashMap<String, CachedGroups>();
+
+  public Groups(Configuration conf) {
+    impl = 
+      ReflectionUtils.newInstance(conf.getClass("hadoop.security.group.mapping", 
+                                                ShellBasedUnixGroupsMapping.class, 
+                                                GroupMappingServiceImpl.class), 
+                                  conf);
+    
+    // Start the timer thread to purge stale user-to-groups mappings
+    final long cacheTimeout = 
+      conf.getLong("hadoop.security.groups.cache.mins", 5) * 60 * 1000;
+    Timer timer = 
+      new Timer("Timer thread for purging stale user-to-groups mappings.", true);
+    TimerTask task = new TimerTask() {
+      @Override
+      public void run() {
+        long now = System.currentTimeMillis();
+        for (Iterator<Map.Entry<String, CachedGroups>> iter = 
+               userToGroupsMap.entrySet().iterator();
+             iter.hasNext();) {
+          Map.Entry<String, CachedGroups> entry = iter.next();
+          if (entry.getValue().getTimestamp() + cacheTimeout < now) {
+            iter.remove();
+          }
+        }
+      }
+    };
+    timer.schedule(task, cacheTimeout, cacheTimeout);
+  }
+  
+  /**
+   * Get the {@link Group} memberships of a given {@link User}.
+   * @param user <code>User</code> name
+   * @return the <code>Group</code> memberships of <code>user</code>
+   * @throws IOException
+   */
+  public List<String> getGroups(String user) throws IOException {
+    // Return cached value if available
+    CachedGroups groups = userToGroupsMap.get(user);
+    if (groups != null) {
+      LOG.info("Returning cached groups for '" + user + "'");
+      return groups.getGroups();
+    }
+    
+    // Create and cache user's groups
+    groups = new CachedGroups(impl.getGroups(user));
+    userToGroupsMap.put(user, groups);
+    LOG.info("Returning fetched groups for '" + user + "'");
+    return groups.getGroups();
+  }
+  
+  /**
+   * Refresh all user-to-groups mappings.
+   */
+  public void refresh() {
+    userToGroupsMap.clear();
+  }
+  
+  private static class CachedGroups {
+    final long timestamp;
+    final List<String> groups;
+    
+    CachedGroups(List<String> groups) {
+      this.groups = groups;
+      this.timestamp = System.currentTimeMillis();
+    }
+
+    public long getTimestamp() {
+      return timestamp;
+    }
+
+    public List<String> getGroups() {
+      return groups;
+    }
+  }
+}
diff --git src/java/org/apache/hadoop/security/RefreshUserToGroupMappingsProtocol.java src/java/org/apache/hadoop/security/RefreshUserToGroupMappingsProtocol.java
new file mode 100644
index 0000000..b9816cf
--- /dev/null
+++ src/java/org/apache/hadoop/security/RefreshUserToGroupMappingsProtocol.java
@@ -0,0 +1,41 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.security;
+
+import java.io.IOException;
+
+import org.apache.hadoop.ipc.VersionedProtocol;
+
+/**
+ * Protocol use 
+ * @author arunc
+ *
+ */
+public interface RefreshUserToGroupMappingsProtocol extends VersionedProtocol {
+  
+  /**
+   * Version 1: Initial version.
+   */
+  public static final long versionID = 1L;
+
+  /**
+   * Refresh {@link User} to {@link Group} mappings.
+   * @throws IOException
+   */
+  public void refreshUserToGroupsMappings() throws IOException;
+}
diff --git src/java/org/apache/hadoop/security/SecurityUtil.java src/java/org/apache/hadoop/security/SecurityUtil.java
index 94b6825..d8a341b 100644
--- src/java/org/apache/hadoop/security/SecurityUtil.java
+++ src/java/org/apache/hadoop/security/SecurityUtil.java
@@ -17,9 +17,11 @@
  */
 package org.apache.hadoop.security;
 
+import java.io.IOException;
 import java.security.Policy;
 import java.security.Principal;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
 
@@ -41,6 +43,8 @@ public class SecurityUtil {
                                    PolicyProvider.DEFAULT_POLICY_PROVIDER));
   }
   
+  private static Groups GROUPS = new Groups(new Configuration());
+  
   /**
    * Set the global security policy for Hadoop.
    * 
@@ -62,6 +66,14 @@ public class SecurityUtil {
   }
   
   /**
+   * Get the {@link Groups} being used to map user-to-groups.
+   * @return the <code>Groups</code> being used to map user-to-groups.
+   */
+  public static Groups getUserToGroupsMappingService() {
+    return GROUPS;
+  }
+  
+  /**
    * Get the {@link Subject} for the user identified by <code>ugi</code>.
    * @param ugi user
    * @return the {@link Subject} for the user identified by <code>ugi</code>
@@ -87,6 +99,43 @@ public class SecurityUtil {
   }
   
   /**
+   * Get the {@link Subject} for the user identified by <code>userName</code>.
+   * @param userName user name
+   * @return the {@link Subject} for the user identified by <code>userName</code>
+   * @throws IOException
+   */
+  public static Subject getSubject(String userName) throws IOException {
+    if (userName == null) {
+      return null;
+    }
+    
+    Set<Principal> principals = new HashSet<Principal>();
+    User userPrincipal = new User(userName); 
+    principals.add(userPrincipal);
+    
+    // Get user's groups
+    List<String> groups = GROUPS.getGroups(userName);
+    StringBuffer sb = new StringBuffer("Groups for '" + userName + "': <");
+    for (String group : groups) {
+      Group groupPrincipal = new Group(group);
+      principals.add(groupPrincipal);
+      sb.append(group + " ");
+    }
+    sb.append(">");
+    LOG.info(sb);
+    
+    // Create the ugi with the right groups
+    UserGroupInformation ugi = 
+      new UnixUserGroupInformation(userName, 
+                                   groups.toArray(new String[groups.size()]));
+    principals.add(ugi);
+    Subject user = 
+      new Subject(false, principals, new HashSet<Object>(), new HashSet<Object>());
+    
+    return user;
+  }
+  
+  /**
    * Class representing a configured access control list.
    */
   public static class AccessControlList {
diff --git src/java/org/apache/hadoop/security/ShellBasedUnixGroupsMapping.java src/java/org/apache/hadoop/security/ShellBasedUnixGroupsMapping.java
new file mode 100644
index 0000000..9877953
--- /dev/null
+++ src/java/org/apache/hadoop/security/ShellBasedUnixGroupsMapping.java
@@ -0,0 +1,64 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 org.apache.hadoop.security;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.hadoop.util.Shell;
+
+/**
+ * A simple shell-based implementation of {@link GroupMappingServiceImpl} which
+ * exec's the <code>groups</code> shell command to fetch the {@link Group}
+ * memberships of a given {@link User}.
+ */
+class ShellBasedUnixGroupsMapping extends GroupMappingServiceImpl {
+  Map<String, List<String>> userGroups = 
+    new ConcurrentHashMap<String, List<String>>();
+  
+  @Override
+  public List<String> getGroups(String user) throws IOException {
+    List<String> groups = userGroups.get(user);
+    if (groups == null) {
+      groups = getUnixGroups(user);
+      userGroups.put(user, groups);
+    }
+    return groups;
+  }
+
+  /** 
+   * Get the current user's group list from Unix by running the command 'groups'
+   * 
+   * @param user user name
+   * @return the groups list that the <code>user</code> belongs to
+   * @throws IOException if encounter any error when running the command
+   */
+  private static List<String> getUnixGroups(final String user) throws IOException {
+    String result = Shell.execCommand(Shell.getGROUPS_FOR_USER_COMMAND(user));
+    StringTokenizer tokenizer = new StringTokenizer(result);
+    List<String> groups = new LinkedList<String>();
+    while (tokenizer.hasMoreTokens()) {
+      groups.add(tokenizer.nextToken());
+    }
+    return groups;
+  }
+}
diff --git src/java/org/apache/hadoop/util/Shell.java src/java/org/apache/hadoop/util/Shell.java
index f9e176a..9570524 100644
--- src/java/org/apache/hadoop/util/Shell.java
+++ src/java/org/apache/hadoop/util/Shell.java
@@ -47,6 +47,10 @@ abstract public class Shell {
   public static String[] getGROUPS_COMMAND() {
     return new String[]{"bash", "-c", "groups"};
   }
+  /** a Unix command to get a given user's groups list */
+  public static String[] getGROUPS_FOR_USER_COMMAND(final String user) {
+    return new String[]{"bash", "-c", "groups " + user};
+  }
   /** a Unix command to set permission */
   public static final String SET_PERMISSION_COMMAND = "chmod";
   /** a Unix command to set owner */
