Tuesday, September 1, 2015

Authentication and Authorization modules that don’t encapsulate the credentials in one piece such as a token suffer from the problem that they are just about as secure as SMTP. Anyone can spoof anyone by passing different user ids. That said there is a real need to be able to switch users in the request.user such that an API implementation can be tested and have very little or no instrumentation for the live usage by a logged in user as well as for the passive testing for coverage. The latter can possibly be alleviated with test accounts that are created beforehand for all API implementations. Such a test account may need to be registered in the Active Directory as a user that can sign in. This may or may not be available. On the other hand, when  user information in the passed credentials are hardened, then they become tamper proof and push the switching to using different tokens.
With the above two requirements in a landscape with a typical portal or WebUI accessing different API functionalities through a gateway, we now look at the minimal steps or changes required to merely use the token and nothing else for authentication providing a one-point maintenance and hence secure switching. Each request is therefore authenticated and the sessions is guaranteed for the lifetime of the token.
Django-oauth-toolkit 0.9.0 package https://pypi.python.org/pypi/django-oauth-toolkit provides all the implementations for an RFC compliant OAuth server. By definition of OAuth, when users accept certain applications to access some or all of their information, they enable the OAuth server to cut tokens that represent the user+client+the-issuing-authority. The token can then be passed directly in the Authorization header or in its own custom header or as query string whichever is convenient.  The application can be a web portal and will have its own client id and client secret. When a user logs in to the portal, she blesses certain modules aka clients. These modules can in turn request token from an OAuth server.  Ideally, the identity provider such as Okta will implement the Oauth token server itself and hence we could use those OAuth APIs  as priority. In the absence of these OAuth apis, we write an OAuth server but don’t put it behind the Nginx server that forwards to different destinations. Since the clients are registered in  a table and the users are also registered, the OAuth server does not need to verify the requestor to issue the token. Besides, the verification of the token requestor is handled within the protocol.
The first step therefore it to use an OAuth server such as the out-of-box OAuth server with the toolkit referred above and deploy it outside the gateway to different API functionalities.
Second the portal needs to provision a page that lets clients be registered. Note that a developer who writes a client application is the user who logs in to access this page. Clients may be written by one user (owner/developer) and request the server for tokens on behalf of the users of the client. This page has captures the information such as the name, description, callback URL and environment.
Third the portal needs to provision a page that lets logged in users to permit different clients to request tokens from the OAuth server on their behalf. This page usually has the description of the client and the kind of information it will be accessing from the users profile. In addition, it may disclose all the actions it will take the user’s information.
Fourth, the use of a utility package to verify the token employs a static method (one that relies entirely on the parameters passed in and does not have an instance associated for any API implementation) that takes a request header and validates it against the OAuth server.  Given a token, an OAuth server can reverse lookup the associated user, client and check itself as the issuing authority. The method returns this looked up information.
Finally, the API implementations should have the ability to get information such as
Request.user.id
Request.user.email
Request.user.fullname
And arguably request.user.password (encrypted)

With these an API should be able to impersonate the logged in user.

No comments:

Post a Comment