Merge "Adding user_id handling to keypair index, show and create api calls"
This commit is contained in:
@@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.9",
|
||||
"version": "2.10",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
14
doc/v3/api_samples/keypairs/v2.10/keypairs-get-resp.json
Normal file
14
doc/v3/api_samples/keypairs/v2.10/keypairs-get-resp.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "44:fe:29:6e:23:14:b9:53:5b:65:82:58:1c:fe:5a:c3",
|
||||
"name": "keypair-6638abdb-c4e8-407c-ba88-c8dd7cc3c4f1",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1HTrHCbb9NawNLSV8N6tSa8i637+EC2dA+lsdHHfQlT54t+N0nHhJPlKWDLhc579j87vp6RDFriFJ/smsTnDnf64O12z0kBaJpJPH2zXrBkZFK6q2rmxydURzX/z0yLSCP77SFJ0fdXWH2hMsAusflGyryHGX20n+mZK6mDrxVzGxEz228dwQ5G7Az5OoZDWygH2pqPvKjkifRw0jwUKf3BbkP0QvANACOk26cv16mNFpFJfI1N3OC5lUsZQtKGR01ptJoWijYKccqhkAKuo902tg/qup58J5kflNm7I61sy1mJon6SGqNUSfoQagqtBH6vd/tU1jnlwZ03uUroAL Generated-by-Nova\n",
|
||||
"user_id": "fake",
|
||||
"deleted": false,
|
||||
"created_at": "2014-05-07T12:06:13.681238",
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"id": 1
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "keypair-d20a3d59-9433-4b79-8726-20b431d89c78",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "1e:2c:9b:56:79:4b:45:77:f9:ca:7a:98:2c:b0:d5:3c",
|
||||
"name": "keypair-803a1926-af78-4b05-902a-1d6f7a8d9d3e",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDx8nkQv/zgGgB4rMYmIf+6A4l6Rr+o/6lHBQdW5aYd44bd8JttDCE/F/pNRr0lRE+PiqSPO8nDPHw0010JeMH9gYgnnFlyY3/OcJ02RhIPyyxYpv9FhY+2YiUkpwFOcLImyrxEsYXpD/0d3ac30bNH6Sw9JD9UZHYcpSxsIbECHw== Generated-by-Nova",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
12
doc/v3/api_samples/keypairs/v2.10/keypairs-list-resp.json
Normal file
12
doc/v3/api_samples/keypairs/v2.10/keypairs-list-resp.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-50ca852e-273f-4cdc-8949-45feba200837",
|
||||
"type": "ssh",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
7
doc/v3/api_samples/keypairs/v2.10/keypairs-post-req.json
Normal file
7
doc/v3/api_samples/keypairs/v2.10/keypairs-post-req.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "keypair-ab9ff2e6-a6d7-4915-a241-044c369c07f9",
|
||||
"type": "ssh",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
10
doc/v3/api_samples/keypairs/v2.10/keypairs-post-resp.json
Normal file
10
doc/v3/api_samples/keypairs/v2.10/keypairs-post-resp.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "7e:eb:ab:24:ba:d1:e1:88:ae:9a:fb:66:53:df:d3:bd",
|
||||
"name": "keypair-ab9ff2e6-a6d7-4915-a241-044c369c07f9",
|
||||
"type": "ssh",
|
||||
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEApBdzF+fTq5QbN3R+QlO5TZr6W64GcUqcho5ZxPBZZIq53P1K\ndtpaY856ManqEwME1tN+JOw8+mmCK2RpkMHtk5BNPOMqr5Y+OQ5MqI/eX1v7GWnJ\ntHGTbi+vRDmxBh3aa3xiUGo66c9tjUKAg/ExQfFr/vKJvTR/S3urPlj3vfFgu+yi\n8PKoH0LGyHsviWsD1peDuu2XS+ca8qbkY3yD1o4Mv1R/OSF4P2fxjjWdp8R4EkoT\nJMKkhRAgAuS9zxwftPv9djP4opHWrRUlRo6bh75CzrN6Hu5uh5Tn5bkifOQcy1gW\n772vd6pBpi4OGQHPKz4djvmCLAVBzSyzDP6EKQIDAQABAoIBAQCB+tU/ZXKlIe+h\nMNTmoz1QfOe+AY625Rwx9cakGqMk4kKyC62VkgcxshfXCToSjzyhEuyEQOFYloT2\n7FY2xXb0gcS861Efv0pQlcQhbbz/GnQ/wC13ktPu3zTdPTm9l54xsFiMTGmYVaf4\n0mnMmhyjmKIsVGDJEDGZUD/oZj7wJGOFha5M4FZrZlJIrEZC0rGGlcC0kGF2no6B\nj1Mu7HjyK3pTKf4dlp+jeRikUF5Pct+qT+rcv2rZ3fl3inxtlLEwZeFPbp/njf/U\nIGxFzZsuLmiFlsJar6M5nEckTB3p25maWWaR8/0jvJRgsPnuoUrUoGDq87DMKCdk\nlw6by9fRAoGBANhnS9ko7Of+ntqIFR7xOG9p/oPATztgHkFxe4GbQ0leaDRTx3vE\ndQmUCnn24xtyVECaI9a4IV+LP1npw8niWUJ4pjgdAlkF4cCTu9sN+cBO15SfdACI\nzD1DaaHmpFCAWlpTo68VWlvWll6i2ncCkRJR1+q/C/yQz7asvl4AakElAoGBAMId\nxqMT2Sy9xLuHsrAoMUvBOkwaMYZH+IAb4DvUDjVIiKWjmonrmopS5Lpb+ALBKqZe\neVfD6HwWQqGwCFItToaEkZvrNfTapoNCHWWg001D49765UV5lMrArDbM1vXtFfM4\nDRYM6+Y6o/6QH8EBgXtyBxcYthIDBM3wBJa67xG1AoGAKTm8fFlMkIG0N4N3Kpbf\nnnH915GaRoBwIx2AXtd6QQ7oIRfYx95MQY/fUw7SgxcLr+btbulTCkWXwwRClUI2\nqPAdElGMcfMp56r9PaTy8EzUyu55heSJrB4ckIhEw0VAcTa/1wnlVduSd+LkZYmq\no2fOD11n5iycNXvBJF1F4LUCgYAMaRbwCi7SW3eefbiA5rDwJPRzNSGBckyC9EVL\nzezynyaNYH5a3wNMYKxa9dJPasYtSND9OXs9o7ay26xMhLUGiKc+jrUuaGRI9Asp\nGjUoNXT2JphN7s4CgHsCLep4YqYKnMTJah4S5CDj/5boIg6DM/EcGupZEHRYLkY8\n1MrAGQKBgQCi9yeC39ctLUNn+Ix604gttWWChdt3ozufTZ7HybJOSRA9Gh3iD5gm\nzlz0xqpGShKpOY2k+ftvja0poMdGeJLt84P3r2q01IgI7w0LmOj5m0W10dHysH27\nBWpCnHdBJMxnBsMRPoM4MKkmKWD9l5PSTCTWtkIpsyuDCko6D9UwZA==\n-----END RSA PRIVATE KEY-----\n",
|
||||
"public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCkF3MX59OrlBs3dH5CU7lNmvpbrgZxSpyGjlnE8Flkirnc/Up22lpjznoxqeoTAwTW034k7Dz6aYIrZGmQwe2TkE084yqvlj45Dkyoj95fW/sZacm0cZNuL69EObEGHdprfGJQajrpz22NQoCD8TFB8Wv+8om9NH9Le6s+WPe98WC77KLw8qgfQsbIey+JawPWl4O67ZdL5xrypuRjfIPWjgy/VH85IXg/Z/GONZ2nxHgSShMkwqSFECAC5L3PHB+0+/12M/iikdatFSVGjpuHvkLOs3oe7m6HlOfluSJ85BzLWBbvva93qkGmLg4ZAc8rPh2O+YIsBUHNLLMM/oQp Generated-by-Nova\n",
|
||||
"user_id": "fake"
|
||||
}
|
||||
}
|
@@ -302,10 +302,10 @@
|
||||
"os_compute_api:ips:show": "rule:admin_or_owner",
|
||||
"os_compute_api:os-keypairs:discoverable": "",
|
||||
"os_compute_api:os-keypairs": "",
|
||||
"os_compute_api:os-keypairs:index": "",
|
||||
"os_compute_api:os-keypairs:show": "",
|
||||
"os_compute_api:os-keypairs:create": "",
|
||||
"os_compute_api:os-keypairs:delete": "",
|
||||
"os_compute_api:os-keypairs:index": "rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:show": "rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:create": "rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:delete": "rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:limits:discoverable": "",
|
||||
"os_compute_api:limits": "",
|
||||
"os_compute_api:os-lock-server:discoverable": "",
|
||||
|
@@ -48,6 +48,8 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
* 2.7 - Check flavor type before add tenant access.
|
||||
* 2.8 - Add new protocol for VM console (mks)
|
||||
* 2.9 - Exposes lock information in server details.
|
||||
* 2.10 - Allow admins to query, create and delete keypairs owned by any
|
||||
user.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@@ -56,7 +58,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
_MIN_API_VERSION = "2.1"
|
||||
_MAX_API_VERSION = "2.9"
|
||||
_MAX_API_VERSION = "2.10"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@@ -51,7 +51,26 @@ class KeypairController(wsgi.Controller):
|
||||
clean[attr] = keypair[attr]
|
||||
return clean
|
||||
|
||||
@wsgi.Controller.api_version("2.2")
|
||||
@wsgi.Controller.api_version("2.10")
|
||||
@wsgi.response(201)
|
||||
@extensions.expected_errors((400, 403, 409))
|
||||
@validation.schema(keypairs.create_v210)
|
||||
def create(self, req, body):
|
||||
"""Create or import keypair.
|
||||
|
||||
A policy check restricts users from creating keys for other users
|
||||
|
||||
params: keypair object with:
|
||||
name (required) - string
|
||||
public_key (optional) - string
|
||||
type (optional) - string
|
||||
user_id (optional) - string
|
||||
"""
|
||||
# handle optional user-id for admin only
|
||||
user_id = body['keypair'].get('user_id')
|
||||
return self._create(req, body, type=True, user_id=user_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.2", "2.9") # noqa
|
||||
@wsgi.response(201)
|
||||
@extensions.expected_errors((400, 403, 409))
|
||||
@validation.schema(keypairs.create_v22)
|
||||
@@ -89,24 +108,26 @@ class KeypairController(wsgi.Controller):
|
||||
"""
|
||||
return self._create(req, body)
|
||||
|
||||
def _create(self, req, body, **keypair_filters):
|
||||
def _create(self, req, body, user_id=None, **keypair_filters):
|
||||
context = req.environ['nova.context']
|
||||
authorize(context, action='create')
|
||||
|
||||
params = body['keypair']
|
||||
name = params['name']
|
||||
key_type = params.get('type', keypair_obj.KEYPAIR_TYPE_SSH)
|
||||
user_id = user_id or context.user_id
|
||||
authorize(context, action='create',
|
||||
target={'user_id': user_id,
|
||||
'project_id': context.project_id})
|
||||
|
||||
try:
|
||||
if 'public_key' in params:
|
||||
keypair = self.api.import_key_pair(context,
|
||||
context.user_id, name,
|
||||
user_id, name,
|
||||
params['public_key'], key_type)
|
||||
keypair = self._filter_keypair(keypair, user_id=True,
|
||||
**keypair_filters)
|
||||
else:
|
||||
keypair, private_key = self.api.create_key_pair(
|
||||
context, context.user_id, name, key_type)
|
||||
context, user_id, name, key_type)
|
||||
keypair = self._filter_keypair(keypair, user_id=True,
|
||||
**keypair_filters)
|
||||
keypair['private_key'] = private_key
|
||||
@@ -127,22 +148,46 @@ class KeypairController(wsgi.Controller):
|
||||
def delete(self, req, id):
|
||||
self._delete(req, id)
|
||||
|
||||
@wsgi.Controller.api_version("2.2") # noqa
|
||||
@wsgi.Controller.api_version("2.2", "2.9") # noqa
|
||||
@wsgi.response(204)
|
||||
@extensions.expected_errors(404)
|
||||
def delete(self, req, id):
|
||||
self._delete(req, id)
|
||||
|
||||
def _delete(self, req, id):
|
||||
@wsgi.Controller.api_version("2.10") # noqa
|
||||
@wsgi.response(204)
|
||||
@extensions.expected_errors(404)
|
||||
def delete(self, req, id):
|
||||
# handle optional user-id for admin only
|
||||
user_id = self._get_user_id(req)
|
||||
self._delete(req, id, user_id=user_id)
|
||||
|
||||
def _delete(self, req, id, user_id=None):
|
||||
"""Delete a keypair with a given name."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context, action='delete')
|
||||
# handle optional user-id for admin only
|
||||
user_id = user_id or context.user_id
|
||||
authorize(context, action='delete',
|
||||
target={'user_id': user_id,
|
||||
'project_id': context.project_id})
|
||||
try:
|
||||
self.api.delete_key_pair(context, context.user_id, id)
|
||||
self.api.delete_key_pair(context, user_id, id)
|
||||
except exception.KeypairNotFound as exc:
|
||||
raise webob.exc.HTTPNotFound(explanation=exc.format_message())
|
||||
|
||||
@wsgi.Controller.api_version("2.2")
|
||||
def _get_user_id(self, req):
|
||||
if 'user_id' in req.GET.keys():
|
||||
user_id = req.GET.getall('user_id')[0]
|
||||
return user_id
|
||||
|
||||
@wsgi.Controller.api_version("2.10")
|
||||
@extensions.expected_errors(404)
|
||||
def show(self, req, id):
|
||||
# handle optional user-id for admin only
|
||||
user_id = self._get_user_id(req)
|
||||
return self._show(req, id, type=True, user_id=user_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.2", "2.9") # noqa
|
||||
@extensions.expected_errors(404)
|
||||
def show(self, req, id):
|
||||
return self._show(req, id, type=True)
|
||||
@@ -152,15 +197,18 @@ class KeypairController(wsgi.Controller):
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
def _show(self, req, id, **keypair_filters):
|
||||
def _show(self, req, id, user_id=None, **keypair_filters):
|
||||
"""Return data for the given key name."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context, action='show')
|
||||
user_id = user_id or context.user_id
|
||||
authorize(context, action='show',
|
||||
target={'user_id': user_id,
|
||||
'project_id': context.project_id})
|
||||
|
||||
try:
|
||||
# The return object needs to be a dict in order to pop the 'type'
|
||||
# field, if the api_version < 2.2.
|
||||
keypair = self.api.get_key_pair(context, context.user_id, id)
|
||||
keypair = self.api.get_key_pair(context, user_id, id)
|
||||
keypair = self._filter_keypair(keypair, created_at=True,
|
||||
deleted=True, deleted_at=True,
|
||||
id=True, user_id=True,
|
||||
@@ -172,7 +220,14 @@ class KeypairController(wsgi.Controller):
|
||||
# behaviors in this keypair resource.
|
||||
return {'keypair': keypair}
|
||||
|
||||
@wsgi.Controller.api_version("2.2")
|
||||
@wsgi.Controller.api_version("2.10")
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req):
|
||||
# handle optional user-id for admin only
|
||||
user_id = self._get_user_id(req)
|
||||
return self._index(req, type=True, user_id=user_id)
|
||||
|
||||
@wsgi.Controller.api_version("2.2", "2.9") # noqa
|
||||
@extensions.expected_errors(())
|
||||
def index(self, req):
|
||||
return self._index(req, type=True)
|
||||
@@ -182,11 +237,14 @@ class KeypairController(wsgi.Controller):
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
def _index(self, req, **keypair_filters):
|
||||
def _index(self, req, user_id=None, **keypair_filters):
|
||||
"""List of keypairs for a user."""
|
||||
context = req.environ['nova.context']
|
||||
authorize(context, action='index')
|
||||
key_pairs = self.api.get_key_pairs(context, context.user_id)
|
||||
user_id = user_id or context.user_id
|
||||
authorize(context, action='index',
|
||||
target={'user_id': user_id,
|
||||
'project_id': context.project_id})
|
||||
key_pairs = self.api.get_key_pairs(context, user_id)
|
||||
rval = []
|
||||
for key_pair in key_pairs:
|
||||
rval.append({'keypair': self._filter_keypair(key_pair,
|
||||
|
@@ -53,6 +53,28 @@ create_v22 = {
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
create_v210 = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'keypair': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'name': parameter_types.name,
|
||||
'type': {
|
||||
'type': 'string',
|
||||
'enum': ['ssh', 'x509']
|
||||
},
|
||||
'public_key': {'type': 'string'},
|
||||
'user_id': {'type': 'string'},
|
||||
},
|
||||
'required': ['name'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['keypair'],
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
server_create = {
|
||||
'key_name': parameter_types.name,
|
||||
}
|
||||
|
@@ -107,3 +107,13 @@ user documentation.
|
||||
Add a new ``locked`` attribute to the detailed view of
|
||||
servers. ``locked`` will be ``true`` if anyone is currently holding
|
||||
a lock on the server, ``false`` otherwise.
|
||||
|
||||
2.10
|
||||
---
|
||||
|
||||
Added user_id parameter to os-keypairs plugin, as well as a new property
|
||||
in the request body, for the create operation.
|
||||
|
||||
Administrators will be able to list, get details and delete keypairs owned by
|
||||
users other than themselves and to create new keypairs on behalf of their
|
||||
users.
|
||||
|
@@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.9",
|
||||
"version": "2.10",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@@ -304,6 +304,7 @@ class ApiSampleTestBase(integrated_helpers._IntegratedTestBase):
|
||||
'compute_host': self.compute.host,
|
||||
'text': text,
|
||||
'int': '[0-9]+',
|
||||
'user_id': text,
|
||||
}
|
||||
|
||||
def _get_response(self, url, method, body=None, strip_version=False,
|
||||
|
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"keypair": {
|
||||
"public_key": "%(public_key)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"user_id": "%(user_id)s",
|
||||
"deleted": false,
|
||||
"created_at": "%(strtime)s",
|
||||
"updated_at": null,
|
||||
"deleted_at": null,
|
||||
"id": 1
|
||||
}
|
||||
}
|
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"keypairs": [
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"public_key": "%(public_key)s"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"keypair": {
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"keypair": {
|
||||
"fingerprint": "%(fingerprint)s",
|
||||
"name": "%(keypair_name)s",
|
||||
"type": "%(keypair_type)s",
|
||||
"private_key": "%(private_key)s",
|
||||
"public_key": "%(public_key)s",
|
||||
"user_id": "%(user_id)s"
|
||||
}
|
||||
}
|
@@ -169,3 +169,66 @@ class KeyPairsV22SampleJsonTest(KeyPairsSampleJsonTest):
|
||||
def test_keypairs_import_key_post_invalid_combination(self):
|
||||
self._check_keypairs_import_key_post_invalid(
|
||||
keypair_type=keypair_obj.KEYPAIR_TYPE_X509)
|
||||
|
||||
|
||||
class KeyPairsV210SampleJsonTest(KeyPairsSampleJsonTest):
|
||||
ADMIN_API = True
|
||||
request_api_version = '2.10'
|
||||
expected_post_status_code = 201
|
||||
expected_delete_status_code = 204
|
||||
scenarios = [('v2_10', {})]
|
||||
_api_version = 'v2'
|
||||
|
||||
def test_keypair_create_for_user(self):
|
||||
subs = {
|
||||
'keypair_type': keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
'public_key': fake_crypto.get_ssh_public_key(),
|
||||
'user_id': "fake"
|
||||
}
|
||||
self._check_keypairs_post(**subs)
|
||||
|
||||
def test_keypairs_post(self):
|
||||
return self._check_keypairs_post(
|
||||
keypair_type=keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
user_id="admin")
|
||||
|
||||
def test_keypairs_import_key_post(self):
|
||||
# NOTE(claudiub): overrides the method with the same name in
|
||||
# KeypairsSampleJsonTest, since the API sample expects a keypair_type.
|
||||
public_key = fake_crypto.get_ssh_public_key()
|
||||
self._check_keypairs_import_key_post(
|
||||
public_key, keypair_type=keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
user_id="fake")
|
||||
|
||||
def test_keypairs_delete_for_user(self):
|
||||
# Delete a keypair on behalf of a user
|
||||
subs = {
|
||||
'keypair_type': keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
'public_key': fake_crypto.get_ssh_public_key(),
|
||||
'user_id': "fake"
|
||||
}
|
||||
key_name = self._check_keypairs_post(**subs)
|
||||
response = self._do_delete('os-keypairs/%s?user_id=fake' % key_name,
|
||||
api_version=self.request_api_version)
|
||||
self.assertEqual(self.expected_delete_status_code,
|
||||
response.status_code)
|
||||
|
||||
|
||||
class KeyPairsV210SampleJsonTestNotAdmin(KeyPairsV210SampleJsonTest):
|
||||
ADMIN_API = False
|
||||
|
||||
def test_keypairs_post(self):
|
||||
return self._check_keypairs_post(
|
||||
keypair_type=keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
user_id="fake")
|
||||
|
||||
def test_keypairs_post_for_other_user(self):
|
||||
key_name = 'keypair-' + str(uuid.uuid4())
|
||||
subs = dict(keypair_name=key_name,
|
||||
keypair_type=keypair_obj.KEYPAIR_TYPE_SSH,
|
||||
user_id='fake1')
|
||||
response = self._do_post('os-keypairs', 'keypairs-post-req', subs,
|
||||
api_version=self.request_api_version,
|
||||
)
|
||||
|
||||
self.assertEqual(403, response.status_code)
|
||||
|
@@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
from oslo_serialization import jsonutils
|
||||
import webob
|
||||
|
||||
@@ -399,6 +400,105 @@ class KeypairsTestV22(KeypairsTestV21):
|
||||
self.assertEqual('ssh', res_dict['keypair']['type'])
|
||||
|
||||
|
||||
class KeypairsTestV210(KeypairsTestV22):
|
||||
wsgi_api_version = '2.10'
|
||||
|
||||
def test_keypair_list_other_user(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs?user_id=foo',
|
||||
version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
with mock.patch.object(self.controller.api, 'get_key_pairs') as mock_g:
|
||||
self.controller.index(req)
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('foo', userid)
|
||||
|
||||
def test_keypair_list_other_user_not_admin(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs?user_id=foo',
|
||||
version=self.wsgi_api_version)
|
||||
with mock.patch.object(self.controller.api, 'get_key_pairs'):
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_keypair_show_other_user(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs/FAKE?user_id=foo',
|
||||
version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
with mock.patch.object(self.controller.api, 'get_key_pair') as mock_g:
|
||||
self.controller.show(req, 'FAKE')
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('foo', userid)
|
||||
|
||||
def test_keypair_show_other_user_not_admin(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs/FAKE?user_id=foo',
|
||||
version=self.wsgi_api_version)
|
||||
with mock.patch.object(self.controller.api, 'get_key_pair'):
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.controller.show, req, 'FAKE')
|
||||
|
||||
def test_keypair_delete_other_user(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs/FAKE?user_id=foo',
|
||||
version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
with mock.patch.object(self.controller.api,
|
||||
'delete_key_pair') as mock_g:
|
||||
self.controller.delete(req, 'FAKE')
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('foo', userid)
|
||||
|
||||
def test_keypair_delete_other_user_not_admin(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs/FAKE?user_id=foo',
|
||||
version=self.wsgi_api_version)
|
||||
with mock.patch.object(self.controller.api, 'delete_key_pair'):
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.controller.delete, req, 'FAKE')
|
||||
|
||||
def test_keypair_create_other_user(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs',
|
||||
version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
body = {'keypair': {'name': 'create_test',
|
||||
'user_id': '8861f37f-034e-4ca8-8abe-6d13c074574a'}}
|
||||
with mock.patch.object(self.controller.api,
|
||||
'create_key_pair',
|
||||
return_value=(mock.MagicMock(), 1)) as mock_g:
|
||||
res = self.controller.create(req, body=body)
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('8861f37f-034e-4ca8-8abe-6d13c074574a', userid)
|
||||
self.assertIn('keypair', res)
|
||||
|
||||
def test_keypair_import_other_user(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs',
|
||||
version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
body = {'keypair': {'name': 'create_test',
|
||||
'user_id': '8861f37f-034e-4ca8-8abe-6d13c074574a',
|
||||
'public_key': 'public_key'}}
|
||||
with mock.patch.object(self.controller.api,
|
||||
'import_key_pair') as mock_g:
|
||||
res = self.controller.create(req, body=body)
|
||||
userid = mock_g.call_args_list[0][0][1]
|
||||
self.assertEqual('8861f37f-034e-4ca8-8abe-6d13c074574a', userid)
|
||||
self.assertIn('keypair', res)
|
||||
|
||||
def test_keypair_create_other_user_not_admin(self):
|
||||
req = fakes.HTTPRequest.blank(self.base_url +
|
||||
'/os-keypairs',
|
||||
version=self.wsgi_api_version)
|
||||
body = {'keypair': {'name': 'create_test',
|
||||
'user_id': '8861f37f-034e-4ca8-8abe-6d13c074574a'}}
|
||||
self.assertRaises(exception.PolicyNotAuthorized,
|
||||
self.controller.create,
|
||||
req, body=body)
|
||||
|
||||
|
||||
class KeypairPolicyTestV2(KeypairPolicyTestV21):
|
||||
KeyPairController = keypairs_v2.KeypairController()
|
||||
policy_path = 'compute_extension:keypairs'
|
||||
|
@@ -65,7 +65,7 @@ EXP_VERSIONS = {
|
||||
"v2.1": {
|
||||
"id": "v2.1",
|
||||
"status": "CURRENT",
|
||||
"version": "2.9",
|
||||
"version": "2.10",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
@@ -114,7 +114,7 @@ class VersionsTestV20(test.NoDBTestCase):
|
||||
{
|
||||
"id": "v2.1",
|
||||
"status": "CURRENT",
|
||||
"version": "2.9",
|
||||
"version": "2.10",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z",
|
||||
"links": [
|
||||
|
@@ -266,10 +266,14 @@ policy_data = """
|
||||
"compute_extension:keypairs:delete": "",
|
||||
|
||||
"os_compute_api:os-keypairs": "",
|
||||
"os_compute_api:os-keypairs:index": "",
|
||||
"os_compute_api:os-keypairs:show": "",
|
||||
"os_compute_api:os-keypairs:create": "",
|
||||
"os_compute_api:os-keypairs:delete": "",
|
||||
"os_compute_api:os-keypairs:index":
|
||||
"rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:show":
|
||||
"rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:create":
|
||||
"rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-keypairs:delete":
|
||||
"rule:admin_api or user_id:%(user_id)s",
|
||||
"os_compute_api:os-lock-server:lock": "",
|
||||
"os_compute_api:os-lock-server:unlock": "",
|
||||
"os_compute_api:os-lock-server:unlock:unlock_override": "",
|
||||
|
Reference in New Issue
Block a user