diff options
author | Edmund von der Burg <evdb@mysociety.org> | 2011-03-04 11:08:07 +0000 |
---|---|---|
committer | Edmund von der Burg <evdb@mysociety.org> | 2011-03-04 11:08:07 +0000 |
commit | 770ffd1d8fb1f023e78df876a29dc36022246692 (patch) | |
tree | 3ab4571d487c4e50c19fcece42983764fbab3b5c /perllib/FixMyStreet/App/Controller/Auth.pm | |
parent | e18bf78e0513d4f1ebf0413d60691525cdcc2f5d (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.pm | 142 |
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 |