views:

60

answers:

1

I am using the core Auth component. I have created a user login that manages all of the permissions. The way I am implementing the login monitoring is by checking for $this->Auth->user() in the app_controller. Each time the app_controller cycles the beforeFilter() function and !$this->Auth->user(), it will increment the Captcha.LoginAttempts session variable. When Captcha.LoginAttempts is > 3, I want it to redirect to the Captchas controller, displaying a captcha screen requiring the user to confirm they are a human. (Similar to how stackoverflow does it).

The issue I am having is if I am using an element somewhere or referencing something within the cake framework on the page, it will hit the redirect and cause an endless circular redirect for every accessing element/component being called external to the actual controller/action. Is there a better way to implement this?

Here is the actual code I have been messing with. But it basically sucks (IMO):

// this is in the app_controller beforeFilter() method.

if($this->Auth->user()) {
            $this->Session->delete('Captcha');
        } else {
            $this->Session->write('Captcha.LoginAttempts', $this->Session->read('Captcha.LoginAttempts') + 1);
            if ($this->Session->read('Captcha.LoginAttempts') > 3) {
                if (!$this->Session->read('Captcha.controller')) {
                    $this->Session->write('Captcha.controller', $this->params['controller']);
                    $this->Session->write('Captcha.action', $this->params['action']);
                }
                if ($this->Session->read('Captcha.fail') !== 'true') { // avoid circular reference redirects
                    $this->Session->write('Captcha.fail', 'true');
                    $this->redirect(array('controller' => 'captchas', 'action' => 'index'));
                }
            }
        }

You can see how I try to avoid the circular reference. But then the user could just go to the login page and since the Captcha.fail session variable is already set, it will ignore the redirect. There must be a more elegant way to implement this. Anyone?

+1  A: 

Normally, I would just try to answer the way you are trying to do it, but since you asked for any better ideas, what I would do is have the Captcha actually on the login page and use the AuthComponents builtin methods and properties like loginRedirect, autoRedirect, and allow(). Then, just turn the captcha on/off based on the Captchas.loginAttempts variable.

For your current method, I don't think you're going to get an elegant way of doing this. However, you might be able to change the properties of the AuthComponent to get what you want. You could change loginRedirect and loginAction so that /captchas/index is the new login form, then on successful captcha, set loginAction back to /users/login or whatever. This way, if someone were to attempt to hit /users/login directly without doing the captcha, then the AuthComponent logic would kick in and redirect to /captchas/index.

Here are some relevant manual pages:

Hope this helps!

Finster
I like the auth redirect idea. That could do the trick. I will implement and report how that works. Thanks for the great suggestion!
cdburgess
Unfortunately, $this->Auth->loginAction=''; Will not do what I intended - it will only redirect unauthenticated users in the default way. So I cannot change this mid stream (for example) and how the thrice failed attempts now route to captcha/index. But thanks for the idea. It was worth looking into.
cdburgess