Commit bec7a53b authored by Sofia Papagiannaki's avatar Sofia Papagiannaki
Browse files

astakos: modifications in authenticate keystone api call

* change the call to utilize the updated db models
* update tests
* update docs
parent a05484d2
......@@ -310,14 +310,14 @@ Tokens API Operations
Authenticate
^^^^^^^^^^^^
Fallback call which receives the user token or the user uuid/token and returns
back the token as well as information about the token holder and the services
he/she can access.
Fallback call which receives the user token or the user uuid/token pair and
returns back the token as well as information about the token holder and the
services he/she can access.
========================================= ========= ==================
Uri Method Description
========================================= ========= ==================
``/astakos/api/tokens/`` POST Checks whether the provided token is valid and conforms with the provided uuid (if present) and returns back information about the user
``/identity/v2.0/tokens/`` POST Checks whether the provided token is valid and conforms with the provided uuid (if present) and returns back information about the user
========================================= ========= ==================
The input should be json formatted.
......@@ -328,9 +328,8 @@ Example request:
{
"auth":{
"passwordCredentials":{
"username":"c18088be-16b1-4263-8180-043c54e22903",
"password":"CDEe2k0T/HdiJWBMMbHyOA=="
"token":{
"id":"CDEe2k0T/HdiJWBMMbHyOA=="
},
"tenantName":"c18088be-16b1-4263-8180-043c54e22903"
}
......@@ -342,8 +341,9 @@ or
{
"auth":{
"token":{
"id":"CDEe2k0T/HdiJWBMMbHyOA=="
"passwordCredentials":{
"username":"c18088be-16b1-4263-8180-043c54e22903",
"password":"CDEe2k0T/HdiJWBMMbHyOA=="
},
"tenantName":"c18088be-16b1-4263-8180-043c54e22903"
}
......@@ -359,36 +359,67 @@ Example json response:
::
{'serviceCatalog': [
{'endpoints': [{'SNF:uiURL': 'https://node1.example.com/ui/',
'adminURL': 'https://node1.example.com/v1',
'internalUrl': 'https://node1.example.com/v1',
'publicURL': 'https://node1.example.com/v1',
'region': 'cyclades'}],
'name': 'cyclades',
'type': 'compute'},
{'endpoints': [{'SNF:uiURL': 'https://node2.example.com/ui/',
'adminURL': 'https://node2.example.com/v1',
'internalUrl': 'https://node2.example.com/v1',
'publicURL': 'https://node2.example.com/v1',
'region': 'pithos'}],
'name': 'pithos',
'type': 'storage'}],
'token': {'expires': '2013-06-19T15:23:59.975572+00:00',
'id': 'CDEe2k0T/HdiJWBMMbHyOA==',
'tenant': {'id': 'c18088be-16b1-4263-8180-043c54e22903',
'name': 'Firstname Lastname'}},
'user': {'id': 'c18088be-16b1-4263-8180-043c54e22903',
'name': 'Firstname Lastname',
'roles': [{'id': 1, 'name': 'default'}],
'roles_links': []}}
{"access": {
"serviceCatalog": [
{"SNF:uiURL": "https://node2.example.com/ui/",
"endpoints": [{
"publicURL": "https://object-store.example.synnefo.org/pithos/public/v2.0",
"versionId": "v2.0"}],
"endpoints_links": [],
"name": "pithos_public",
"type": "public"},
{"SNF:uiURL": "https://node2.example.com/ui/",
"endpoints": [{
"publicURL": "https://object-store.example.synnefo.org/pithos/object-store/v1",
"versionId": "v1"}],
"endpoints_links": [],
"name": "pithos_object-store",
"type": "object-store"},
{"SNF:uiURL": "https://node2.example.com/ui/",
"endpoints": [{
"publicURL": "https://object-store.example.synnefo.org/pithos/ui",
"versionId": ""}],
"endpoints_links": [],
"name": "pithos_ui",
"type": "pithos_ui"},
{"SNF:uiURL": "http://localhost:8080",
"endpoints": [{
"publicURL": "https://accounts.example.synnefo.org/ui/v1.0",
"versionId": "v1.0"}],
"endpoints_links": [],
"name": "astakos_ui",
"type": "astakos_ui"},
{"SNF:uiURL": "http://localhost:8080",
"endpoints": [{
"publicURL": "https://accounts.example.synnefo.org/account/v1.0",
"versionId": "v1.0"}],
"endpoints_links": [],
"name": "astakos_account",
"type": "account"},
{"SNF:uiURL": "http://localhost:8080",
"endpoints": [{
"publicURL": "https://accounts.example.synnefo.org/identity/v2.0",
"versionId": "v2.0"}],
"endpoints_links": [],
"name": "astakos_keystone",
"type": "identity"}],
"token": {
"expires": "2013-06-19T15:23:59.975572+00:00",
"id": "CDEe2k0T/HdiJWBMMbHyOA==",
"tenant": {"id": "c18088be-16b1-4263-8180-043c54e22903",
"name": "Firstname Lastname"}},
"user": {
"id": "c18088be-16b1-4263-8180-043c54e22903",
"name": "Firstname Lastname",
"roles": [{"id": 1, "name": "default"},
"roles_links": []}}}
Example xml response:
::
<?xml version="1.0" encoding="UTF-8"?>
<access xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://docs.openstack.org/identity/api/v2.0">
<token id="CDEe2k0T/HdiJWBMMbHyOA==" expires="2013-06-19T15:23:59.975572+00:00">
......@@ -400,22 +431,35 @@ Example xml response:
</roles>
</user>
<serviceCatalog>
<service type="None" name="cyclades">
<endpoint region="cyclades"
publicURL="https://node1.example.com/v1"
adminURL="https://node1.example.com/v1"
internalURL="https://node1.example.com/v1"
SNF:uiURL="https://node1.example.com/ui/">
</endpoint>
<service type="public" name="pithos_public" SNF:uiURL="">
<endpoint
versionId="v2.0"
publicURL="https://object-store.example.synnefo.org/pithos/public/v2.0"
</service>
<service type="object-store" name="pithos_object-store" SNF:uiURL="">
<endpoint
versionId="v1"
publicURL="https://object-store.example.synnefo.org/pithos/object-store/v1"
</service>
<service type="pithos_ui" name="pithos_ui" SNF:uiURL="">
<endpoint
versionId=""
publicURL="https://object-store.example.synnefo.org/pithos/ui"
</service>
<service type="astakos_ui" name="astakos_ui" SNF:uiURL="">
<endpoint
versionId="v1.0"
publicURL="https://accounts.example.synnefo.org/ui/v1.0"
</service>
<service type="account" name="astakos_account" SNF:uiURL="">
<endpoint
versionId="v1.0"
publicURL="https://accounts.example.synnefo.org/account/v1.0"
</service>
<service type="None" name="pithos">
<endpoint
region="pithos"
publicURL="https://node2.example.com/v1"
adminURL="https://node2.example.com/v1"
internalURL="https://node2.example.com/v1"
SNF:uiURL="https://node2.example.com/ui/">
</endpoint>
<service type="identity" name="astakos_keystone" SNF:uiURL="">
<endpoint
versionId="v2.0"
publicURL="https://accounts.example.synnefo.org/identity/v2.0"
</service>
</serviceCatalog>
</access>
......
......@@ -32,6 +32,7 @@
# or implied, of GRNET S.A.
from urlparse import urlunsplit, urlsplit
from collections import defaultdict
from django.http import urlencode
from django.views.decorators.csrf import csrf_exempt
......@@ -114,24 +115,29 @@ def authenticate(request):
if user.uuid != uuid:
raise faults.Unauthorized('Invalid credentials')
access = {}
access['token'] = {'id': user.auth_token,
'expires': utils.isoformat(user.auth_token_expires),
'tenant': {'id': user.uuid, 'name': user.realname}}
access['user'] = {'id': user.uuid, 'name': user.realname,
'roles': list(user.groups.values('id', 'name')),
'roles_links': []}
access['serviceCatalog'] = []
append = access['serviceCatalog'].append
for s in Service.objects.all().order_by('id'):
append({'name': s.name, 'type': s.type,
'endpoints': [{'adminURL': s.api_url,
'publicURL': s.api_url,
'internalURL': s.api_url,
'SNF:uiURL': s.url,
'region': s.name}]})
d = defaultdict(dict)
d["access"]["token"] = {
"id": user.auth_token,
"expires": utils.isoformat(user.auth_token_expires),
"tenant": {"id": user.uuid, "name": user.realname}}
d["access"]["user"] = {
"id": user.uuid, 'name': user.realname,
"roles": list(user.groups.values("id", "name")),
"roles_links": []}
d["access"]["serviceCatalog"] = []
append = d["access"]["serviceCatalog"].append
for s in Service.objects.all().order_by("id"):
endpoints = []
for l in [e.data.values('key', 'value') for e in s.endpoints.all()]:
endpoint = dict((d['key'], d['value']) for d in l)
endpoints.append(endpoint)
append({"name": s.name,
"type": s.type,
"SNF:uiURL": s.component.url,
"endpoints": endpoints,
"endpoints_links": []})
if request.serialization == 'xml':
return xml_response({'access': access}, 'api/access.xml')
return xml_response({'d': d}, 'api/access.xml')
else:
return json_response(access)
return json_response(d)
......@@ -2,26 +2,24 @@
{% load filters %}
<access xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://docs.openstack.org/identity/api/v2.0">
<token id="{{access.token.id}}" expires="{{access.token.expires}}">
<tenant id="{{access.token.tenant.id}}" name="{{access.token.tenant.name}}" />
<token id="{{d.access.token.id}}" expires="{{d.access.token.expires}}">
<tenant id="{{d.access.token.tenant.id}}" name="{{d.access.token.tenant.name}}" />
</token>
<user id="{{access.user.id}}" name="{{access.user.name}}">
<user id="{{d.access.user.id}}" name="{{d.access.user.name}}">
<roles>
{% for r in access.user.roles %}
{% for r in d.access.user.roles %}
<role id="{{r.id}}" name="{{r.name}}"/>
{% endfor %}
</roles>
</user>
<serviceCatalog>
{% for s in access.serviceCatalog %}
<service type="{{s.type}}" name="{{s.name}}">
{% for s in d.access.serviceCatalog %}
<service type="{{s.type}}" name="{{s.name}}" SNF:uiURL="{{s.component.url}}">
{% for e in s.endpoints %}
<endpoint
region="{{e.region}}"
publicURL="{{e.publicURL}}"
adminURL="{{e.adminURL}}"
internalURL="{{e.internalURL}}"
SNF:uiURL="{{e|lookup:'SNF:uiURL'}}"/>
{% for k, v in e.items %}
{{k}}="{{v}}"
{% endfor %}
{% endfor %}
</service>
{% endfor %}
......
......@@ -34,10 +34,12 @@
from astakos.im.tests.common import *
from django.test import TestCase
from django.core.urlresolvers import reverse
from urllib import quote
from urlparse import urlparse, parse_qs
from xml.dom import minidom
#from xml.dom import minidom
import json
......@@ -391,31 +393,46 @@ class TokensApiTest(TestCase):
backend.activate_user(self.user2)
assert self.user2.is_active is True
Service(name='service1', url='http://localhost/service1',
api_url='http://localhost/api/service1',
type='service1').save()
Service(name='service2', url='http://localhost/service2',
api_url='http://localhost/api/service2',
type='service2').save()
Service(name='service3', url='http://localhost/service3',
api_url='http://localhost/api/service3',
type='service3').save()
c1 = Component(name='component1', url='http://localhost/component1')
c1.save()
s1 = Service(component=c1, type='type1', name='service1')
s1.save()
e1 = Endpoint(service=s1)
e1.save()
e1.data.create(key='versionId', value='v1.0')
e1.data.create(key='publicURL', value='http://localhost:8000/s1/v1.0')
s2 = Service(component=c1, type='type2', name='service2')
s2.save()
e2 = Endpoint(service=s2)
e2.save()
e2.data.create(key='versionId', value='v1.0')
e2.data.create(key='publicURL', value='http://localhost:8000/s2/v1.0')
c2 = Component(name='component2', url='http://localhost/component2')
c2.save()
s3 = Service(component=c2, type='type3', name='service3')
s3.save()
e3 = Endpoint(service=s3)
e3.save()
e3.data.create(key='versionId', value='v2.0')
e3.data.create(key='publicURL', value='http://localhost:8000/s3/v2.0')
def test_authenticate(self):
client = Client()
# Check not allowed method
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
r = client.get(url, post_data={})
self.assertEqual(r.status_code, 400)
# Malformed request
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
r = client.post(url, post_data={})
self.assertEqual(r.status_code, 400)
# Check unsupported xml input
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """
<?xml version="1.0" encoding="UTF-8"?>
<auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
......@@ -431,7 +448,7 @@ class TokensApiTest(TestCase):
"Unsupported Content-type: 'application/xml'")
# Check malformed request: missing password
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"passwordCredentials":{"username":"%s"},
"tenantName":"%s"}}""" % (
self.user1.uuid, self.user1.uuid)
......@@ -442,7 +459,7 @@ class TokensApiTest(TestCase):
'Malformed request')
# Check malformed request: missing username
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"passwordCredentials":{"password":"%s"},
"tenantName":"%s"}}""" % (
self.user1.auth_token, self.user1.uuid)
......@@ -453,7 +470,7 @@ class TokensApiTest(TestCase):
'Malformed request')
# Check invalid pass
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"passwordCredentials":{"username":"%s",
"password":"%s"},
"tenantName":"%s"}}""" % (
......@@ -465,7 +482,7 @@ class TokensApiTest(TestCase):
'Invalid token')
# Check inconsistent pass
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"passwordCredentials":{"username":"%s",
"password":"%s"},
"tenantName":"%s"}}""" % (
......@@ -477,14 +494,14 @@ class TokensApiTest(TestCase):
'Invalid credentials')
# Check invalid json data
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
r = client.post(url, "not json", content_type='application/json')
self.assertEqual(r.status_code, 400)
body = json.loads(r.content)
self.assertEqual(body['badRequest']['message'], 'Invalid JSON data')
# Check auth with token
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"token": {"id":"%s"},
"tenantName":"%s"}}""" % (
self.user1.auth_token, self.user1.uuid)
......@@ -497,7 +514,7 @@ class TokensApiTest(TestCase):
self.fail(e)
# Check successful json response
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
post_data = """{"auth":{"passwordCredentials":{"username":"%s",
"password":"%s"},
"tenantName":"%s"}}""" % (
......@@ -511,9 +528,9 @@ class TokensApiTest(TestCase):
self.fail(e)
try:
token = body['token']['id']
user = body['user']['id']
service_catalog = body['serviceCatalog']
token = body['access']['token']['id']
user = body['access']['user']['id']
service_catalog = body['access']['serviceCatalog']
except KeyError:
self.fail('Invalid response')
......@@ -522,7 +539,7 @@ class TokensApiTest(TestCase):
self.assertEqual(len(service_catalog), 3)
# Check successful xml response
url = '/astakos/api/tokens'
url = reverse('astakos.api.tokens.authenticate')
headers = {'HTTP_ACCEPT': 'application/xml'}
post_data = """{"auth":{"passwordCredentials":{"username":"%s",
"password":"%s"},
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment