diff --git a/novaclient/keystone/shell.py b/novaclient/keystone/shell.py
new file mode 100644
index 000000000..18299cd61
--- /dev/null
+++ b/novaclient/keystone/shell.py
@@ -0,0 +1,99 @@
+# Copyright 2010 Jacob Kaplan-Moss
+
+# Copyright 2011 OpenStack LLC.
+# All Rights Reserved.
+#
+#    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://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.
+
+import httplib2
+import urllib
+import urlparse
+
+try:
+    import json
+except ImportError:
+    import simplejson as json
+
+# Python 2.5 compat fix
+if not hasattr(urlparse, 'parse_qsl'):
+    import cgi
+    urlparse.parse_qsl = cgi.parse_qsl
+
+
+from novaclient import exceptions
+from novaclient import utils
+from novaclient import client
+
+
+@utils.unauthenticated
+def do_discover(cs, args):
+    """
+    Discover Keystone servers and show authentication protocols supported.
+
+    Usage:
+    $ nova discover
+    Keystone found at http://localhost:35357
+        - supports version v2.0 (beta) here http://localhost:35357/v2.0
+    Keystone found at https://openstack.org/
+        - supports version v1.0 (DEPRECATED) here https://openstack.org/v1.0
+        - supports version v1.1 (CURRENT) here https://openstack.org/v1.1
+        - supports version v2.0 (BETA) here https://openstack.org/v2.0
+    """
+    _local_keystone_exists()
+    _check_keystone_versions(cs.client.auth_url)
+
+
+def _local_keystone_exists():
+    return _check_keystone_versions("http://localhost:35357")
+
+
+def _check_keystone_versions(url):
+    try:
+        httpclient = client.HTTPClient(user=None, password=None,
+                            projectid=None, auth_url=None)
+        resp, body = httpclient.request(url, "GET",
+                                  headers={'Accept': 'application/json'})
+        if resp.status in (200, 204):  # in some cases we get No Content
+            try:
+                print "Keystone found at %s" % url
+                if 'version' in body:
+                    version = body['version']
+                    # Stable/diablo incorrect format
+                    _display_version_info(version, url)
+                    return True
+                if 'versions' in body:
+                    # Correct format
+                    for version in body['versions']['values']:
+                        _display_version_info(version, url)
+                    return True
+                print "Unrecognized response from %s" % url
+            except KeyError:
+                raise exceptions.AuthorizationFailure()
+        elif resp.status == 305:
+            return _check_keystone_versions(resp['location'])
+        else:
+            raise exceptions.from_response(resp, body)
+    except:
+        return False
+
+
+def _display_version_info(version, url):
+    id = version['id']
+    status = version['status']
+    ref = urlparse.urljoin(url, id)
+    if 'links' in version:
+        for link in version['links']:
+            if link['rel'] == 'self':
+                ref = link['href']
+                break
+    print "    - supports version %s (%s) here %s" % (id, status, ref)
diff --git a/novaclient/shell.py b/novaclient/shell.py
index 989b6ef19..b46a174d9 100644
--- a/novaclient/shell.py
+++ b/novaclient/shell.py
@@ -29,6 +29,7 @@ from novaclient import base
 from novaclient import exceptions as exc
 from novaclient import utils
 from novaclient.v1_1 import shell as shell_v1_1
+from novaclient.keystone import shell as shell_keystone
 
 
 def env(*vars):
@@ -119,6 +120,7 @@ class OpenStackComputeShell(object):
             actions_module = shell_v1_1
 
         self._find_actions(subparsers, actions_module)
+        self._find_actions(subparsers, shell_keystone)
         self._find_actions(subparsers, self)
 
         for _, _, ext_module in extensions:
@@ -229,27 +231,39 @@ class OpenStackComputeShell(object):
         #FIXME(usrleon): Here should be restrict for project id same as
         # for username or password but for compatibility it is not.
 
-        if not user:
-            raise exc.CommandError("You must provide a username, either "
-                                   "via --username or via "
-                                   "env[OS_USER_NAME]")
+        if not utils.isunauthenticated(args.func):
+            if not user:
+                raise exc.CommandError("You must provide a username, either "
+                                       "via --username or via "
+                                       "env[NOVA_USERNAME]")
 
-        if not password:
-            if not apikey:
-                raise exc.CommandError("You must provide a password, either "
-                        "via --password or via env[OS_PASSWORD]")
-            else:
-                password = apikey
+            if not password:
+                if not apikey:
+                    raise exc.CommandError("You must provide a password, "
+                            "either via --password or via env[NOVA_PASSWORD]")
+                else:
+                    password = apikey
 
-        if not projectid:
-            raise exc.CommandError("You must provide an projectid, either "
-                                   "via --projectid or via "
-                                   "env[OS_TENANT_NAME]")
+            if not projectid:
+                raise exc.CommandError("You must provide an projectid, either "
+                                       "via --projectid or via "
+                                       "env[OS_TENANT_NAME]")
 
-        if not url:
-            raise exc.CommandError("You must provide a auth url, either "
-                                   "via --url or via "
-                                   "env[OS_AUTH_URL]")
+            if not url:
+                raise exc.CommandError("You must provide a auth url, either "
+                                       "via --url or via "
+                                       "env[OS_AUTH_URL]")
+
+        if options.version and options.version != '1.0':
+            if not projectid:
+                raise exc.CommandError("You must provide an projectid, "
+                                       "either via --projectid or via "
+                                       "env[NOVA_PROJECT_ID")
+
+            if not url:
+                raise exc.CommandError("You must provide a auth url,"
+                                       " either via --url or via "
+                                       "env[NOVA_URL")
 
         self.cs = self.get_api_class(options.version)(user, password,
                                      projectid, url, insecure,
@@ -258,7 +272,8 @@ class OpenStackComputeShell(object):
                                      extensions=extensions)
 
         try:
-            self.cs.authenticate()
+            if not utils.isunauthenticated(args.func):
+                self.cs.authenticate()
         except exc.Unauthorized:
             raise exc.CommandError("Invalid OpenStack Nova credentials.")
         except exc.AuthorizationFailure:
diff --git a/novaclient/utils.py b/novaclient/utils.py
index 083620add..9c6dbd079 100644
--- a/novaclient/utils.py
+++ b/novaclient/utils.py
@@ -15,6 +15,27 @@ def arg(*args, **kwargs):
     return _decorator
 
 
+def unauthenticated(f):
+    """
+    Adds 'unauthenticated' attribute to decorated function.
+    Usage:
+        @unauthenticated
+        def mymethod(f):
+            ...
+    """
+    f.unauthenticated = True
+    return f
+
+
+def isunauthenticated(f):
+    """
+    Checks to see if the function is marked as not requiring authentication
+    with the @unauthenticated decorator. Returns True if decorator is
+    set to True, False otherwise.
+    """
+    return getattr(f, 'unauthenticated', False)
+
+
 def pretty_choice_list(l):
     return ', '.join("'%s'" % i for i in l)
 
diff --git a/setup.py b/setup.py
index c209667d4..701295c33 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,8 @@ setuptools.setup(
     long_description=read_file("README.rst"),
     license="Apache License, Version 2.0",
     url="https://github.com/openstack/python-novaclient",
-    packages=["novaclient", "novaclient.v1_1", "novaclient.v1_1.contrib"],
+    packages=["novaclient", "novaclient.v1_1", "novaclient.v1_1.contrib",
+              "novaclient.keystone"],
     install_requires=requirements,
     tests_require=["nose", "mock"],
     test_suite="nose.collector",