$ PYTHONPATH=. python quantum/cli.py -v create_net $TENANT network1
Created a new Virtual Network with ID:e754e7c0-a8eb-40e5-861a-b182d30c3441
+# -- Authentication and Authorization
+
+Requests to Quantum API are authenticated with the Keystone identity service
+using a token-based authentication protocol.
+
+A user should first authenticate with Keystone, supplying user credentials;
+the Keystone service will return an authentication token, together with
+informations concerning token expirations and endpoint where that token can
+be used.
+
+The authentication token must be included in every request for the Quantum
+API, in the 'X_AUTH_TOKEN' header. Quantum will look for the authentication
+token in this header, and validate it with the Keystone service.
+
+In order to validate authentication tokens, Quantum uses Keystone's
+administrative API. It therefore requires credentials for an administrative
+user, which can be specified in Quantum's configuration file
+(etc/quantum.conf)
+Either username and password, or an authentication token for an administrative
+user can be specified in the configuration file:
+
+- Credentials:
+
+admin_user = admin
+admin_password = secrete
+
+- Admin token:
+
+admin_token = 9a82c95a-99e9-4c3a-b5ee-199f6ba7ff04
+
+As of the current release, any user for a tenant is allowed to perform
+every operation on the networks owned by the tenant itself, except for
+plugging interfaces. In order to perform such operation, the user must have
+the Quantum:NetworkAdmin roles. Roles can be configured in Keystone using
+the administrative API.
+
+
# -- Writing your own Quantum plug-in
If you wish the write your own Quantum plugin, please refer to some concrete as
/v0.1: quantumapi
[pipeline:quantumapi]
-# To enable keystone integration comment the following line and
+# To disable keystone integration comment the following line and
# uncomment the next one
-pipeline = extensions quantumapiapp
-#pipeline = authN authZ extensions quantumapiapp
+pipeline = authN authZ extensions quantumapiapp
+#pipeline = extensions quantumapiapp
+
[filter:authN]
paste.filter_factory = quantum.common.authentication:filter_factory
def _reject_request(self):
"""Redirect client to auth server"""
- return HTTPUseProxy(location=self.auth_location)(self.env,
- self.start_response)
+ return HTTPUnauthorized()(self.env, self.start_response)
def _reject_claims(self):
"""Client sent bad claims"""
- return HTTPUnauthorized()(self.env,
- self.start_response)
+ return HTTPUnauthorized()(self.env, self.start_response)
def _validate_claims(self, claims):
"""Validate claims, and provide identity information if applicable """
from webob.exc import HTTPUnauthorized, HTTPForbidden
LOG = logging.getLogger('quantum.common.authorization')
+TENANT_HEADER = "HTTP_X_TENANT"
+ROLE_HEADER = "HTTP_X_ROLE"
+ADMIN_ROLE = "Quantum:NetworkAdmin"
#TODO(salvatore-orlando): This class should extend Middleware class
# should already have been authenticated with Keystone
self.headers = req.copy()
LOG.debug("Looking for X_TENANT header")
- LOG.debug("Headers:%s" % self.headers)
- if not "HTTP_X_TENANT" in self.headers:
+ if not TENANT_HEADER in self.headers:
# This is bad, very bad
return self._reject()
- LOG.debug("X_TENANT header found:%s", self.headers['HTTP_X_TENANT'])
- auth_tenant_id = self.headers['HTTP_X_TENANT']
+ LOG.debug("X_TENANT header found:%s", self.headers[TENANT_HEADER])
+ auth_tenant_id = self.headers[TENANT_HEADER]
path = self.req['PATH_INFO']
parts = path.split('/')
LOG.debug("Request parts:%s", parts)
if auth_tenant_id != req_tenant_id:
# This is bad, very bad
return self._forbid()
-
+ # Are you trying to operate on an attachment?
+ # If yes, you must be Quantum:NetworkAdmin
+ if parts[len(parts) - 1] == "attachment":
+ LOG.debug("Looking for X_ROLE header")
+ LOG.debug("Headers:%s", self.headers)
+ if not ROLE_HEADER in self.headers:
+ #This is bad as you definetely are not an administrator
+ return self._forbid()
+ LOG.debug("X_ROLE header found:%s", self.headers[ROLE_HEADER])
+ roles = self.headers[ROLE_HEADER].split(',')
+ if not ADMIN_ROLE in roles:
+ # Sorry, you're not and admin
+ return self._forbid()
# Okay, authorize it - pass downstream
return self.app(self.req, self.start_response)