Skip to content

Commit

Permalink
Added login example. Moved remaining README.rst information to sphinx…
Browse files Browse the repository at this point in the history
… docs.
  • Loading branch information
Martijn Jacobs committed Jan 6, 2016
1 parent 594ddae commit 8360e0e
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 169 deletions.
176 changes: 10 additions & 166 deletions README.rst
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
==============
Oscar REST API
==============

This package provides a RESTful API for `django-oscar`_.

.. _`django-oscar`: https://github.com/django-oscar/django-oscar
.. _`django-oscar@googlegroups.com`: https://groups.google.com/forum/?fromgroups#!forum/django-oscar
.. _`on the wiki`: https://github.com/django-oscar/django-oscar-api/wiki

Continuous integration status:
=====================
Django Oscar REST API
=====================

.. image:: https://travis-ci.org/django-oscar/django-oscar-api.svg?branch=master
:target: https://travis-ci.org/django-oscar/django-oscar-api
Expand All @@ -17,179 +9,31 @@ Continuous integration status:
:alt: Coverage
:target: http://codecov.io/github/django-oscar/django-oscar-api?branch=master

Docs status:

.. image:: https://readthedocs.org/projects/django-oscar-api/badge/
:alt: Documentation Status
:target: http://django-oscar-api.readthedocs.org/

This package provides a RESTful API for `django-oscar`_.

REST API Gateway & resource protection.
---------------------------------------

Because we need the REST API to fascilitate the same usage patterns as
a regular oscar HTML frontend, we need protection of resources on several
levels.

1. gateway level.
An API token is required to communicate with the REST API.
That means we can authorize client applications to make use of the
REST API. Examples of client applications are a website or a
mobile application.
2. User level. Because we don't want resource protection to be the
responsibility of the client application, we need restrictions of resource
access on a user level. The user will use the REST API through an authorized
client application. A user must only be able to access his own resources and
it must be strictly enforced inside the REST API, that there is no way an
API client application can access resources of a different user than the one
identified to the REST API. Effectively an authorized client application can
only manipulate resources on a user level and not on an administrator level.


Anonymous users
---------------

Just like the oscar HTML frontend, some part of the functionality of oscar is
available to anonymous users. That doesn't mean an anonymous user can not be
identified. They are identified by their session, the same way as in a regular
HTML frontend.

There is an upgrade path for an anonymous user, to become an authenticated user,
which opens up the functionality restricted to authenticated users, such as
checkout, order history etc.

A client application can upgrade a user by using the login API.
The following actions will be performed when a user logs in:

1. The user will be authenticated with the REST API. The next steps will only be
performed is login is succesful.
2. The anonymous cart will be merged with the private cart associated with that
authenticated user.
3. A new session will be started, this session identifies the authenticated user
for the duration of the session.
4. The new, merged cart will be associated with this session.
5. The anonymous session will be terminated.
6. A response will be issued containing the new session id as a header (more on
this later).

Session protocol
----------------

.. caution::
The session protocol should only be used when a *TRUSTED* application needs to
perform operations on behalf of a user. Never use the session protocol in any
application where the requests can be inspected by an attacker, such as a
mobile application. CSRF protection is NOT applied so requests CAN be forged
when using the session protocol. Regular cookie based sessions are still
fully functional and the entire REST API should work with this method of
authentication as well. When using cookie based session, csrf restrictions
are enforced as usual, so this is the preferred method of authentication
for any untrusted applications.

.. important::
When using the session protocol, the client application is 100% responsible
for making sure session id's uniquely identify users. A session CAN and
WILL be attached to another user if that user logs in with a session id
allready in use by someone else.

When using the session protocol for authentication, the REST API will not make
use of cookies, which are usually used for transferring the session id between
the client and the backend. Instead we will use the ``Session-Id`` header as
specified in http://www.w3.org/TR/WD-session-id

The w3c Session Identification URI specification proposes a format for a session
identifier as follows::

SID:type:realm:identifier[-thread][:count]
Where the fields type, realm, identifier. thread and count are defined as follows:

type
Type of session identifier. This field allows other session identifier types to be defined. This draft specifies the identifier type "ANON".
realm
Specifies the realm within which linkage of the identifier is possible. Realms have the same format as DNS names.
identifier
Unstructured random integer specific to realm generated using a procedure with a negligible probability of collision. The identifier is encoded using base 64.
thread
Optional extension of identifier field used to differentiate concurrent uses of the same session identifier. The thread field is an integer encoded in hexadecimal.
count
Optional Hexadecimal encoded Integer containing a monotonically increasing counter value. A client should increment the count field after each operation.


An example of a session identifier would be: ``SID:ANON:www.example.com:82d7ac3f-135c-4b12-a296-ff3c4701307d``.
This identifier will be hashed to fit in 40 bytes to yield the final session key.

The ``thread`` and ``count`` values, while allowed will be ignored and not
included when hashing. When upgrading a user from anonymous to authenticated, a
new session id will be generated, by replacing ``ANON`` in the original session
id with ``AUTH`` and performing the hashing again, example:

``SID:AUTH:www.example.com:82d7ac3f-135c-4b12-a296-ff3c4701307d``.

Every response of the REST API will also contain the ``Session-Id`` header.
When a user is logged in, The response will contain a DIFFERENT Session-Id as
the request, because ANON will be replaced with AUTH.

Note that the generation of the ``identifier`` is a responsibility of the client
application, as specified in the w3c specification. This means that it remains
possible for a client application to resume sessions, as long as the identifier
is kept.

Client applications MUST ensure that session id's are unique, since it must
uniquely identify a user, in the same way as a user name.

Why?
----

The above measures ensure the following behaviour:

1. Anonymous sessions can be resumed indefinately, preventing loss of shopping
basket content.
2. Differentiating Session Identification URI's between anonymous users and
authenticated users prevents accidental retrieval of a private shopping basket
for a user that has logged out of the client application.
3. Keeping the session identifier part of the Session Identification URI the same
for both anonymous and authenticated users, simplifies tracking and associating
REST API resources with client application resources.

Final note
----------

Note that guessing the ``identifier`` of an authenticated or anonymous user and
therefor hyjacking the session, is nomore difficult then guessing the session id
stored in a cookie for a web application.

Also note that the identifier, which is in the Session Identification URI, not
used as the session id directly, which means session id's gathered from cookies
can not be used to authenticate with the header Session-Id.
.. _`django-oscar`: https://github.com/django-oscar/django-oscar

Usage
=====

To use the oscarapi application in an oscar ecommerce site, follow these
steps:

1. Install the oscarapi python egg someway.
1. Install the `django-oscar-api` python egg someway.
2. Add oscarapi to INSTALLED_APPS.
3. Add the application's urls to your urlconf::
from oscarapi.app import application as api
urlpatterns = patterns('',
... all the things you allready got
url(r'^oscarapi/', include(api.urls)),
# all the things you allreadya got
url(r'^api/', include(api.urls)),
)

Extending and overriding
------------------------

When needed, the functionality of the REST API can be overridden.
The entry point for customization is ``oscarapi.app:Application``.
In your own app, you can extend this class, and override some of the urls to
direct them to your own views. You can subclass any of the views in oscarapi,
or just write your own from scratch.
See the `readthedocs`_ section for more information.

So to modify some of the functionality in oscarapi, do the following:
.. _`readthedocs`: https://django-oscar-api.readthedocs.org

1. Create a new django app with ``manage.py startapp``
2. Create a file named app.py and in there extend oscarapi.app:Application.
3. Direct some of the urls to your own (subclassed) views.
4. Include your own app in INSTALLED_APPS and urls.py instead of oscarapi.
43 changes: 43 additions & 0 deletions docs/source/usage/communicate_with_the_api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,46 @@ When your basket is filled an you want to proceed to checkout you can do a singl

.. caution::
Explain the payment_url a bit more and add a login example.

.. _login-user-label:

Login the user
--------------
When you don't support anonymous checkouts you will need to login first. Oscar API comes with a simple login view for this:

.. code-block:: python
data = {
"username": "test",
"password": "test"
}
response = session.post('http://localhost:8000/api/login/', json=data)
When the authentication was succesful, your will receive a new (authenticated) sessionid, and the anonymous basket will be automatically merged with a (previous stored) basket of this specific user. You can see that the owner is now set in the basket:

.. code-block:: python
response = session.get('http://localhost:8000/api/basket/')
print(response.content)
{
"currency": "EUR",
"id": 2,
"is_tax_known": true,
"lines": "http://localhost:8000/api/baskets/2/lines/",
"offer_discounts": [],
# now, this basket has an owner
"owner": "http://localhost:8000/api/users/2/",
"status": "Open",
"total_excl_tax": "10.00",
"total_excl_tax_excl_discounts": "10.00",
"total_incl_tax": "10.00",
"total_incl_tax_excl_discounts": "10.00",
"total_tax": "0.00",
"url": "http://localhost:8000/api/baskets/2/",
"voucher_discounts": []
}
2 changes: 2 additions & 0 deletions docs/source/usage/middleware.rst
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ Other Middleware Classes

Next to the :ref:`header-session-label`, Oscar API ships with some useful middelware classes which restrict access to your API and make sure that you can mix an Oscar stand-alone application and the API.

.. _gateway-middleware-label:

Gateway MiddleWare
------------------
Protects the usage of your API with an authentication token (we call it an ApiKey). To use this, add this as the first middleware in MIDDLEWARE_CLASSES in your ``settings.py``.
Expand Down
56 changes: 53 additions & 3 deletions docs/source/usage/permissions.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,56 @@
===========
Permissions
===========
========================
Permissions and security
========================

Some notes on gateway & resource protection.
--------------------------------------------

Because we need the REST API to fascilitate the same usage patterns as
a regular oscar HTML frontend, we need protection of resources on several
levels.

1. `Gateway level`. An API token can be used to communicate with the REST API.
That means we can authorize client applications to make use of the
REST API. Examples of client applications are a website or a
mobile application. See also the :ref:`gateway-middleware-label`.
2. `User level.` Because we don't want resource protection to be the
responsibility of the client application, we need restrictions of resource
access on a user level. The user will use the REST API through an authorized
client application. A user must only be able to access his own resources and
it must be strictly enforced inside the REST API, that there is no way an
API client application can access resources of a different user than the one
identified to the REST API. Effectively an authorized client application can
only manipulate resources on a user level and not on an administrator level.
See aso the :ref:`main-settings-label`.


Anonymous users
---------------

Just like the oscar HTML frontend, some part of the functionality of oscar is
available to anonymous users. That doesn't mean an anonymous user can not be
identified. They are identified by their session, the same way as in a regular
HTML frontend.

There is an upgrade path for an anonymous user, to become an authenticated user,
which opens up the functionality restricted to authenticated users.

A client application can upgrade a user by using the login API, See also
the :ref:`login-user-label` example.


The following actions will be performed when a user logs in:

1. The user will be authenticated with the REST API. The next steps will only be
performed is login is succesful.
2. The anonymous cart will be merged with the private cart associated with that
authenticated user.
3. A new session will be started, this session identifies the authenticated user
for the duration of the session.
4. The new, merged cart will be associated with this session.
5. The anonymous session will be terminated.
6. A response will be issued containing the new session id.


.. attention::
We need to write something about permissions here.
2 changes: 2 additions & 0 deletions docs/source/usage/settings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
Oscar API Settings
==================

.. _main-settings-label:

Main settings
=============

Expand Down

0 comments on commit 8360e0e

Please sign in to comment.