aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/App/Controller/Auth.pm
diff options
context:
space:
mode:
authorEdmund von der Burg <evdb@mysociety.org>2011-03-04 11:08:07 +0000
committerEdmund von der Burg <evdb@mysociety.org>2011-03-04 11:08:07 +0000
commit770ffd1d8fb1f023e78df876a29dc36022246692 (patch)
tree3ab4571d487c4e50c19fcece42983764fbab3b5c /perllib/FixMyStreet/App/Controller/Auth.pm
parente18bf78e0513d4f1ebf0413d60691525cdcc2f5d (diff)
Completed auth section (main parts at least)
Diffstat (limited to 'perllib/FixMyStreet/App/Controller/Auth.pm')
-rw-r--r--perllib/FixMyStreet/App/Controller/Auth.pm142
1 files changed, 98 insertions, 44 deletions
diff --git a/perllib/FixMyStreet/App/Controller/Auth.pm b/perllib/FixMyStreet/App/Controller/Auth.pm
index b21981417..2069b3903 100644
--- a/perllib/FixMyStreet/App/Controller/Auth.pm
+++ b/perllib/FixMyStreet/App/Controller/Auth.pm
@@ -34,7 +34,7 @@ sub general : Path : Args(0) {
return unless $req->method eq 'POST';
# check that the email is valid - otherwise flag an error
- my $raw_email = $req->param('email') || '';
+ my $raw_email = lc( $req->param('email') || '' );
my $email_checker = Email::Valid->new(
-mxcheck => 1,
-tldcheck => 1,
@@ -52,7 +52,8 @@ sub general : Path : Args(0) {
}
# decide which action to take
- $c->detach('create_account') if $req->param('create_account');
+ $c->detach('login') if $req->param('login');
+ $c->detach('email_login') if $req->param('email_login');
# hmm - should not get this far. 404 so that user knows there is a problem
# rather than it silently not working.
@@ -60,78 +61,131 @@ sub general : Path : Args(0) {
}
-=head2 create_account
+=head2 login
-Create an account for the user, send them an email with confirm link and log
-them in straight away. If the email address already has an account send them an
-email with a password reset link (slightly leaks privacy information but
-required to allow instant logins).
+Allow the user to legin with a username and a password.
=cut
-sub create_account : Private {
+sub login : Private {
my ( $self, $c ) = @_;
- my $email = $c->stash->{email};
- # get account from the database
- my $account = $c->model('DB::User')->find_or_new( { email => $email } );
+ my $email = $c->stash->{email} || '';
+ my $password = $c->req->param('password') || '';
- # Deal with existing accounts by treating it like a password reset link
- if ( $account->in_storage ) {
- $c->stash->{tried_to_create_account} = 1;
- $c->detach('email_reset');
- }
+ # logout just in case
+ $c->logout();
- # we have a new account
- my $password = mySociety::AuthToken::random_token();
- $account->password( sha1_hex($password) );
- $account->insert; # save to database
+ if ( $c->authenticate( { email => $email, password => $password } ) ) {
+ $c->res->redirect( $c->uri_for('/my') );
+ return;
+ }
- # log the user in, send them an email and redirect to the welcome page
- $c->authenticate( { email => $email, password => $password } );
- $c->send_email( 'auth_new_account_welcome', { to => $email } );
- $c->res->redirect( $c->uri_for('welcome') );
+ # could not authenticate - show an error
+ $c->stash->{login_error} = 1;
}
-=head2 welcome
+=head2 email_login
-Page that new users are redirected to after they have created an account.
+Email the user the details they need to log in. Don't check for an account - if
+there isn't one we can create it when they come back with a token (which
+contains the email addresss).
=cut
-sub welcome : Local {
+sub email_login : Private {
my ( $self, $c ) = @_;
+ my $email = $c->stash->{email};
- # FIXME - check that user is logged in!
- # pass thru
-}
+ my $token_obj = $c->model('DB::Token') #
+ ->create(
+ {
+ scope => 'email_login',
+ data => { email => $email }
+ }
+ );
-=head2 confirm
+ # log the user in, send them an email and redirect to the welcome page
+ $c->stash->{token} = $token_obj->token;
+ $c->send_email( 'login', { to => $email } );
+ $c->res->redirect( $c->uri_for('token') );
+}
-Confirm that a user can receive email - url is .../confirm/$token
+=head2 token
-We don't assume that the user is logged in, but if they are they are logged out
-and then logged in as the user they are confirming. The token is destroyed at
-the end of the request so it cannot be reused.
+Handle the 'email_login' tokens. Find the account for the email address
+(creating if needed), authenticate the user and delete the token.
=cut
-sub confirm : Local {
+sub token : Local {
my ( $self, $c, $url_token ) = @_;
- # Use the token to confirm the user and return them.
- my $user = $c->model('DB::User')->confirm_user_from_token($url_token);
+ # check for a token - if none found then return
+ return unless $url_token;
- # If we did not get a user back then the token was not valid
- return if !$user;
+ # retrieve the token or return
+ my $token_obj =
+ $c->model('DB::Token')
+ ->find( { scope => 'email_login', token => $url_token, } );
+
+ if ( !$token_obj ) {
+ $c->stash->{token_not_found} = 1;
+ return;
+ }
- # got a user back which is now confirmed - auth as them
+ # logout in case we are another user
$c->logout();
+
+ # get the email and scrap the token
+ my $email = $token_obj->data->{email};
+ $token_obj->delete;
+
+ # find or create the user related to the token and delete the token
+ my $user = $c->model('DB::User')->find_or_create( { email => $email } );
$c->authenticate( { email => $user->email }, 'no_password' );
- $c->stash->{user_now_confirmed} = 1;
- # TODO - should we redirect somewhere - perhaps to pending problems?
- return;
+ # send the user to their page
+ $c->res->redirect( $c->uri_for('/my') );
+}
+
+=head2 change_password
+
+Let the user change their password.
+
+=cut
+
+sub change_password : Local {
+ my ( $self, $c ) = @_;
+
+ # FIXME - should be logged in
+ # FIXME - CSRF check here
+ # FIXME - minimum criteria for passwords (length, contain number, etc)
+
+ # If not a post then no submission
+ return unless $c->req->method eq 'POST';
+
+ # get the passwords
+ my $new = $c->req->param('new_password') // '';
+ my $confirm = $c->req->param('confirm') // '';
+
+ # check for errors
+ my $password_error =
+ !$new && !$confirm ? 'missing'
+ : $new ne $confirm ? 'mismatch'
+ : '';
+
+ if ($password_error) {
+ $c->stash->{password_error} = $password_error;
+ $c->stash->{new_password} = $new;
+ $c->stash->{confirm} = $confirm;
+ return;
+ }
+
+ # we should have a usable password - save it to the user
+ $c->user->obj->update( { password => sha1_hex($new) } );
+ $c->stash->{password_changed} = 1;
+
}
=head2 logout