Commit 1bbb6771 authored by Sofia Papagiannaki's avatar Sofia Papagiannaki

astakos: WIP move all api calls under ``/astakos/api``

Refs: #3340
parent 68af7c49
......@@ -14,16 +14,12 @@ v0.13next
Released: UNRELEASED
* Incorporate quotaholder in astakos
* obsolete settings:
PITHOS_USE_QUOTAHOLDER, PITHOS_QUOTAHOLDER_URL, PITHOS_QUOTAHOLDER_TOKEN
* new settins:
PITHOS_ASTAKOSCLIENT_POOLSIZE
Synnefo-wide
------------
* Create 'snf_django' Python package to hold common code for all Synnefo
components.
* CLOUDBAR_SERVICES_URL should point to /astakos/api/get_services
* CLOUDBAR_MENU_URL should point to /astakos/api/get_menu
Astakos
-------
......@@ -51,6 +47,8 @@ Pithos
astakos users.
* Remove 'PITHOS_USER_CATALOG_URL', 'PITHOS_USER_FEEDBACK_URL' and
'PITHOS_USER_LOGIN_URL' settings.
* Remove PITHOS_USE_QUOTAHOLDER, PITHOS_QUOTAHOLDER_URL,
PITHOS_QUOTAHOLDER_TOKEN and PITHOS_ASTAKOSCLIENT_POOLSIZE
Tools
-----
......
......@@ -173,7 +173,7 @@ class AstakosClient():
raise InvalidResponse(str(err), data)
# ------------------------
# GET /im/authenticate
# GET /astakos/api/authenticate
def get_user_info(self, token, usage=False):
"""Authenticate user and get user's info as a dictionary
......@@ -186,13 +186,13 @@ class AstakosClient():
"""
# Send request
auth_path = "/im/authenticate"
auth_path = "/astakos/api/authenticate"
if usage:
auth_path += "?usage=1"
return self._call_astakos(token, auth_path)
# ----------------------------------
# POST /user_catalogs (or /service/api/user_catalogs)
# POST /astakos/api/user_catalogs (or /astakos/api/service/user_catalogs)
# with {'uuids': uuids}
def _uuid_catalog(self, token, uuids, req_path):
req_headers = {'content-type': 'application/json'}
......@@ -218,7 +218,7 @@ class AstakosClient():
keys and the corresponding user names as values
"""
req_path = "/user_catalogs"
req_path = "/astakos/api/user_catalogs"
return self._uuid_catalog(token, uuids, req_path)
def get_username(self, token, uuid):
......@@ -232,7 +232,7 @@ class AstakosClient():
def service_get_usernames(self, token, uuids):
"""Return a uuid_catalog dict using a service's token"""
req_path = "/service/api/user_catalogs"
req_path = "/astakos/api/service/user_catalogs"
return self._uuid_catalog(token, uuids, req_path)
def service_get_username(self, token, uuid):
......@@ -245,7 +245,7 @@ class AstakosClient():
raise NoUserName(uuid)
# ----------------------------------
# POST /user_catalogs (or /service/api/user_catalogs)
# POST /astakos/api/user_catalogs (or /astakos/api/service/user_catalogs)
# with {'displaynames': display_names}
def _displayname_catalog(self, token, display_names, req_path):
req_headers = {'content-type': 'application/json'}
......@@ -271,7 +271,7 @@ class AstakosClient():
the names as keys and the corresponding uuids as values
"""
req_path = "/user_catalogs"
req_path = "/astakos/api/user_catalogs"
return self._displayname_catalog(token, display_names, req_path)
def get_uuid(self, token, display_name):
......@@ -285,7 +285,7 @@ class AstakosClient():
def service_get_uuids(self, token, display_names):
"""Return a display_name catalog using a service's token"""
req_path = "/service/api/user_catalogs"
req_path = "/astakos/api/service/user_catalogs"
return self._displayname_catalog(token, display_names, req_path)
def service_get_uuid(self, token, display_name):
......@@ -298,10 +298,10 @@ class AstakosClient():
raise NoUUID(display_name)
# ----------------------------------
# GET "/im/get_services"
# GET "/astakos/api/get_services"
def get_services(self):
"""Return a list of dicts with the registered services"""
return self._call_astakos(None, "/im/get_services")
return self._call_astakos(None, "/astakos/api/get_services")
# ----------------------------------
# GET "/astakos/api/resources"
......
......@@ -108,9 +108,9 @@ def _request_status_400(conn, method, url, **kwargs):
def _request_ok(conn, method, url, **kwargs):
"""This request behaves like original Astakos does"""
if url.startswith("/im/authenticate"):
if url.startswith("/astakos/api/authenticate"):
return _req_authenticate(conn, method, url, **kwargs)
elif url.startswith("/user_catalogs"):
elif url.startswith("/astakos/api/user_catalogs"):
return _req_catalogs(conn, method, url, **kwargs)
elif url.startswith("/astakos/api/resources"):
return _req_resources(conn, method, url, **kwargs)
......@@ -472,7 +472,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_offline])
try:
client = AstakosClient("https://example.com", use_pool=pool)
client._call_astakos(token_1, "/im/authenticate")
client._call_astakos(token_1, "/astakos/api/authenticate")
except AstakosClientException:
pass
else:
......@@ -493,7 +493,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("https://example.com", use_pool=pool)
client._call_astakos(token, "/im/authenticate")
client._call_astakos(token, "/astakos/api/authenticate")
except Unauthorized:
pass
except Exception:
......@@ -516,7 +516,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("https://example.com", use_pool=pool)
client._call_astakos(token_1, "/im/misspelled")
client._call_astakos(token_1, "/astakos/api/misspelled")
except NotFound:
pass
except Exception:
......@@ -539,7 +539,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("ftp://example.com", use_pool=pool)
client._call_astakos(token_1, "/im/authenticate")
client._call_astakos(token_1, "/astakos/api/authenticate")
except BadValue:
pass
except Exception:
......@@ -562,7 +562,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("http://example.com", use_pool=pool)
client._call_astakos(token_1, "/im/authenticate")
client._call_astakos(token_1, "/astakos/api/authenticate")
except AstakosClientException as err:
if err.status != 302:
self.fail("Should have returned 302 (Found)")
......@@ -584,7 +584,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("https://example.com", use_pool=pool)
client._call_astakos(token_1, "/im/authenticate", method="POST")
client._call_astakos(token_1, "/astakos/api/authenticate", method="POST")
except BadRequest:
pass
except Exception:
......@@ -607,7 +607,7 @@ class TestCallAstakos(unittest.TestCase):
_mock_request([_request_ok])
try:
client = AstakosClient("https://example.com", use_pool=pool)
client._call_astakos(token_1, "/user_catalogs")
client._call_astakos(token_1, "/astakos/api/user_catalogs")
except BadRequest:
pass
except Exception:
......
......@@ -20,6 +20,7 @@ Document Revisions
========================= ================================
Revision Description
========================= ================================
0.14 (May 02, 2013) Change URIs (keep also the old ones until the next version)
0.13 (January 21, 2013) Extend api to export user presentation & quota information.
0.6 (June 06, 2012) Split service and admin API.
0.1 (Feb 10, 2012) Initial release.
......@@ -30,11 +31,11 @@ Get Services
Returns a json formatted list containing information about the supported cloud services.
==================== ========= ==================
Uri Method Description
==================== ========= ==================
``/im/get_services`` GET Get cloud services
==================== ========= ==================
============================= ========= ==================
Uri Method Description
============================= ========= ==================
``/astakos/api/get_services`` GET Get cloud services
============================= ========= ==================
Example reply:
......@@ -44,17 +45,20 @@ Example reply:
{"url": "/okeanos.html", "name": "~okeanos", "id": "2"},
{"url": "/ui/", "name": "pithos+", "id": "3"}]
.. warning:: The service is also available under ``/im/get_services``.
It will be removed in the next version.
Get Menu
^^^^^^^^
Returns a json formatted list containing the cloud bar links.
==================== ========= ==================
Uri Method Description
==================== ========= ==================
``/im/get_menu`` GET Get cloud bar menu
==================== ========= ==================
========================= ========= ==================
Uri Method Description
========================= ========= ==================
``/astakos/api/get_menu`` GET Get cloud bar menu
========================= ========= ==================
Example reply if request user is not authenticated:
......@@ -66,10 +70,13 @@ Example reply if request user is authenticated:
::
[{"url": "/im/login", "name": "user@example.com"},
{"url": "/im/profile", "name": "My account"},
[{"url": "/im/", "name": "user@example.com"},
{"url": "/im/landing", "name": "Dashboard"},
{"url": "/im/logout", "name": "Sign out"}]
.. warning:: The service is also available under ``/im/get_menu``.
It will be removed in the next version.
Admin API Operations
--------------------
......@@ -84,11 +91,11 @@ Authenticate
Authenticate API requests require a token. An application that wishes to connect to Astakos, but does not have a token, should redirect the user to ``/login``. (see :ref:`authentication-label`)
==================== ========= ==================
Uri Method Description
==================== ========= ==================
``/im/authenticate`` GET Authenticate user using token
==================== ========= ==================
============================= ========= ==================
Uri Method Description
============================= ========= ==================
``/astakos/api/authenticate`` GET Authenticate user using token
============================= ========= ==================
|
......@@ -225,6 +232,9 @@ Return Code Description
500 (Internal Server Error) The request cannot be completed because of an internal error
=========================== =====================
.. warning:: The service is also available under ``/im/authenticate``.
It will be removed in the next version.
Send feedback
^^^^^^^^^^^^^
......@@ -234,7 +244,7 @@ Post user feedback.
========================= ========= ==================
Uri Method Description
========================= ========= ==================
``/feedback`` POST Send feedback
``astakos/api/feedback`` POST Send feedback
========================= ========= ==================
|
......@@ -274,7 +284,7 @@ Return a json formatted dictionary containing information about a specific user
================================ ========= ==================
Uri Method Description
================================ ========= ==================
``/user_catalogs`` POST Get 2 catalogs containing uuid to displayname mapping and the opposite
``astakos/api/user_catalogs`` POST Get 2 catalogs containing uuid to displayname mapping and the opposite
================================ ========= ==================
|
......@@ -329,11 +339,11 @@ Get User catalogs
Return a json formatted dictionary containing information about a specific user
================================ ========= ==================
Uri Method Description
================================ ========= ==================
``/user_catalogs`` POST Get 2 catalogs containing uuid to displayname mapping and the opposite
================================ ========= ==================
===================================== ========= ==================
Uri Method Description
===================================== ========= ==================
``astakos/api/service/user_catalogs`` POST Get 2 catalogs containing uuid to displayname mapping and the opposite
===================================== ========= ==================
|
......
......@@ -86,11 +86,12 @@ Cloud service user
Alice requests a specific resource from a cloud service ex. Pithos+. In the
request supplies the `X-Auth-Token` to identify whether she is eligible to
perform the specific task. The service contacts Astakos through its
``/im/authenticate`` api call (see :ref:`authenticate-api-label`) providing the
specific ``X-Auth-Token``. Astakos checkes whether the token belongs to an
active user and it has not expired and returns a dictionary containing user
related information. Finally the service uses the ``uniq`` field included in
the dictionary as the account string to identify the user accessible resources.
``/astakos/api/authenticate`` api call (see :ref:`authenticate-api-label`)
providing the specific ``X-Auth-Token``. Astakos checkes whether the token
belongs to an active user and it has not expired and returns a dictionary
containing user related information. Finally the service uses the ``uniq``
field included in the dictionary as the account string to identify the user
accessible resources.
.. _registration-flow-label:
......
......@@ -610,9 +610,9 @@ Then edit ``/etc/synnefo/20-snf-astakos-app-cloudbar.conf`` :
CLOUDBAR_LOCATION = 'https://node1.example.com/static/im/cloudbar/'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/im/get_menu'
CLOUDBAR_MENU_URL = 'https://node1.example.com/astakos/api/get_menu'
Those settings have to do with the black cloudbar endpoints and will be
described in more detail later on in this guide. For now, just edit the domain
......@@ -912,8 +912,8 @@ pithos+ web UI with the astakos web UI (through the top cloudbar):
CLOUDBAR_LOCATION = 'https://node1.example.com/static/im/cloudbar/'
PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE = '3'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/im/get_menu'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/astakos/api/get_menu'
The ``CLOUDBAR_LOCATION`` tells the client where to find the astakos common
cloudbar.
......@@ -1722,8 +1722,8 @@ Edit ``/etc/synnefo/20-snf-cyclades-app-cloudbar.conf``:
CLOUDBAR_LOCATION = 'https://node1.example.com/static/im/cloudbar/'
CLOUDBAR_ACTIVE_SERVICE = '2'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://account.node1.example.com/im/get_menu'
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://account.node1.example.com/astakos/api/get_menu'
``CLOUDBAR_LOCATION`` tells the client where to find the Astakos common
cloudbar. The ``CLOUDBAR_SERVICES_URL`` and ``CLOUDBAR_MENU_URL`` options are
......
......@@ -39,8 +39,8 @@ In `/etc/synnefo/astakos.conf` add:
.. code-block:: console
CLOUDBAR_LOCATION = 'https://accounts.example.com/static/im/cloudbar/'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/im/get_menu'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/astakos/api/get_menu'
ASTAKOS_IM_MODULES = ['local']
......
......@@ -42,8 +42,8 @@ In `/etc/synnefo/cloudcms.conf` add:
CLOUDBAR_ACTIVE = True
CLOUDBAR_LOCATION = 'https://accounts.example.com/static/im/cloudbar/'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/im/get_menu'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/astakos/api/get_menu'
WEBPROJECT_SERVE_STATIC = True
......
......@@ -64,7 +64,7 @@ In `/etc/synnefo/cyclades.conf` add:
GANETI_USE_HOTPLUG = True
CLOUDBAR_LOCATION = 'https://accounts.example.com/static/im/cloudbar/'
CLOUDBAR_ACTIVE_SERVICE = '2'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/im/get_services'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/im/get_menu'
BACKEND_DB_CONNECTION = 'postgresql://synnefo:example_passw0rd@db.example.com:5432/snf_pithos'
BACKEND_BLOCK_PATH = '/srv/pithos/data/'
......
......@@ -85,8 +85,8 @@ In `/etc/synnefo/webclient.conf` add:
.. code-block:: console
CLOUDBAR_LOCATION = 'https://accounts.example.com/static/im/cloudbar/'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/im/get_menu'
CLOUDBAR_SERVICES_URL = 'https://accounts.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://accounts.example.com/astakos/api/get_menu'
PITHOS_UI_CLOUDBAR_ACTIVE_SERVICE = 'XXXXXXXX'
......
......@@ -74,3 +74,55 @@ Finally, Astakos needs to inform the quota system for the current number
of pending applications per user::
astakos-host$ snf-manage reconcile-resources-astakos --fix
4 Change Astakos URIs in settings
=================================
In astakos-host edit ``/etc/synnefo/20-snf-astakos-app-cloudbar.conf`` and replace
the following lines:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/im/get_menu'
with:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/astakos/api/get_menu'
|
Also in pithos-host edit ``/etc/synnefo/20-snf-pithos-webclient-cloudbar.conf``
and the following lines:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/im/get_menu'
with:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://node1.example.com/astakos/api/get_menu'
|
Finally in cyclades-node edit ``/etc/synnefo/20-snf-cyclades-app-cloudbar.conf``
and replace the following lines:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/im/get_services'
CLOUDBAR_MENU_URL = 'https://account.node1.example.com/im/get_menu'
with:
.. code-block:: console
CLOUDBAR_SERVICES_URL = 'https://node1.example.com/astakos/api/get_services'
CLOUDBAR_MENU_URL = 'https://account.node1.example.com/astakos/api/get_menu'
# Copyright 2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# conditions are met:
#
# 1. Redistributions of source code must retain the above
# copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials
# provided with the distribution.
#
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
# Decorator for API methods, using common utils.api_method decorator.
# It is used for 'get_services' and 'get_menu' methods that do not
# require any sort of authentication
from functools import partial
from django.http import HttpResponse
from django.utils import simplejson as json
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
from django.contrib import messages
from snf_django.lib import api
from astakos.im.models import Service
from astakos.im.settings import (INVITATIONS_ENABLED, QUOTAHOLDER_URL,
PROJECTS_VISIBLE)
import logging
logger = logging.getLogger(__name__)
absolute = lambda request, url: request.build_absolute_uri(url)
api_method = partial(api.api_method, user_required=False,
token_required=False, logger=logger)
@api_method(http_method=None)
def get_services(request):
callback = request.GET.get('callback', None)
mimetype = 'application/json'
data = json.dumps(Service.catalog().values())
if callback:
# Consume session messages. When get_services is loaded from an astakos
# page, messages should have already been consumed in the html
# response. When get_services is loaded from another domain/service we
# consume them here so that no stale messages to appear if user visits
# an astakos view later on.
# TODO: messages could be served to other services/sites in the dict
# response of get_services and/or get_menu. Services could handle those
# messages respectively.
messages_list = list(messages.get_messages(request))
mimetype = 'application/javascript'
data = '%s(%s)' % (callback, data)
return HttpResponse(content=data, mimetype=mimetype)
@api_method()
def get_menu(request, with_extra_links=False, with_signout=True):
user = request.user
index_url = reverse('index')
if user.is_authenticated():
l = []
append = l.append
item = MenuItem
item.current_path = absolute(request, request.path)
append(item(url=absolute(request, reverse('index')),
name=user.email))
if with_extra_links:
append(item(url=absolute(request, reverse('landing')),
name="Overview"))
if with_signout:
append(item(url=absolute(request, reverse('landing')),
name="Dashboard"))
if with_extra_links:
append(item(url=absolute(request, reverse('edit_profile')),
name="Profile"))
if with_extra_links:
if INVITATIONS_ENABLED:
append(item(url=absolute(request, reverse('invite')),
name="Invitations"))
append(item(url=absolute(request, reverse('resource_usage')),
name="Usage"))
if QUOTAHOLDER_URL and PROJECTS_VISIBLE:
append(item(url=absolute(request, reverse('project_list')),
name="Projects"))
#append(item(
#url=absolute(request, reverse('api_access')),
#name="API Access"))
append(item(url=absolute(request, reverse('feedback')),
name="Contact"))
if with_signout:
append(item(url=absolute(request, reverse('logout')),
name="Sign out"))
else:
l = [{'url': absolute(request, index_url),
'name': _("Sign in")}]
callback = request.GET.get('callback', None)
data = json.dumps(tuple(l))
mimetype = 'application/json'
if callback:
mimetype = 'application/javascript'
data = '%s(%s)' % (callback, data)
return HttpResponse(content=data, mimetype=mimetype)
class MenuItem(dict):
current_path = ''
def __init__(self, *args, **kwargs):
super(MenuItem, self).__init__(*args, **kwargs)
if kwargs.get('url') or kwargs.get('submenu'):
self.__set_is_active__()
def __setitem__(self, key, value):
super(MenuItem, self).__setitem__(key, value)
if key in ('url', 'submenu'):
self.__set_is_active__()
def __set_is_active__(self):
if self.get('is_active'):
return
if self.current_path.startswith(self.get('url')):
self.__setitem__('is_active', True)
else:
submenu = self.get('submenu', ())
current = (i for i in submenu if i.get('url') == self.current_path)
try:
current_node = current.next()
if not current_node.get('is_active'):
current_node.__setitem__('is_active', True)
self.__setitem__('is_active', True)
except StopIteration:
return
def __setattribute__(self, name, value):
super(MenuItem, self).__setattribute__(name, value)
if name == 'current_path':
self.__set_is_active__()
......@@ -36,20 +36,18 @@ from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
from snf_django.lib.db.transaction import commit_on_success_strict
from astakos.api.util import json_response, is_integer, are_integer
from snf_django.lib import api
from snf_django.lib.api.faults import BadRequest, ItemNotFound
from astakos.im.api.user import user_from_token
from astakos.im.api.service import service_from_token
from astakos.im.resources import get_resources
from astakos.im.quotas import get_user_quotas, service_get_quotas
import astakos.quotaholder_app.exception as qh_exception
import astakos.quotaholder_app.callpoint as qh
from .util import (json_response, is_integer, are_integer,
user_from_token, service_from_token)
@api.api_method(http_method='GET', token_required=True, user_required=False)
@user_from_token
......
......@@ -31,56 +31,19 @@
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
from time import time, mktime
from functools import wraps
from django.views.decorators.csrf import csrf_exempt
from . import __get_uuid_displayname_catalogs, __send_feedback
from snf_django.lib import api
from snf_django.lib.api import faults
from astakos.im.models import Service
from .util import (__get_uuid_displayname_catalogs, __send_feedback,
service_from_token)
import logging
logger = logging.getLogger(__name__)
def service_from_token(func):
"""Decorator for authenticating service by it's token.
Check that a service with the corresponding token exists. Also,
if service's token has an expiration token, check that it has not
expired.
"""
@wraps(func)
def wrapper(request, *args, **kwargs):
try:
token = request.x_auth_token
except AttributeError:
raise faults.Unauthorized("No authentication token")
if not token:
raise faults.Unauthorized("Invalid X-Auth-Token")
try:
service = Service.objects.get(auth_token=token)
except Service.DoesNotExist:
raise faults.Unauthorized("Invalid X-Auth-Token")
# Check if the token has expired
expiration_date = service.auth_token_expires
if expiration_date:
expires_at = mktime(expiration_date.timetuple())
if time() > expires_at:
raise faults.Unauthorized("Authentication expired")
request.service_instance = service
return func(request, *args, **kwargs)
return wrapper
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False,
logger=logger)
logger=logger)
@service_from_token # Authenticate service !!
def get_uuid_displayname_catalogs(request):
# Normal Response Codes: 200
......@@ -92,7 +55,7 @@ def get_uuid_displayname_catalogs(request):
@csrf_exempt
@api.api_method(http_method='POST', token_required=True, user_required=False,
logger=logger)
logger=logger)
@service_from_token # Authenticate service !!
def send_feedback(request, email_template_name='im/feedback_mail.txt'):
# Normal Response Codes: 200
......
......@@ -34,6 +34,12 @@
from django.conf.urls.defaults import patterns, url
urlpatterns = patterns(
'astakos.api',
url(r'^get_services/?$', 'get_services'),
url(r'^get_menu/?$', 'get_menu'),
)
urlpatterns += patterns(
'astakos.api.quotas',
url(r'^quotas/?$', 'quotas', name="astakos-api-quotas"),
url(r'^service_quotas/?$', 'service_quotas'),
......@@ -43,3 +49,15 @@ urlpatterns = patterns(