Rest and ZF session management - authentication

I'm trying to create a web service which utilizes Zend framework. The API is REST based and uses Zend_Rest_Controller as base class. I wish to have user management and session, and for that I'm using the following code:
Login (POST)
// user id and password fetched first
$users = new Application_Model_DbTable_UserInfo();
$auth = Zend_Auth::getInstance();
$authAdapter = new Zend_Auth_Adapter_DbTable($users->getAdapter(),'users');
$authAdapter->setIdentityColumn('userid')
->setCredentialColumn('password');
$authAdapter->setIdentity($userid)
->setCredential($pwd);
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
Zend_Session::rememberMe(604800);
$storage = new Zend_Auth_Storage_Session();
$usa = $authAdapter->getResultRowObject();
$auth->getStorage()->write($usa);
$authSession = new Zend_Session_Namespace('Zend_Auth');
$authSession->setExpirationSeconds(60*60);
}
and when accessing the service with e.g. some GET method I wish to check that there is a valid session with the following code:
$auth = Zend_Auth::getInstance();
if(!$auth->hasIdentity())
{
// error handling etc.
}
I never get an identity, hence the service doesn't work.
I have followed the guidance for ZF authentication quite strictly, but does the REST stuff need additional items to be taken into account?

I know I'm not answering your question, but if you are REALLY planning to implement a true REST interface (which implies it's going to enable you to scale well), you'd probably better forget about sessions and using Zend_Auth in the way you've depicted above.
Take a look here, where something about REST interfaces and authentication has been discussed already:
Can you help me understand this? "Common REST Mistakes: Sessions are irrelevant"
In short, quoting from the Q/A thread above, "To be RESTful, each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP". I really feel like seconding that.

Related

Standalone alternative to express-session for use in serverless context (w/ DynamoDB)

Background: why use cookies with Lambdas?
OWASP is very clear that cookies are the best option for session management:
.. cookies .. are one of the most extensively used session ID exchange mechanisms, offering advanced capabilities not available in other methods.
However AWS's API Gateway literature often talks about using JWTs for authentication rather than cookies. While some tech blogs out there seem to think it's ok to use JWTs in this way, there are definitely recognised issues with JWTs. Two issues of particaular note are:
(a) you can't easily invalidate a JWT. At best you can keep a server-side database of blocked JWTs and make sure any service validating JWTs also implements a check against this block list. That sounds a lot like implementing regular old sessions, largely defeating the point of using JWTs.
(b) if your want to use JWTs for authorization as well as authentication, you'll run into issues when you need to update the authorization and it's not a change being driven by the enduser themselves. Scenarios in this category include: a system administrator or account manager changes the user's access level; a trial/contract is ended by a cron job; a webhook is triggered by a 3rd party SaaS integration (e.g. Stripe). You might say, "in that case use a separate mechanism for authorization", but then again you're back to good old sessions.
To be clear, I understand the value of JWTs in letting one server communicate its trust in a user's identity to another server, but that's a very different purpose to session management.
Session management in Node
All roads seem to lead to express-session as the most battle-tested implementation of sessions in Node. It offers a wide range of storage options to choose from*.
In the context of Lambdas, in principle you could try and use express-session as though it were just a function factory, for functions with the signature (req,res,next)=>void, that's rather hacky, and in no way recommended by express-sessions. It's also not entirely clear how best to match that call signature to the objects you get in an AWS Lambda, nor which storage mechanisms are optimised for lambdas (which are ephemeral and need to start quickly).
I would really like a lightweight node module that lets you do something like the following:
import {Sessions} from 'sessions';
// configure session management. Should be super lightweight for use in Lambda.
const sessions = new Sessions({
/* ..basic cookie & expiration config, */
secret: "something", // extra security recommended by express
store: { // object with following interface:
createSession(sessionId, metadata),
getFromSessionId(sessionId),
updateSession(sessionId, metadata),
customIndexedProperties: ['userId'], // in addition to sessionId
getSessionIdsFromIndexedProperty(propertyName, propertyValue),
}
});
// create session. Note the api is not opinionated about response header mechanics.
response.headers['set-cookie'] = await sessions.createCookieForSession({
userId: 'user1',
/*...other user info */
});
// get user's session. Again not opinionated about where cookie comes from.
const userSessionInfo = await sessions.getSessionFromCookie(request.header['cookies']);
// update a user's session, but not initiated by the user themselves
const sessionIds = await sessions.getSessionIdsFromIndexedProperty('userId', 'user1');
await sessions.updateSession(sessionIds[0], {something: 'has change'});
Questions
Is my above thinking reasonable?
Are there any node packages I've not encountered that might be helpful.
If not, why not? I have come across a few people with closely related problems, but it must be a fairly common issue when working with serverless.
If I were to implement a module to my own liking how do I get any confidence that I've done a good job security-wise? I could use pieces of express-session that are relevant, but that's not a great long-term solution for good security.
Related to 4, if I were to try and hook into express-sessions, but just build my own store that does what I need, how would I get confidence in the security? Also, I haven't managed to find any docs on what the official api is for an express-session store, which I find amazing given that express-sessions seems to be the go to for sessions in Node.
Any help would be massively appreciated, thanks!
P.S. I appreciate a lot of what I'm discussing relates to open source projects that are often poorly funded. However, I was very surprised to have reached the above conclusions about the state of the ecosystem and wondered if I was missing something.
*Annoyingly, the suggested DynamoDb store package isn't great. Two of the features we'd want from it are not support, indeed PRs seem to have been opened back in 2019 but never looked at by the maintainer. Technically we don't absolutely have to use DynamoDb as our store, but it is does offer a lot of features we like.

How to get session context in wamp router validator

According to comment and a criticism for question being too broad; I'll try to make it more specific;
Environment - Server: autobahn|python with twisted, wampv2
Given that:
a) I have a class which extends RouterSession and authenticates user, and at the moment of authentification knows who the user accessing the wamp service is;
and
b) I have a class which extends ApplicationSession and on creation exposes several rpc methods through wamp
How do I access the user data in the exposed RPC method. By the user data - I mean - which I verified at the beginning of a specific client connection through RouterSession.
Because ApplicationSessions are initiated only once, and don't have a clue about caller (from what I have seen in debugger).
The reason I would need this - is to execute the rpc call with the context of a calling user. Where method's result might depend on specific user profile properties.
I am probably looking for something which could represent per-connection created Application instances (which could then hold reference to authorization result and data). Like most of the server Protocols operate in twisted.
-----------------ORIGINAL POST-----------
Brief question: imagine a scenario where user rights are based not on method but object; Example - I may have right to edit my profile account and profile accounts of my subordinates but not any other. This leaves to a situation where I would expose "com.myorg.profile.update_profile_details" RPC through WAMP to everyone, but would have to check which user is trying to modify which profile.
I see there is a validate mechanism in WAMP Router to deal with validating request - but it seems, that it lacks a reference to previous authentication result or session.
I really would like to avoid passing session keys (or, god forbid auth tokens) back and forth through the WAMP; whats the suggested approach for this?
----------------END OF ORIGINAL POST----------
After debugging traces back and forth, I found a solution which fits me - the trick is to pass additional options parameter when registering RPC methods:
self.register(self.test_me_now, 'com.ossnet.testme', options = RegisterOptions(details_arg = 'details', discloseCaller = True))
and voila - there is a new incoming parameter into registered RPC method: 'details'
with following contents:
CallDetails: CallDetails(progress = None, caller = 774234234575675677138, authid = johan.gram, authrole = user, authmethod = ticket)

CakePHP Authentication on REST API

So I'm creating a REST API for a web app I'm developing, and I know the basic ways for authentication are either sending the credentials on each request or sending a token.
Since I have never used token before, I think I may send the credentials for each request. The point is I can't find any examples on how to handle this in the controller. Would it be something like this?
public function api_index() {
if(!$this->Auth->login()) return;
$this->set(array(
'models' => $this->Model->find('all'),
'_serialize' => array('models')
));
}
I don't really think this is the way AuthComponent::login() works, can I get some directions here please?
Alright, first a clarification about how AuthComponent::login works. In Cake 2.x that method does not do any authentication, but rather creates the Auth.User array in your session. You need to implement the actual authentication yourself (the User model is a natural place to do this). A basic authentication method might look like this:
App::uses('AuthComponent', 'Controller/Component');
public function authenticate($data) {
$user = $this->find('first', array(
'conditions' => array('User.login' => $data['login']),
));
if($user['User']['password'] !== AuthComponent::password($data['password']) {
return false;
}
unset($user['User']['password']); // don't forget this part
return $user;
// the reason I return the user is so I can pass it to Authcomponent::login if desired
}
Now you can use this from any controller as long as the User model is loaded. You may be aware that you can load it by calling Controller::loadModel('User').
If you want to authenticate every request, then you should then put in the beforeFilter method of AppController:
public function beforeFilter() {
$this->loadModel('User');
if(!$this->User->authenticate($this->request->data)) {
throw new UnauthorizedException(__('You don\'t belong here.'));
}
}
All of the above assumes that you pass POST values for login and password every time. I think token authentication is definitely the better way to go, but for getting up and running this should work. Some downsides include sending password in cleartext (unless you require ssl) every request and the probably high cpu usage of the hashing algorithm each time. Nevertheless, I hope this gives you a better idea of how to do authentication with cakephp.
Let me know if something needs clarifying.
Update:
Since posting this, I found out that you can actually use AuthComponent::login with no parameters, but I am not a fan of doing so. From the CakePHP documentation:
In 2.x $this->Auth->login($this->request->data) will log the user in with
whatever data is posted, whereas in 1.3 $this->Auth->login($this->data)
would try to identify the user first and only log in when successful.
AuthComponent::login() creates a session variable that stores the user data, so say you had data that was something like.
$data = array('User' => array('id' => 1, 'username' => 'johndoe'));
Then you would use
$this->Auth->login($data);
And access the data with
$this->Auth->user('User');
To get the user id
$this->Auth->user('User.id');
In your AppControllers beforefilter put $this->Auth->deny(); that will deny all actions to someone who is not logged in. Then in each controllers before filter you want to $this->Auth->allow(array('view')); 'view' being the name of an action you want to be public.
http://book.cakephp.org/2.0/en/core-libraries/components/authentication.html
Cakephp 2.X, After lots of research about this on internet I did not find any satisfactory answer So I found a way myself to do this. May be this answer will help some folks in future. This answer is only applicable for REST API's in cake php.
Add following line in your logic action of REST API before checking for the $this->Auth->login().
$this->request->data['User'] = $this->request->data ;
if($this->Auth->login()){
echo "Hurray You are logged In from REST API.";
}
else
{
throw new UnauthorizedException(__('You don\'t belong here.'));
}
Desciption : As #threeve said in one of the answers that $this->Auth->login() does not do any authentication itself. but rather creates the Auth.User array in your session. For Authentication we require our $this->request->data to be inside User array since User is the model which will check the Credentials in Database. Therefore we have to pass the data to Auth as it is required when not using REST API's. Rest of the things will be handled by Cake and Auth itself.
Any enhancements or suggestions on this answer are most welcome.

Backbone.sync – Collection using ajax as well as Socket.IO/WebSockets

I have a Backbone application, which has a collection called Links. Links maps to a REST API URI of /api/links.
The API will give the user the latest links. However, I have a system in place that will add a job to the message queue when the user hits this API, requesting that the links in the database are updated.
When this job is finished, I would to push the new links to the Backbone collection.
How should I do this? In my mind I have two options:
From the Backbone collection, long poll the API for new links
Setup WebSockets to send a "message" to the collection when the job is done, sending the new data with it
Scrap the REST API for my application and just use WebSockets for everything, as I am likely to have more realtime needs later down the line
WebSockets with the REST API
If I use WebSockets, I'm not sure of the best way to integrate this into my Backbone collection so that it works alongside the REST API.
At the moment my Backbone collection looks like this:
var Links = Backbone.Collection.extend({
url: '/api/links'
});
I'm not sure how to enable the Backbone collection to handle AJAX and WebSockets. Do I continue to use the default Backbone.sync for the CRUD Ajax operations, and then deal with the single WebSocket connection manually? In my mind:
var Links = Backbone.Collection.extend({
url: '/api/links',
initialize: function () {
var socket = io.connect('http://localhost');
socket.on('newLinks', addLinks)
},
addLinks: function (data) {
// Prepend `data` to the collection
};
})
Questions
How should I implement my realtime needs, from the options above or any other ideas you have? Please provide examples of code to give some context.
No worries! Backbone.WS got you covered.
You can init a WebSocket connection like:
var ws = new Bakcbone.WS('ws://exmaple.com/');
And bind a Model to it like:
var model = new Backbone.Model();
ws.bind(model);
Then this model will listen to messages events with the type ws:message and you can call model.send(data) to send data via that connection.
Of course the same goes for Collections.
Backbone.WS also gives some tools for mapping a custom REST-like API to your Models/Collections.
My company has a fully Socket.io based solution using backbone, primarily because we want our app to "update" the gui when changes are made on another users screen in real time.
In a nutshell, it's a can of worms. Socket.IO works well, but it also opens a lot of doors you may not be interested in seeing behind. Backbone events get quite out of whack because they are so tightly tied to the ajax transactions...you're effectively overriding that default behavior. One of our better hiccups has been deletes, because our socket response isn't the model that changed, but the entire collection, for example. Our solution does go a bit further than most, because transactions are via a DDL that is specifically setup to be universal across the many devices we need to be able to communicate with, now and in the future.
If you do go the ioBind path, beware that you'll be using different methods for change events compared to your non-socket traffic (if you mix and match) That's the big drawback of that method, standard things like "change" becomes "update" for example to avoid collisions. It can get really confusing in late-night debug or when you have a new developer join the team. For that reason, I prefer either going sockets, or not, not a combination. Sockets have been good so far, and scary fast.
We use a base function that does the heavy lifting, and have several others that extend this base to give us the transaction functionality we need.
This article gives a great starter for the method we used.

Restlet: Adding a role depending on which 'project' (group) the user is accessing

Assume a blackboard type application. There are 2 Projects - ProjectA and ProjectB. User 'nupul' (me) is part of both projects. For A I'm an admin and for B I'm just a 'member' (no admin rights)
When accessing the resource at /MySite/ProjectA/Items I want to check if the user is an admin or not.
I know it can be simply done by picking out the {projectName} parameter from the request and using the identifier (of the user making the request) and forwarding that to check against a DB etc.,
My question is 'how' can I add the roles using an Enroler 'during' authentication itself. Since I don't have access to the {projectName} parameter at that stage. I don't know if you have to use Groups/Realms etc., to make this work, but honestly it's just taking me tooooooooooooooooooo long to even understand how to effectively use this? (i.e., before the request is forwarded to the resource)
I mean I know I can create these groups/realms but how do I access the correct 'role' from the resource???? Restlet seriously needs to have more realistic examples and a much better documentation showing the use of it's classes!! It's driving me insane!! Authentication shouldn't be THIS DIFFICULT! :)
The way to do what you want is to split your routers basing on project name within your application (method createInboundRoot). In this case, the projectname will be evaluated before calling the authenticator. See below some examples of implementing such approach:
public Restlet createInboundRoot() {
Router rootRouter = new Router(getContext());
rootRouter.setDefaultMatchingMode(Template.MODE_STARTS_WITH);
rootRouter.attach("/{projectname}/", createApplicationForProject());
return rootRouter;
}
private Restlet createApplicationForProject() {
Router router = new Router(getContext());
ChallengeAuthenticator guard
= new ChallengeAuthenticator(getContext(),
ChallengeScheme.HTTP_BASIC, "realm");
guard.setVerifier(verifier);
guard.setEnroler(enroler);
guard.setNext(router);
router.attach("items", ItemsServerResource.class);
return guard;
}
Using such approach, you'll have access to the value of the projectname variable within the verifier and be able to use it in the authentication processing.
Hope it helps you,
Thierry